From: Apple Date: Tue, 24 Mar 2020 21:08:16 +0000 (+0000) Subject: Security-59306.41.2.tar.gz X-Git-Tag: macos-10151^0 X-Git-Url: https://git.saurik.com/apple/security.git/commitdiff_plain/7fb2cbd2e68c73bf213d9907905431dbdb74c908 Security-59306.41.2.tar.gz --- diff --git a/CircleJoinRequested/CircleJoinRequested.m b/CircleJoinRequested/CircleJoinRequested.m index 2009f377..38e7c8ea 100644 --- a/CircleJoinRequested/CircleJoinRequested.m +++ b/CircleJoinRequested/CircleJoinRequested.m @@ -62,6 +62,7 @@ #include "utilities/SecAKSWrappers.h" #include "utilities/SecCFWrappers.h" #include +#import #import "CoreCDP/CDPFollowUpController.h" #import "CoreCDP/CDPFollowUpContext.h" @@ -561,13 +562,21 @@ static NSString *getLocalizedApplicationReminder() { return (__bridge_transfer NSString *) applicationReminder; } +static bool isSOSInternalDevice(void) { + static dispatch_once_t onceToken; + static BOOL internal = NO; + dispatch_once(&onceToken, ^{ + internal = os_variant_has_internal_diagnostics("com.apple.security"); + }); + return internal; +} static void postApplicationReminderAlert(NSDate *nowish, PersistentState *state, unsigned int alertInterval) { NSString *body = getLocalizedApplicationReminder(); bool has_iCSC = iCloudResetAvailable(); - if (CPIsInternalDevice() && + if (isSOSInternalDevice() && state.defaultPendingApplicationReminderAlertInterval != state.pendingApplicationReminderAlertInterval) { #ifdef DEBUG body = [body stringByAppendingFormat: @"〖debug interval %u; wait time %@〗", @@ -686,7 +695,7 @@ static void postKickedOutAlert(enum DepartureReason reason) break; } - if (CPIsInternalDevice()) { + if (isSOSInternalDevice()) { static const char *departureReasonStrings[] = { "kSOSDepartureReasonError", "kSOSNeverLeftCircle", @@ -758,6 +767,22 @@ static void postKickedOutAlert(enum DepartureReason reason) debugState = @"pKOA Z"; } +static void askForCDPFollowup() { + doOnceInMain(^{ + NSError *localError = nil; + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; + CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; + [cdpd postFollowUpWithContext:context error:&localError ]; + if(localError){ + secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); + } + else{ + secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } + }); +} + static bool processEvents() { debugState = @"processEvents A"; @@ -805,49 +830,47 @@ static bool processEvents() } if(_isAccountICDP){ - if((circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedFollowupAndStillInError == false) { - if(circleStatus == kSOSCCError) { - secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); - } - + state.lastCircleStatus = circleStatus; + [state writeToStorage]; + if(_hasPostedFollowupAndStillInError == true) { + secnotice("cjr", "followup not resolved"); + _executeProcessEventsOnce = true; + return false; + } + + switch(circleStatus) { + case kSOSCCInCircle: + secnotice("cjr", "follow up should be resolved"); + _executeProcessEventsOnce = true; + _hasPostedFollowupAndStillInError = false; + break; + case kSOSCCError: + secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); + askForCDPFollowup(); + _executeProcessEventsOnce = true; + return false; + case kSOSCCCircleAbsent: + case kSOSCCNotInCircle: /* - You would think we could count on not being iCDP if the account was signed out. Evidently that's wrong. - So we'll go based on the artifact that when the account object is reset (like by signing out) the - departureReason will be set to kSOSDepartureReasonError. So we won't push to get back into a circle if that's - the current reason. I've checked code for other ways we could be out. If we boot and can't load the account - we'll end up with kSOSDepartureReasonError. Then too if we end up in kSOSDepartureReasonError and reboot we end up - in the same place. Leave it to cdpd to decide whether the user needs to sign in to an account. + You would think we could count on not being iCDP if the account was signed out. Evidently that's wrong. + So we'll go based on the artifact that when the account object is reset (like by signing out) the + departureReason will be set to kSOSDepartureReasonError. So we won't push to get back into a circle if that's + the current reason. I've checked code for other ways we could be out. If we boot and can't load the account + we'll end up with kSOSDepartureReasonError. Then too if we end up in kSOSDepartureReasonError and reboot we end up + in the same place. Leave it to cdpd to decide whether the user needs to sign in to an account. */ if(departureReason != kSOSDepartureReasonError) { secnotice("cjr", "iCDP: We need to get back into the circle"); - doOnceInMain(^{ - NSError *localError = nil; - CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; - CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; - [cdpd postFollowUpWithContext:context error:&localError ]; - if(localError){ - secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); - } - else{ - secnotice("cjr", "CoreCDP handling follow up"); - _hasPostedFollowupAndStillInError = true; - } - }); + askForCDPFollowup(); } else { secnotice("cjr", "iCDP: We appear to not be associated with an iCloud account"); } - state.lastCircleStatus = circleStatus; _executeProcessEventsOnce = true; return false; - } - else if(circleStatus == kSOSCCInCircle){ - secnotice("cjr", "follow up should be resolved"); - _executeProcessEventsOnce = true; - _hasPostedFollowupAndStillInError = false; - } - else{ - secnotice("cjr", "followup not resolved"); - _executeProcessEventsOnce = true; + case kSOSCCRequestPending: + break; + default: + secnotice("cjr", "Unknown circle status %d", circleStatus); return false; } } else if(circleStatus == kSOSCCError && state.lastCircleStatus != kSOSCCError && (departureReason == kSOSNeverLeftCircle)) { diff --git a/KeychainCircle/KCAccountKCCircleDelegate.h b/KeychainCircle/KCAccountKCCircleDelegate.h index 62e26e2e..3e1d3497 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.h +++ b/KeychainCircle/KCAccountKCCircleDelegate.h @@ -40,7 +40,7 @@ */ - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer error: (NSError**) error; --(NSData*) circleGetInitialSyncViews: (NSError**) error; +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error; + (instancetype) delegate; diff --git a/KeychainCircle/KCAccountKCCircleDelegate.m b/KeychainCircle/KCAccountKCCircleDelegate.m index 71e86c63..a0fa541d 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.m +++ b/KeychainCircle/KCAccountKCCircleDelegate.m @@ -69,9 +69,9 @@ return (__bridge_transfer NSData*) result; } --(NSData*) circleGetInitialSyncViews: (NSError**) error{ +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{ CFErrorRef failure = NULL; - CFDataRef result = SOSCCCopyInitialSyncData(&failure); + CFDataRef result = SOSCCCopyInitialSyncData(flags, &failure); if (failure != NULL && error != nil) { *error = (__bridge_transfer NSError*) failure; } diff --git a/KeychainCircle/KCJoiningAcceptSession.m b/KeychainCircle/KCJoiningAcceptSession.m index 743b60e3..01285024 100644 --- a/KeychainCircle/KCJoiningAcceptSession.m +++ b/KeychainCircle/KCJoiningAcceptSession.m @@ -42,8 +42,8 @@ typedef enum { @interface KCJoiningAcceptSession () @property (readonly) uint64_t dsid; -@property (readonly) NSObject* secretDelegate; -@property (readonly) NSObject* circleDelegate; +@property (weak) id secretDelegate; +@property (weak) id circleDelegate; @property (readonly) KCSRPServerContext* context; @property (readonly) KCAESGCMDuplexSession* session; @property (readonly) KCJoiningAcceptSessionState state; @@ -114,8 +114,8 @@ typedef enum { digestInfo: ccsha256_di() group: ccsrp_gp_rfc5054_3072() randomSource: rng]; - self->_secretDelegate = secretDelegate; - self->_circleDelegate = circleDelegate; + self.secretDelegate = secretDelegate; + self.circleDelegate = circleDelegate; self->_state = kExpectingA; self->_dsid = dsid; self->_piggy_uuid = nil; @@ -273,25 +273,27 @@ typedef enum { return nil; } + id secretDelegate = self.secretDelegate; + // We handle failure, don't capture the error. NSData* confirmation = [self.context copyConfirmationFor:message.firstData error:NULL]; if (!confirmation) { // Find out what kind of error we should send. NSData* errorData = nil; - KCRetryOrNot status = [self.secretDelegate verificationFailed: error]; + KCRetryOrNot status = [secretDelegate verificationFailed: error]; secerror("processResponse: handle error: %d", (int)status); switch (status) { case kKCRetryError: // We fill in an error if they didn't, but if they did this wont bother. - KCJoiningErrorCreate(kInternalError, error, @"Delegate returned error without filling in error: %@", self.secretDelegate); + KCJoiningErrorCreate(kInternalError, error, @"Delegate returned error without filling in error: %@", secretDelegate); return nil; case kKCRetryWithSameChallenge: errorData = [NSData data]; break; case kKCRetryWithNewChallenge: - if ([self.context resetWithPassword:[self.secretDelegate secret] error:error]) { + if ([self.context resetWithPassword:[secretDelegate secret] error:error]) { errorData = [self copyChallengeMessage: error]; } break; @@ -303,7 +305,7 @@ typedef enum { error:error] der]; } - NSData* encoded = [NSData dataWithEncodedString:[self.secretDelegate accountCode] error:error]; + NSData* encoded = [NSData dataWithEncodedString:[secretDelegate accountCode] error:error]; if (encoded == nil) return nil; @@ -323,6 +325,8 @@ typedef enum { NSData* decryptedPayload = [self.session decryptAndVerify:message error:error]; if (decryptedPayload == nil) return nil; + id circleDelegate = self.circleDelegate; + CFErrorRef cfError = NULL; SOSPeerInfoRef ref = SOSPeerInfoCreateFromData(NULL, &cfError, (__bridge CFDataRef) decryptedPayload); if (ref == NULL) { @@ -331,7 +335,7 @@ typedef enum { return nil; } - NSData* joinData = [self.circleDelegate circleJoinDataFor:ref error:error]; + NSData* joinData = [circleDelegate circleJoinDataFor:ref error:error]; if(ref) { CFRelease(ref); ref = NULL; @@ -339,13 +343,26 @@ typedef enum { if (joinData == nil) return nil; - if(self->_piggy_version == kPiggyV1){ + SOSInitialSyncFlags flags = 0; + switch (self.piggy_version) { + case kPiggyV0: + break; + case kPiggyV1: + secnotice("acceptor", "piggy version is 1"); + flags |= kSOSInitialSyncFlagTLKs | kSOSInitialSyncFlagiCloudIdentity; + break; + case kPiggyV2: + secnotice("acceptor", "piggy version is 2"); + flags |= kSOSInitialSyncFlagiCloudIdentity; + break; + } + + if (flags) { //grab iCloud Identities, TLKs - secnotice("acceptor", "piggy version is 1"); - NSError *localV1Error = nil; - NSData* initialSyncData = [self.circleDelegate circleGetInitialSyncViews:&localV1Error]; - if(localV1Error){ - secnotice("piggy", "PB v1 threw an error: %@", localV1Error); + NSError *localISVError = nil; + NSData* initialSyncData = [circleDelegate circleGetInitialSyncViews:flags error:&localISVError]; + if(initialSyncData == NULL){ + secnotice("piggy", "PB threw an error: %@", localISVError); } NSMutableData* growPacket = [[NSMutableData alloc] initWithData:joinData]; diff --git a/KeychainCircle/KCJoiningRequestSecretSession.m b/KeychainCircle/KCJoiningRequestSecretSession.m index f251465c..2cb52bcf 100644 --- a/KeychainCircle/KCJoiningRequestSecretSession.m +++ b/KeychainCircle/KCJoiningRequestSecretSession.m @@ -61,7 +61,7 @@ bool KCJoiningOctagonPiggybackingEnabled() { @interface KCJoiningRequestSecretSession () -@property (readonly) NSObject* secretDelegate; +@property (weak) id secretDelegate; @property (readonly) KCSRPClientContext* context; @property (readonly) uint64_t dsid; @property (readonly) KCJoiningRequestSecretSessionState state; @@ -245,9 +245,11 @@ bool KCJoiningOctagonPiggybackingEnabled() { - (NSData*) handleVerification: (KCJoiningMessage*) message error: (NSError**) error { secnotice("joining", "joining: KCJoiningRequestSecretSession handleVerification called"); + id secretDelegate = self.secretDelegate; + if ([message type] == kError) { bool newCode = [[message firstData] length] == 0; - NSString* nextSecret = [self.secretDelegate verificationFailed: newCode]; + NSString* nextSecret = [secretDelegate verificationFailed: newCode]; if (nextSecret) { if (newCode) { @@ -279,7 +281,7 @@ bool KCJoiningOctagonPiggybackingEnabled() { NSString* accountCode = [NSString decodeFromDER:payload error:error]; if (accountCode == nil) return nil; - if (![self.secretDelegate processAccountCode:accountCode error:error]) return nil; + if (![secretDelegate processAccountCode:accountCode error:error]) return nil; } self->_state = kRequestSecretDone; diff --git a/KeychainCircle/KCJoiningSession.h b/KeychainCircle/KCJoiningSession.h index f94064a0..dd0d61c4 100644 --- a/KeychainCircle/KCJoiningSession.h +++ b/KeychainCircle/KCJoiningSession.h @@ -138,7 +138,7 @@ NS_ASSUME_NONNULL_BEGIN @result Data blob contains tlks, icloud identities, and backupv0 */ --(NSData*) circleGetInitialSyncViews: (NSError**) error; +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error; @end typedef enum { diff --git a/KeychainCircle/PairingChannel.m b/KeychainCircle/PairingChannel.m index e2d2b677..b65d3f6b 100644 --- a/KeychainCircle/PairingChannel.m +++ b/KeychainCircle/PairingChannel.m @@ -273,16 +273,25 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE; return; } - if(OctagonIsEnabled() && self.sessionSupportsOctagon && !self.testFailOctagon) { + if(self.sessionSupportsOctagon && self.sessionSupportsSOS && !self.testFailOctagon) { __weak typeof(self) weakSelf = self; self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; }; complete(false, @{ @"d" : @YES, @"o" : @{@"v" : @"O"} }, NULL); - } else if (OctagonIsEnabled() && self.testFailOctagon) { + return; + } else if (self.sessionSupportsOctagon && self.testFailOctagon) { complete(true, nil, NULL); return; - } else { + } else if (self.sessionSupportsOctagon && !self.sessionSupportsSOS) { + __weak typeof(self) weakSelf = self; + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; + }; + complete(false, @{ @"o" : @{@"v" : @"O"} }, NULL); + return; + } + else { __weak typeof(self) weakSelf = self; self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; diff --git a/KeychainCircle/Tests/KCJoiningSessionTest.m b/KeychainCircle/Tests/KCJoiningSessionTest.m index a8919e9d..a3d71d0f 100644 --- a/KeychainCircle/Tests/KCJoiningSessionTest.m +++ b/KeychainCircle/Tests/KCJoiningSessionTest.m @@ -254,7 +254,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) { return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ]; } --(NSData*) circleGetInitialSyncViews: (NSError**) error{ +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{ return [NSData data]; } diff --git a/OSX/authd/authorization.plist b/OSX/authd/authorization.plist index 2b135078..2a1930aa 100644 --- a/OSX/authd/authorization.plist +++ b/OSX/authd/authorization.plist @@ -857,7 +857,9 @@ See remaining rules for examples. shared timeout - 300 + 900 + version + 2 system.install.software.iap diff --git a/OSX/config/security_framework_macos.xcconfig b/OSX/config/security_framework_macos.xcconfig index 6aa60fd8..b9708656 100644 --- a/OSX/config/security_framework_macos.xcconfig +++ b/OSX/config/security_framework_macos.xcconfig @@ -26,7 +26,7 @@ APPLY_RULES_IN_COPY_FILES = NO // Adding things here is against the spirit of TAPI. If something is in the framework, it should be in the framework headers. // Don't add things. -OTHER_TAPI_FLAGS_TRUST = -extra-private-header $(PROJECT_DIR)/OSX/trustd/macOS/SecTrustOSXEntryPoints.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecCertificateInternal.h +OTHER_TAPI_FLAGS_TRUST = -extra-private-header $(PROJECT_DIR)/trust/trustd/macOS/SecTrustOSXEntryPoints.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecCertificateInternal.h OTHER_TAPI_FLAGS_USR_LIB_HEADERS = -extra-private-header $(PROJECT_DIR)/OSX/utilities/debugging.h OTHER_TAPI_FLAGS_HACKS = -exclude-public-header $(BUILT_PRODUCTS_DIR)/Security.framework/Versions/A/Headers/AuthorizationPlugin.h -extra-public-header $(PROJECT_DIR)/OSX/macos_tapi_hacks.h -extra-public-header $(PROJECT_DIR)/OSX/sec/Security/SecItemShim.h -D SECURITY_PROJECT_TAPI_HACKS=1 diff --git a/OSX/libsecurity_keychain/lib/Item.cpp b/OSX/libsecurity_keychain/lib/Item.cpp index 474aba73..4d4dc772 100644 --- a/OSX/libsecurity_keychain/lib/Item.cpp +++ b/OSX/libsecurity_keychain/lib/Item.cpp @@ -1526,7 +1526,7 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite theList->count = 0; theList->attr = NULL; } else { - SecKeychainAttribute *attr=reinterpret_cast(malloc(sizeof(SecKeychainAttribute)*attrCount)); + SecKeychainAttribute *attr=reinterpret_cast(calloc(attrCount, sizeof(SecKeychainAttribute))); theList->count=attrCount; theList->attr=attr; diff --git a/OSX/libsecurity_keychain/lib/SecItem.cpp b/OSX/libsecurity_keychain/lib/SecItem.cpp index 40122c76..b1b571c2 100644 --- a/OSX/libsecurity_keychain/lib/SecItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecItem.cpp @@ -539,6 +539,12 @@ _ConvertNewFormatToOldFormat( SecKeychainAttributeList* &attrList ) { + // make storage to extract the dictionary items + CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); + if (itemsInDictionary > 10000) { + return errSecParam; + } + // get the keychain attributes array from the data item // here's the problem. On the one hand, we have a dictionary that is purported to contain // attributes for our type. On the other hand, the dictionary may contain items we don't support, @@ -547,8 +553,6 @@ _ConvertNewFormatToOldFormat( // setup the return attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList)); - // make storage to extract the dictionary items - CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); std::vector keys(itemsInDictionary); std::vector values(itemsInDictionary); @@ -592,7 +596,7 @@ _ConvertNewFormatToOldFormat( if(count == 0) { attrList->attr = NULL; } else { - attrList->attr = (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count); + attrList->attr = (SecKeychainAttribute*) calloc(count, sizeof(SecKeychainAttribute)); // fill out the array int resultPointer = 0; @@ -2362,7 +2366,7 @@ _ReplaceKeychainItem( // make attribute list for new item (the data is still owned by attrList) newAttrList.count = attrList->count; - newAttrList.attr = (SecKeychainAttribute *) malloc(sizeof(SecKeychainAttribute) * attrList->count); + newAttrList.attr = (SecKeychainAttribute *) calloc(attrList->count, sizeof(SecKeychainAttribute)); int i, newCount; for (i=0, newCount=0; i < attrList->count; i++) { if (attrList->attr[i].length > 0) { diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index 1495ca1d..7ef6027b 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -863,9 +863,9 @@ namespace Security { } } } else { - cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL)); if (cdsaKey) { - SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.retain()); + SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); } } } diff --git a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp index 0ce7406d..3d64c65d 100644 --- a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp +++ b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp @@ -26,7 +26,7 @@ * Framework. */ -#include "OSX/trustd/macOS/SecTrustOSXEntryPoints.h" +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" #include #include diff --git a/OSX/libsecurity_keychain/lib/TokenLogin.cpp b/OSX/libsecurity_keychain/lib/TokenLogin.cpp index 77b27a02..347d007b 100644 --- a/OSX/libsecurity_keychain/lib/TokenLogin.cpp +++ b/OSX/libsecurity_keychain/lib/TokenLogin.cpp @@ -119,7 +119,7 @@ static CFDataRef getPubKeyHashWrap(CFDictionaryRef context) return pubKeyHashWrap; } -static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey, CFTypeRef *laCtx) +static OSStatus privKeyForPubKeyHashWrap(CFDictionaryRef context, SecKeyRef *privKey, CFTypeRef *laCtx) { if (!context) { os_log_error(TL_LOG, "private key for pubkeyhash wrong params"); @@ -133,14 +133,14 @@ static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey if (pin) { CFRef LAContext = LACreateNewContextWithACMContext(NULL, error.take()); if (!LAContext) { - os_log_error(TL_LOG, "Failed to LA Context: %@", error.get()); + os_log_error(TL_LOG, "Failed to LA Context: %{public}@", error.get()); return errSecParam; } if (laCtx) *laCtx = (CFTypeRef)CFRetain(LAContext); CFRef externalizedContext = LACopyACMContext(LAContext, error.take()); if (!externalizedContext) { - os_log_error(TL_LOG, "Failed to get externalized context: %@", error.get()); + os_log_error(TL_LOG, "Failed to get externalized context: %{public}@", error.get()); return errSecParam; } CFDictionarySetValue(tokenAttributes, kSecUseCredentialReference, externalizedContext.get()); @@ -149,13 +149,13 @@ static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey CFRef token = TKTokenCreate(tokenAttributes, error.take()); if (!token) { - os_log_error(TL_LOG, "Failed to create token: %@", error.get()); + os_log_error(TL_LOG, "Failed to create token: %{public}@", error.get()); return errSecParam; } CFRef identities = TKTokenCopyIdentities(token, TKTokenKeyUsageAny, error.take()); if (!identities || !CFArrayGetCount(identities)) { - os_log_error(TL_LOG, "No identities found for token: %@", error.get()); + os_log_error(TL_LOG, "No identities found for token: %{public}@", error.get()); return errSecParam; } @@ -218,12 +218,12 @@ OSStatus TokenLoginGetContext(const void *base64TokenLoginData, UInt32 base64Tok NULL, error.take()); if (!*context || CFGetTypeID(*context) != CFDictionaryGetTypeID()) { - os_log_error(TL_LOG, "Invalid token login data property list, %@", error.get()); + os_log_error(TL_LOG, "Invalid token login data property list, %{public}@", error.get()); return errSecParam; } if (!getPin(*context) || !getTokenId(*context) || !getPubKeyHash(*context) || !getPubKeyHashWrap(*context)) { - os_log_error(TL_LOG, "Invalid token login data context, %@", error.get()); + os_log_error(TL_LOG, "Invalid token login data context, %{public}@", error.get()); return errSecParam; } @@ -236,8 +236,8 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) os_log_error(TL_LOG, "Get unlock key - wrong params"); return errSecParam; } - - CFRef loginData; + + CFRef loginData; OSStatus result = TokenLoginGetLoginData(context, loginData.take()); if (result != errSecSuccess) { os_log_error(TL_LOG, "Failed to get login data: %d", (int)result); @@ -254,12 +254,23 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) os_log_error(TL_LOG, "Algorithm not found in unlock key data"); return errSecParam; } + CFDataRef pubKeyHashWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); + if (pubKeyHashWrapFromPlist == NULL) { + os_log_error(TL_LOG, "Failed to get wrapkey for unlock key data"); + return errSecInternal; + } + CFRef ctx = makeCFDictionary(3, + kSecAttrTokenID, getTokenId(context), + kSecAttrService, getPin(context), + kSecAttrAccount, pubKeyHashWrapFromPlist + ); + CFRef privKey; CFRef LAContext; - result = privKeyForPubKeyHash(context, privKey.take(), LAContext.take()); + result = privKeyForPubKeyHashWrap(ctx, privKey.take(), LAContext.take()); if (result != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int)result); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist, (int)result); return result; } @@ -274,14 +285,14 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) wrappedUnlockKey, error.take()); if (!*unlockKey) { - os_log_error(TL_LOG, "Failed to unwrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to unwrap unlock key: %{public}@", error.get()); return errSecDecode; } // we need to re-wrap already unwrapped data to avoid capturing and reusing communication with the smartcard CFRef reWrappedUnlockKey = SecKeyCreateEncryptedData(pubKey, algorithm, *unlockKey, error.take()); if (!reWrappedUnlockKey) { - os_log_error(TL_LOG, "Failed to rewrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to rewrap unlock key: %{public}@", error.get()); TokenLoginDeleteUnlockData(getPubKeyHash(context)); return errSecParam; } @@ -319,7 +330,7 @@ OSStatus TokenLoginGetLoginData(CFDictionaryRef context, CFDictionaryRef *loginD NULL, error.take()); if (!*loginData || CFGetTypeID(*loginData) != CFDictionaryGetTypeID()) { - os_log_error(TL_LOG, "Failed to deserialize unlock key data: %@", error.get()); + os_log_error(TL_LOG, "Failed to deserialize unlock key data: %{public}@", error.get()); return errSecParam; } @@ -366,9 +377,9 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF kSecAttrAccount, pubKeyHashWrap ); CFRef privKey; - OSStatus result = privKeyForPubKeyHash(ctx, privKey.take(), NULL); + OSStatus result = privKeyForPubKeyHashWrap(ctx, privKey.take(), NULL); if (result != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int) result); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap, (int)result); return result; } @@ -407,7 +418,7 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF CFRef error; CFRef wrappedUnlockKey = SecKeyCreateEncryptedData(pubKey, algorithm, unlockKey, error.take()); if (!wrappedUnlockKey) { - os_log_error(TL_LOG, "Failed to wrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to wrap unlock key: %{public}@", error.get()); return errSecParam; } @@ -422,7 +433,7 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF OSStatus TokenLoginStoreUnlockData(CFDictionaryRef context, CFDictionaryRef loginData) { - os_log(TL_LOG, "Storing unlock data"); + os_log_debug(TL_LOG, "Storing unlock data"); CFRef error; CFRef data = CFPropertyListCreateData(kCFAllocatorDefault, @@ -431,24 +442,24 @@ OSStatus TokenLoginStoreUnlockData(CFDictionaryRef context, CFDictionaryRef logi 0, error.take()); if (!data) { - os_log_error(TL_LOG, "Failed to create unlock data: %@", error.get()); + os_log_error(TL_LOG, "Failed to create unlock data: %{public}@", error.get()); return errSecInternal; } CFRef pubKeyHashHex = cfDataToHex(getPubKeyHash(context)); - os_log(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); + os_log_debug(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); CFPreferencesSetValue(pubKeyHashHex, data, kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - os_log(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); + os_log_debug(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); CFPreferencesSynchronize(kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRef storedData = (CFDataRef)CFPreferencesCopyValue(pubKeyHashHex, kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - os_log(TL_LOG, "Stored data %@", storedData.get()); + os_log_debug(TL_LOG, "Stored data %@", storedData.get()); if (!storedData || !CFEqual(storedData, data)) { os_log_error(TL_LOG, "Failed to write token login plist"); return errSecIO; } - os_log(TL_LOG, "Original data %@. Everything is OK", data.get()); + os_log_debug(TL_LOG, "Original data %@. Everything is OK", data.get()); return errSecSuccess; } @@ -481,9 +492,9 @@ OSStatus TokenLoginGetScBlob(CFDataRef pubKeyHashWrap, CFStringRef tokenId, CFSt ); CFRef privKey; - OSStatus retval = privKeyForPubKeyHash(ctx, privKey.take(), NULL); + OSStatus retval = privKeyForPubKeyHashWrap(ctx, privKey.take(), NULL); if (retval != errSecSuccess) { - os_log_error(TL_LOG, "TokenLoginGetScBlob failed to get private key for public key hash: %d", (int) retval); + os_log_error(TL_LOG, "TokenLoginGetScBlob failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap, (int)retval); return retval; } @@ -556,25 +567,24 @@ OSStatus TokenLoginUnlockKeybag(CFDictionaryRef context, CFDictionaryRef loginDa return errSecInternal; } - CFDataRef pubKeyWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); - if (pubKeyWrapFromPlist == NULL) { + CFDataRef pubKeyHashWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); + if (pubKeyHashWrapFromPlist == NULL) { os_log_error(TL_LOG, "Failed to get wrapkey"); return errSecInternal; } - CFRef ctx = makeCFDictionary(4, + CFRef ctx = makeCFDictionary(3, kSecAttrTokenID, getTokenId(context), kSecAttrService, getPin(context), - kSecAttrPublicKeyHash, getPubKeyHash(context), - kSecAttrAccount, pubKeyWrapFromPlist + kSecAttrAccount, pubKeyHashWrapFromPlist ); CFRef error; CFRef privKey; CFRef LAContext; - OSStatus retval = privKeyForPubKeyHash(ctx, privKey.take(), LAContext.take()); + OSStatus retval = privKeyForPubKeyHashWrap(ctx, privKey.take(), LAContext.take()); if (retval != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int) retval); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist, (int)retval); return retval; } diff --git a/OSX/libsecurity_smime/lib/cmssiginfo.c b/OSX/libsecurity_smime/lib/cmssiginfo.c index 470b6098..3a83746d 100644 --- a/OSX/libsecurity_smime/lib/cmssiginfo.c +++ b/OSX/libsecurity_smime/lib/cmssiginfo.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "tsaSupport.h" #include "tsaSupportPriv.h" @@ -93,104 +94,60 @@ static OSStatus DER_UTCTimeToCFDate(const CSSM_DATA_PTR utcTime, CFAbsoluteTime *date) { - CFGregorianDate gdate; - char *string = (char *)utcTime->Data; - long year, month, mday, hour, minute, second, hourOff, minOff; - CFTimeZoneRef timeZone; - - /* Verify time is formatted properly and capture information */ - second = 0; - hourOff = 0; - minOff = 0; - CAPTURE(year,string+0,loser); - if (year < 50) { - /* ASSUME that year # is in the 2000's, not the 1900's */ - year += 100; - } - CAPTURE(month,string+2,loser); - if ((month == 0) || (month > 12)) goto loser; - CAPTURE(mday,string+4,loser); - if ((mday == 0) || (mday > 31)) goto loser; - CAPTURE(hour,string+6,loser); - if (hour > 23) goto loser; - CAPTURE(minute,string+8,loser); - if (minute > 59) goto loser; - if (ISDIGIT(string[10])) { - CAPTURE(second,string+10,loser); - if (second > 59) goto loser; - string += 2; - } - if (string[10] == '+') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - } else if (string[10] == '-') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - hourOff = -hourOff; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - minOff = -minOff; - } else if (string[10] != 'Z') { - goto loser; + CFErrorRef error = NULL; + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + CFAbsoluteTime result = SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME, utcTime->Data, utcTime->Length, &error); + if (error) { + CFReleaseNull(error); + return SECFailure; } - gdate.year = (SInt32)(year + 1900); - gdate.month = month; - gdate.day = mday; - gdate.hour = hour; - gdate.minute = minute; - gdate.second = second; - - if (hourOff == 0 && minOff == 0) - timeZone = NULL; /* GMT */ - else - { - timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, (hourOff * 60 + minOff) * 60); + if (date) { + *date = result; } - - *date = CFGregorianDateGetAbsoluteTime(gdate, timeZone); - if (timeZone) - CFRelease(timeZone); - return SECSuccess; - -loser: - return SECFailure; } static OSStatus DER_CFDateToUTCTime(CFAbsoluteTime date, CSSM_DATA_PTR utcTime) { - CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(date, NULL /* GMT */); unsigned char *d; - SInt8 second; utcTime->Length = 13; utcTime->Data = d = PORT_Alloc(13); - if (!utcTime->Data) - return SECFailure; + if (!utcTime->Data) { + return SECFailure; + } - /* UTC time does not handle the years before 1950 */ - if (gdate.year < 1950) - return SECFailure; + __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; + __block bool result; + SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { + result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second); + }); + if (!result) { + return SECFailure; + } + + /* UTC time does not handle the years before 1950 or after 2049 */ + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + if (year < 1950 || year > 2049) { + return SECFailure; + } /* remove the century since it's added to the year by the CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */ - gdate.year %= 100; - second = gdate.second + 0.5; - - d[0] = HIDIGIT(gdate.year); - d[1] = LODIGIT(gdate.year); - d[2] = HIDIGIT(gdate.month); - d[3] = LODIGIT(gdate.month); - d[4] = HIDIGIT(gdate.day); - d[5] = LODIGIT(gdate.day); - d[6] = HIDIGIT(gdate.hour); - d[7] = LODIGIT(gdate.hour); - d[8] = HIDIGIT(gdate.minute); - d[9] = LODIGIT(gdate.minute); + year %= 100; + + d[0] = HIDIGIT(year); + d[1] = LODIGIT(year); + d[2] = HIDIGIT(month); + d[3] = LODIGIT(month); + d[4] = HIDIGIT(day); + d[5] = LODIGIT(day); + d[6] = HIDIGIT(hour); + d[7] = LODIGIT(hour); + d[8] = HIDIGIT(minute); + d[9] = LODIGIT(minute); d[10] = HIDIGIT(second); d[11] = LODIGIT(second); d[12] = 'Z'; diff --git a/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m b/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m index 795b0f29..adaa8a98 100644 --- a/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m +++ b/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m @@ -224,7 +224,7 @@ static OSStatus securetransport(ssl_test_handle * ssl) SecTrustResultType trust_result = 0; /* this won't verify without setting up a trusted anchor */ require_noerr(SecTrustEvaluate(trust, &trust_result), out); - require((trust_result == kSecTrustResultUnspecified), out); + require((trust_result == kSecTrustResultUnspecified || trust_result == kSecTrustResultProceed), out); } } while (ortn == errSSLWouldBlock diff --git a/OSX/regressions/test/testenv.m b/OSX/regressions/test/testenv.m index ac5096d2..8692ff3c 100644 --- a/OSX/regressions/test/testenv.m +++ b/OSX/regressions/test/testenv.m @@ -62,7 +62,7 @@ int test_check_leaks = 0; char **test_skip_leaks_test = NULL; #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" static int current_dir = -1; static char scratch_dir[50]; diff --git a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c index 13a902fa..c6bfdcfa 100644 --- a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c +++ b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c @@ -391,7 +391,7 @@ static void tests(void) SecTrustResultType trustResult; CFArrayRef properties = NULL; properties = SecTrustCopyProperties(trust); -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE // Note: OS X will trigger the evaluation in order to return the properties. is(properties, NULL, "no properties returned before eval"); #endif @@ -407,8 +407,15 @@ static void tests(void) print_cert(wwdr_intermediate, false); } #endif - CFReleaseNull(properties); + // verify wrapper functions are available + properties = SecCertificateCopyProperties(leaf); + isnt(properties, NULL, "leaf properties returned"); + CFReleaseNull(properties); + properties = SecCertificateCopyLocalizedProperties(leaf, true); + isnt(properties, NULL, "localized leaf properties returned"); + CFReleaseNull(properties); + CFReleaseNull(trust); CFReleaseNull(wwdr_intermediate); CFReleaseNull(leaf); @@ -420,10 +427,10 @@ static void tests(void) int si_26_sectrust_copyproperties(int argc, char *const *argv) { #if TARGET_OS_IPHONE - plan_tests(8); + plan_tests(10); #else // - plan_tests(7); + plan_tests(9); #endif diff --git a/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c b/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c index e28fcf59..a5e11478 100644 --- a/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c +++ b/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c @@ -34,7 +34,7 @@ #include #include "Security_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" /* TODO: This test needs to be updated. It was originally created to test upgrades from DB prior to the introduction of versionning, circa 2008. We don't support upgrading from that old of keychain, but this test should be upgraded to test upgrades from v5 to v6 keychain, or more current diff --git a/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c b/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c index 05fc5bb3..1be9af7f 100644 --- a/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c +++ b/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c b/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c index ecff54fc..0760e00d 100644 --- a/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c +++ b/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c index 258e5895..6e7b25d2 100644 --- a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c +++ b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c @@ -24,7 +24,7 @@ #include -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-60-cms.c b/OSX/sec/Security/Regressions/secitem/si-60-cms.c index 7a90e5fa..6a294a7a 100644 --- a/OSX/sec/Security/Regressions/secitem/si-60-cms.c +++ b/OSX/sec/Security/Regressions/secitem/si-60-cms.c @@ -44,8 +44,6 @@ #include "shared_regressions.h" -#define VERBOSE_ERRORS 1 - /* Bag Attributes friendlyName: uranusLeaf @@ -1746,18 +1744,7 @@ static void tests(void) ok_status(SecCMSSignDataAndAttributes(identity, test_data, false, message_data, simple_attr), "encode message"); ok_status(SecCMSVerifyCopyDataAndAttributes(message_data, NULL, policy, &trust, &message, &attrs), "decode message again"); CFReleaseNull(trust); -#if VERBOSE_ERRORS - size_t message_len = CFDataGetLength(message_data); - const uint8_t* message_ptr = CFDataGetBytePtr(message_data); - char *message_hex = (char *)calloc(1, 2 * message_len + 1); - for (size_t ix = 0; ix < message_len; ix++) { - snprintf(&message_hex[2*ix], 3, "%02X", message_ptr[ix]); - } - is(CFDictionaryGetCount(attrs), 6, "5 signed attributes + cooked date. \n\tattrs=%@\tmessage_data=%s", attrs, message_hex); - free(message_hex); -#else is(CFDictionaryGetCount(attrs), 6, "5 signed attributes + cooked date"); -#endif isnt(CFDictionaryGetValue(attrs, kSecCMSSignDate), NULL, "failed to get cooked data from attributes"); isnt(CFDictionaryGetValue(attrs, kSecCMSAllCerts), NULL, "failed to get cert(s) from attributes"); isnt(CFDictionaryGetValue(attrs, oid_data), NULL, "failed to get user-defined attribute"); @@ -1952,16 +1939,120 @@ out: CFReleaseNull(recipients); } +const uint8_t _sixty_seconds_message[] = { + 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, + 0x80, 0x02, 0x01, 0x01, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, + 0x24, 0x80, 0x04, 0x08, 0x68, 0x6f, 0x69, 0x20, 0x6a, 0x6f, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x82, 0x02, 0xe4, 0x30, 0x82, 0x02, 0xe0, 0x30, 0x82, 0x01, 0xc8, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, + 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x40, 0x70, 0x6c, + 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x35, 0x31, 0x32, 0x31, + 0x37, 0x30, 0x30, 0x30, 0x34, 0x32, 0x35, 0x5a, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x32, 0x31, 0x37, + 0x30, 0x30, 0x30, 0x34, 0x32, 0x35, 0x5a, 0x30, 0x37, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0a, 0x75, 0x72, 0x61, 0x6e, 0x75, 0x73, 0x4c, 0x65, 0x61, 0x66, 0x31, 0x20, + 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x11, 0x75, + 0x72, 0x61, 0x6e, 0x75, 0x73, 0x40, 0x75, 0x72, 0x61, 0x6e, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xa6, 0x82, 0x8e, 0xc6, 0x7e, 0xc9, 0x8c, 0x99, 0x6f, 0xb0, 0x62, 0x32, 0x35, 0xe7, 0xdb, + 0xff, 0x34, 0x84, 0xdc, 0x72, 0xa8, 0xef, 0x22, 0x6f, 0x93, 0x63, 0x64, 0x80, 0x80, 0x5d, 0x50, + 0x7e, 0xb4, 0x2e, 0x1b, 0x93, 0x93, 0x49, 0xca, 0xae, 0xcd, 0x34, 0x44, 0x4b, 0xd7, 0xfa, 0x9f, + 0x3c, 0xfc, 0x9e, 0x65, 0xa9, 0xfb, 0x5e, 0x5d, 0x18, 0xa3, 0xf8, 0xb0, 0x08, 0xac, 0x8f, 0xfd, + 0x03, 0xcb, 0xbd, 0x7f, 0xa0, 0x2a, 0xa6, 0xea, 0xca, 0xa3, 0x24, 0xef, 0x7c, 0xc3, 0xeb, 0x95, + 0xcb, 0x90, 0x3f, 0x5e, 0xde, 0x78, 0xf2, 0x3d, 0x32, 0x72, 0xdb, 0x33, 0x6e, 0x9b, 0x52, 0x9f, + 0x0c, 0x60, 0x4a, 0x24, 0xa1, 0xf6, 0x3b, 0x80, 0xbd, 0xa1, 0xdc, 0x40, 0x03, 0xe7, 0xa0, 0x59, + 0x1f, 0xdb, 0xb4, 0xed, 0x57, 0xdc, 0x74, 0x0d, 0x99, 0x5a, 0x12, 0x74, 0x64, 0xaa, 0xb6, 0xa5, + 0x96, 0x75, 0xf9, 0x42, 0x43, 0xe2, 0x52, 0xc2, 0x57, 0x23, 0x75, 0xd7, 0xa9, 0x4f, 0x07, 0x32, + 0x99, 0xbd, 0x3d, 0x44, 0xbd, 0x04, 0x62, 0xe5, 0xb7, 0x2c, 0x0c, 0x11, 0xc5, 0xb2, 0x2e, 0xc4, + 0x12, 0x1d, 0x7f, 0x42, 0x1e, 0x71, 0xaf, 0x39, 0x2b, 0x78, 0x47, 0x92, 0x23, 0x44, 0xef, 0xe3, + 0xc1, 0x47, 0x69, 0x5a, 0xf1, 0x48, 0xaa, 0x37, 0xa4, 0x94, 0x6b, 0x96, 0xe5, 0x4b, 0xfd, 0x05, + 0xc7, 0x9c, 0xcc, 0x38, 0xd1, 0x47, 0x85, 0x60, 0x7f, 0xef, 0xe9, 0x2e, 0x25, 0x08, 0xf8, 0x7d, + 0x98, 0xdd, 0x6c, 0xeb, 0x4a, 0x32, 0x33, 0x44, 0x0b, 0x61, 0xb3, 0xf9, 0xae, 0x26, 0x41, 0xb5, + 0x38, 0xdb, 0xcf, 0x13, 0x72, 0x23, 0x5b, 0x66, 0x20, 0x86, 0x4d, 0x24, 0xc2, 0xd4, 0x94, 0xde, + 0xe3, 0x24, 0xb7, 0xcd, 0x75, 0x9e, 0x1d, 0x9f, 0xbc, 0xd0, 0x60, 0x34, 0x7d, 0xf8, 0xcb, 0x41, + 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x17, 0xa5, 0x22, 0xed, 0xb8, 0x3e, + 0x1f, 0x11, 0x99, 0xc5, 0xba, 0x28, 0x3e, 0x7e, 0xa6, 0xeb, 0x02, 0x81, 0x06, 0xa1, 0xc6, 0x80, + 0xb9, 0x7e, 0x5c, 0x5a, 0x63, 0xe0, 0x8d, 0xeb, 0xd0, 0xec, 0x9c, 0x3a, 0x94, 0x64, 0x7c, 0x13, + 0x54, 0x0d, 0xd6, 0xe3, 0x27, 0x88, 0xa6, 0xd2, 0x4b, 0x36, 0xdd, 0x2e, 0xfa, 0x94, 0xe5, 0x03, + 0x27, 0xc9, 0xa6, 0x31, 0x02, 0xea, 0x40, 0x77, 0x2e, 0x93, 0xc4, 0x4d, 0xe2, 0x70, 0xe2, 0x67, + 0x1c, 0xa8, 0x0d, 0xcd, 0x1a, 0x72, 0x86, 0x2c, 0xea, 0xdc, 0x7f, 0x8c, 0x49, 0x2c, 0xe7, 0x99, + 0x13, 0xda, 0x3f, 0x58, 0x9e, 0xf5, 0x4d, 0x3c, 0x8c, 0x1c, 0xed, 0x85, 0xa7, 0xe2, 0xae, 0xda, + 0x5f, 0xbe, 0x36, 0x1c, 0x9f, 0x5a, 0xa0, 0xdc, 0x2a, 0xc0, 0xee, 0x71, 0x07, 0x26, 0x8b, 0xe8, + 0x8a, 0xf8, 0x2d, 0x36, 0x78, 0xc9, 0x79, 0xfa, 0xbe, 0x98, 0x59, 0x95, 0x12, 0x24, 0xf1, 0xda, + 0x20, 0xc7, 0x78, 0xf9, 0x7c, 0x6a, 0x24, 0x43, 0x82, 0xa8, 0x0f, 0xb1, 0x7d, 0x94, 0xaa, 0x30, + 0x35, 0xe5, 0x69, 0xdc, 0x0a, 0x0e, 0xaf, 0x10, 0x5e, 0x1a, 0x81, 0x50, 0x5c, 0x7e, 0x24, 0xb3, + 0x07, 0x65, 0x4b, 0xc1, 0x7e, 0xc6, 0x38, 0xdb, 0xd3, 0x6a, 0xf0, 0xd8, 0x85, 0x61, 0x9a, 0x9f, + 0xfe, 0x02, 0x46, 0x29, 0xb2, 0x9a, 0xe2, 0x04, 0xe7, 0x72, 0xcc, 0x87, 0x46, 0xba, 0x7d, 0xa8, + 0xf9, 0xd0, 0x0f, 0x29, 0xfc, 0xfd, 0xd1, 0xd0, 0x7f, 0x36, 0xc1, 0xd8, 0x7d, 0x88, 0x03, 0x62, + 0xf5, 0x8c, 0x00, 0xb5, 0xc2, 0x81, 0x44, 0x67, 0x58, 0x11, 0xb4, 0x3a, 0xbb, 0xd1, 0x8c, 0x94, + 0x20, 0x60, 0xea, 0xa0, 0xac, 0xc1, 0xf1, 0x08, 0x54, 0xb8, 0xf6, 0x5e, 0xac, 0xf1, 0xec, 0x78, + 0x69, 0x9d, 0x7e, 0x4d, 0x06, 0x3b, 0x9b, 0x78, 0x78, 0x10, 0x31, 0x82, 0x01, 0xd4, 0x30, 0x82, + 0x01, 0xd0, 0x02, 0x01, 0x01, 0x30, 0x37, 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x07, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, + 0x6f, 0x40, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x01, 0x02, 0x30, 0x09, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0xa0, 0x74, 0x30, 0x15, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0x3f, 0x2a, 0x06, 0x31, 0x09, 0x04, 0x07, 0x68, 0x6f, 0x69, 0x20, 0x6a, + 0x6f, 0x68, 0x30, 0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03, 0x31, + 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x39, 0x30, + 0x39, 0x31, 0x31, 0x30, 0x32, 0x35, 0x34, 0x36, 0x30, 0x5a, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0x11, 0xe1, 0xcc, 0x76, 0x17, + 0x3a, 0x5f, 0xc7, 0x06, 0x23, 0x74, 0x4a, 0x68, 0x40, 0x7d, 0x0b, 0x30, 0x65, 0x14, 0x75, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x01, 0x00, 0x51, 0x0c, 0x91, 0x28, 0x6d, 0x4b, 0x19, 0xc9, 0xb1, 0x0f, 0x24, 0xda, 0xe4, 0xe2, + 0x56, 0x4f, 0xda, 0x87, 0x57, 0xc6, 0x11, 0xb0, 0x00, 0xcb, 0xa6, 0x38, 0x5c, 0x04, 0x8b, 0xd3, + 0xc7, 0xdb, 0x36, 0x85, 0x66, 0xa7, 0x5b, 0xcd, 0x8d, 0x32, 0x5c, 0x4e, 0xc4, 0x8a, 0x50, 0xb5, + 0xb5, 0x19, 0xf6, 0x7c, 0x31, 0xdd, 0xf9, 0x9c, 0xdd, 0xce, 0xf6, 0x3a, 0x51, 0xf9, 0xc7, 0x53, + 0xe1, 0x72, 0x89, 0xaa, 0x8c, 0xf7, 0xa9, 0xed, 0xa8, 0xc9, 0x93, 0x2a, 0xc0, 0x89, 0x24, 0x8e, + 0xd7, 0x7e, 0x66, 0x30, 0x1e, 0x46, 0x15, 0xbc, 0xe0, 0x0b, 0x37, 0xdc, 0xd5, 0xe0, 0x88, 0xed, + 0xbe, 0x0c, 0x7c, 0x6c, 0xd9, 0xd0, 0x58, 0x64, 0xff, 0x91, 0x5f, 0x18, 0xaa, 0x91, 0xa8, 0x3e, + 0x36, 0x4f, 0xe1, 0xda, 0x85, 0x35, 0x3e, 0xa3, 0x87, 0xbc, 0xa2, 0xec, 0x71, 0x71, 0xb5, 0xc9, + 0xc8, 0x71, 0x43, 0x01, 0x8f, 0x1d, 0x64, 0x5e, 0xfa, 0xdd, 0x58, 0xce, 0x6d, 0xb5, 0x46, 0x09, + 0xef, 0x6e, 0x87, 0xc4, 0xe7, 0x61, 0x6d, 0x7e, 0x8b, 0x2c, 0x57, 0x2f, 0x9f, 0x36, 0xc5, 0xd4, + 0x34, 0x4c, 0xbb, 0xa2, 0xca, 0xee, 0xbb, 0x48, 0xbe, 0x93, 0x06, 0x44, 0xbc, 0x54, 0xdc, 0x28, + 0xa6, 0x57, 0x80, 0x5c, 0xc0, 0x0c, 0xa5, 0x1c, 0x50, 0x9a, 0x44, 0x26, 0x56, 0xc1, 0xc4, 0xfd, + 0x1a, 0xc1, 0xcf, 0x42, 0xf0, 0x49, 0xf5, 0x49, 0xbe, 0x37, 0x98, 0xb5, 0xfe, 0x66, 0x13, 0x7d, + 0xec, 0xda, 0xd6, 0x59, 0xf7, 0x3b, 0x89, 0x20, 0x8f, 0x73, 0xf7, 0x9f, 0x2f, 0x6e, 0x09, 0x62, + 0x25, 0x6a, 0xec, 0x2b, 0x19, 0x5a, 0x37, 0x77, 0x30, 0x30, 0x74, 0x3b, 0x40, 0xb2, 0xed, 0x44, + 0xf2, 0xe7, 0x5e, 0x2c, 0xbb, 0x53, 0x5d, 0x36, 0x73, 0x1c, 0xbd, 0xd7, 0xf7, 0xdf, 0x82, 0x7d, + 0xce, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void test_decode_signing_time_leap_seconds(void) { + SecCertificateRef cert = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + CFDictionaryRef attrs = NULL; + CFDataRef message = NULL; + + CFDataRef message_data = CFDataCreate(NULL, _sixty_seconds_message, sizeof(_sixty_seconds_message)); + ok_status(SecCMSVerifyCopyDataAndAttributes(message_data, NULL, policy, &trust, &message, &attrs), "decode message again"); + CFReleaseNull(trust); + isnt(CFDictionaryGetValue(attrs, kSecCMSSignDate), NULL, "failed to get cooked data from attributes"); + + CFReleaseNull(cert); + CFReleaseNull(policy); + CFReleaseNull(attrs); + CFReleaseNull(message); + CFReleaseNull(message_data); +} + int si_60_cms(int argc, char *const *argv) { #if TARGET_OS_IPHONE - plan_tests(46); + plan_tests(48); #else - plan_tests(45); + plan_tests(47); #endif tests(); test_key_usage_enveloped_data(); + test_decode_signing_time_leap_seconds(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c index f3de052c..44b57a7d 100644 --- a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c +++ b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c @@ -37,7 +37,7 @@ #if TARGET_HAS_KEYSTORE #include -#include +#include "keychain/securityd/SecDbItem.h" #include #include #endif /* TARGET_HAS_KEYSTORE */ diff --git a/OSX/sec/Security/SecBackupKeybagEntry.h b/OSX/sec/Security/SecBackupKeybagEntry.h index c01bc2b5..eb4fd07a 100644 --- a/OSX/sec/Security/SecBackupKeybagEntry.h +++ b/OSX/sec/Security/SecBackupKeybagEntry.h @@ -23,7 +23,7 @@ #import "CKKSSQLDatabaseObject.h" #include -#include +#include "keychain/securityd/SecDbItem.h" #ifndef SecBackupKeybagEntry_h #define SecBackupKeybagEntry_h diff --git a/OSX/sec/Security/SecBackupKeybagEntry.m b/OSX/sec/Security/SecBackupKeybagEntry.m index 558c4e44..6ab0f79f 100644 --- a/OSX/sec/Security/SecBackupKeybagEntry.m +++ b/OSX/sec/Security/SecBackupKeybagEntry.m @@ -26,8 +26,8 @@ #import #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON diff --git a/OSX/sec/Security/SecCertificate.c b/OSX/sec/Security/SecCertificate.c index 0850a4b7..d9b3f39d 100644 --- a/OSX/sec/Security/SecCertificate.c +++ b/OSX/sec/Security/SecCertificate.c @@ -2260,7 +2260,7 @@ static inline int parseDecimalPair(const DERByte **p) { Note that this is needed to distinguish an error condition from a valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0). */ -static CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, +CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, const uint8_t *bytes, size_t length, CFErrorRef *error) { @@ -2367,7 +2367,8 @@ static CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0; - if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 + /* Some basic checks on the date, allowing leap seconds */ + if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 60 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year) || (month != 2 && day > mdays[month] - mdays[month - 1])) { /* Invalid date. */ @@ -4306,13 +4307,12 @@ CFArrayRef SecCertificateCopyLegacyProperties(SecCertificateRef certificate) { return properties; } -CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { +static CFArrayRef CopyProperties(SecCertificateRef certificate, Boolean localized) { if (!certificate->_properties) { CFAllocatorRef allocator = CFGetAllocator(certificate); CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); require_quiet(properties, out); - bool localized = true; /* First we put the Subject Name in the property list. */ CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, @@ -4383,6 +4383,22 @@ out: return certificate->_properties; } +CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { + /* + Wrapper function which defaults to localized string properties + for compatibility with prior releases. + */ + return CopyProperties(certificate, true); +} + +CFArrayRef SecCertificateCopyLocalizedProperties(SecCertificateRef certificate, Boolean localized) { + /* + Wrapper function which permits caller to specify whether + localized string properties are used. + */ + return CopyProperties(certificate, localized); +} + /* Unified serial number API */ CFDataRef SecCertificateCopySerialNumberData( SecCertificateRef certificate, diff --git a/OSX/sec/Security/SecExports.exp-in b/OSX/sec/Security/SecExports.exp-in index 706bf85f..89695818 100644 --- a/OSX/sec/Security/SecExports.exp-in +++ b/OSX/sec/Security/SecExports.exp-in @@ -80,6 +80,7 @@ _kSecPolicyNameAppleEscrowProxyService _kSecPolicyNameAppleFMiPService _kSecPolicyNameAppleGSService _kSecPolicyNameAppleHealthProviderService +_kSecPolicyNameAppleHomeAppClipUploadService _kSecPolicyNameAppleHomeKitService _kSecPolicyNameAppleiCloudSetupService _kSecPolicyNameAppleIDSService @@ -379,6 +380,7 @@ _SecCertificateCopyIssuerSummary _SecCertificateCopyKey _SecCertificateCopyKeychainItem _SecCertificateCopyLegacyProperties +_SecCertificateCopyLocalizedProperties _SecCertificateCopyNormalizedIssuerSequence _SecCertificateCopyNormalizedSubjectSequence _SecCertificateCopyNTPrincipalNames diff --git a/OSX/sec/Security/SecItemBackup.c b/OSX/sec/Security/SecItemBackup.c index cf58386f..614e40d8 100644 --- a/OSX/sec/Security/SecItemBackup.c +++ b/OSX/sec/Security/SecItemBackup.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include "keychain/SecureObjectSync/SOSBackupEvent.h" #include diff --git a/OSX/sec/Security/SecKey.m b/OSX/sec/Security/SecKey.m index 6fa9f866..218f1a9b 100644 --- a/OSX/sec/Security/SecKey.m +++ b/OSX/sec/Security/SecKey.m @@ -170,11 +170,21 @@ static CFMutableDictionaryRef auxilliaryCDSAKeyMap; static struct os_unfair_lock_s auxilliaryCDSAKeyMapLock = OS_UNFAIR_LOCK_INIT; static void SecKeyDestroyAuxilliaryCDSAKeyForKey(CFTypeRef cf) { + CFTypeRef keyToDestroy = NULL; os_unfair_lock_lock(&auxilliaryCDSAKeyMapLock); if (auxilliaryCDSAKeyMap != NULL) { - CFDictionaryRemoveValue(auxilliaryCDSAKeyMap, cf); + keyToDestroy = CFDictionaryGetValue(auxilliaryCDSAKeyMap, cf); + if (keyToDestroy != NULL) { + CFRetain(keyToDestroy); + CFDictionaryRemoveValue(auxilliaryCDSAKeyMap, cf); + } } os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); + + // Actual aux key destruction is performed outside unfair lock to avoid recursive lock. + if (keyToDestroy != NULL) { + CFRelease(keyToDestroy); + } } void SecKeySetAuxilliaryCDSAKeyForKey(SecKeyRef cf, SecKeyRef auxKey) { diff --git a/OSX/sec/Security/SecPolicy.c b/OSX/sec/Security/SecPolicy.c index fa34a2b4..2c37c6b4 100644 --- a/OSX/sec/Security/SecPolicy.c +++ b/OSX/sec/Security/SecPolicy.c @@ -131,6 +131,7 @@ SEC_CONST_DECL (kSecPolicyNameAppleHealthProviderService, "HealthProvider"); SEC_CONST_DECL (kSecPolicyNameAppleParsecService, "Parsec"); SEC_CONST_DECL (kSecPolicyNameAppleAMPService, "AMP"); SEC_CONST_DECL (kSecPolicyNameAppleSiriService, "Siri"); +SEC_CONST_DECL (kSecPolicyNameAppleHomeAppClipUploadService, "HomeAppClipUploadService"); #define kSecPolicySHA1Size 20 #define kSecPolicySHA256Size 32 diff --git a/OSX/sec/Security/SecTrust.c b/OSX/sec/Security/SecTrust.c index 85d45e7f..bf3cbaab 100644 --- a/OSX/sec/Security/SecTrust.c +++ b/OSX/sec/Security/SecTrust.c @@ -65,7 +65,7 @@ #include -#include +#include "trust/trustd/SecTrustServer.h" #pragma clang diagnostic ignored "-Wformat=2" diff --git a/OSX/sec/Security/SecuritydXPC.c b/OSX/sec/Security/SecuritydXPC.c index 65597c29..696d1f2c 100644 --- a/OSX/sec/Security/SecuritydXPC.c +++ b/OSX/sec/Security/SecuritydXPC.c @@ -41,6 +41,7 @@ const char *kSecXPCKeyPeerInfo = "peer-info"; const char *kSecXPCKeyUserLabel = "userlabel"; const char *kSecXPCKeyBackup = "backup"; const char *kSecXPCKeyKeybag = "keybag"; +const char *kSecXPCKeyFlags = "flags"; const char *kSecXPCKeyUserPassword = "password"; const char *kSecXPCKeyEMCSBackup = "emcsbackup"; const char *kSecXPCKeyDSID = "dsid"; diff --git a/OSX/sec/SharedWebCredential/swcagent.m b/OSX/sec/SharedWebCredential/swcagent.m index 146df58e..6c873d22 100644 --- a/OSX/sec/SharedWebCredential/swcagent.m +++ b/OSX/sec/SharedWebCredential/swcagent.m @@ -62,10 +62,10 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void); #include #include "swcagent_client.h" -#include -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "keychain/securityd/spi.h" #include #include diff --git a/OSX/sec/ipc/securityd_client.h b/OSX/sec/ipc/securityd_client.h index 1927babc..afbd42d6 100644 --- a/OSX/sec/ipc/securityd_client.h +++ b/OSX/sec/ipc/securityd_client.h @@ -25,7 +25,7 @@ #include -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include @@ -88,6 +88,7 @@ extern const char *kSecXPCKeyPeerInfoArray; extern const char *kSecXPCKeyUserLabel; extern const char *kSecXPCKeyBackup; extern const char *kSecXPCKeyKeybag; +extern const char *kSecXPCKeyFlags; extern const char *kSecXPCKeyUserPassword; extern const char *kSecXPCKeyEMCSBackup; extern const char *kSecXPCKeyDSID; @@ -438,7 +439,7 @@ struct securityd { bool (*soscc_DeleteEngineState)(CFErrorRef *error); SOSPeerInfoRef (*soscc_CopyApplicant)(CFErrorRef *error); CFDataRef (*soscc_CopyCircleJoiningBlob)(SOSPeerInfoRef applicant, CFErrorRef *error); - CFDataRef (*soscc_CopyInitialSyncData)(CFErrorRef *error); + CFDataRef (*soscc_CopyInitialSyncData)(SOSInitialSyncFlags flags, CFErrorRef *error); bool (*soscc_JoinWithCircleJoiningBlob)(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); bool (*soscc_SOSCCCleanupKVSKeys)(CFErrorRef *error); bool (*soscc_SOSCCTestPopulateKVSWithBadKeys)(CFErrorRef *error); diff --git a/OSX/sec/ipc/server.c b/OSX/sec/ipc/server.c index cfef1c39..917ac3e6 100644 --- a/OSX/sec/ipc/server.c +++ b/OSX/sec/ipc/server.c @@ -48,16 +48,16 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "trust/trustd/OTATrustUtilities.h" +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecLogSettingsServer.h" +#include "keychain/securityd/SecOTRRemote.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "keychain/securityd/iCloudTrace.h" +#include "keychain/securityd/spi.h" #include #include #include @@ -67,17 +67,17 @@ #include #include #include -#include -#include -#include +#include "trust/trustd/personalization.h" +#include "trust/trustd/SecPinningDb.h" +#include "keychain/securityd/SFKeychainControlManager.h" #include #include #include "keychain/ot/OctagonControlServer.h" -#include +#include "keychain/securityd/SFKeychainServer.h" #if !TARGET_OS_BRIDGE -#include +#include "keychain/securityd/PolicyReporter.h" #endif #include @@ -1537,7 +1537,8 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, break; case kSecXPCOpCopyInitialSyncBlob: if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementCircleJoin, &error)) { - CFDataRef initialblob = SOSCCCopyInitialSyncData_Server(&error); + uint64_t flags = xpc_dictionary_get_uint64(event, kSecXPCKeyFlags); // 0 is a valid flags, so no error checking + CFDataRef initialblob = SOSCCCopyInitialSyncData_Server((uint32_t)flags, &error); if (initialblob) { xpc_object_t xpc_object = _CFXPCCreateXPCObjectFromCFObject(initialblob); xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_object); diff --git a/OSX/sec/ipc/server_endpoint.m b/OSX/sec/ipc/server_endpoint.m index 4d3fa424..8db291ac 100644 --- a/OSX/sec/ipc/server_endpoint.m +++ b/OSX/sec/ipc/server_endpoint.m @@ -32,7 +32,7 @@ #include "ipc/server_entitlement_helpers.h" #include "ipc/server_endpoint.h" -#include "securityd/SecItemServer.h" +#include "keychain/securityd/SecItemServer.h" #include #pragma mark - Securityd Server diff --git a/OSX/sec/ipc/server_security_helpers.m b/OSX/sec/ipc/server_security_helpers.m index 946e16f3..cd7f0e15 100644 --- a/OSX/sec/ipc/server_security_helpers.m +++ b/OSX/sec/ipc/server_security_helpers.m @@ -34,7 +34,7 @@ #include "utilities/SecCFRelease.h" #include "utilities/SecCFWrappers.h" #include "utilities/debugging.h" -#include "securityd/SecDbQuery.h" +#include "keychain/securityd/SecDbQuery.h" #if __has_include() && TARGET_HAS_KEYSTORE #include diff --git a/OSX/sec/ipc/server_xpc.m b/OSX/sec/ipc/server_xpc.m index c311212f..27413305 100644 --- a/OSX/sec/ipc/server_xpc.m +++ b/OSX/sec/ipc/server_xpc.m @@ -47,13 +47,13 @@ #include #include -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemDb.h" #include "keychain/ckks/CKKSViewManager.h" -#import "securityd/SecDbBackupManager.h" +#import "keychain/securityd/SecDbBackupManager.h" @interface SecOSTransactionHolder : NSObject @property os_transaction_t transaction; diff --git a/OSX/sec/os_log/com.apple.security.trustedpeers.plist b/OSX/sec/os_log/com.apple.security.trustedpeers.plist new file mode 100644 index 00000000..29e89f75 --- /dev/null +++ b/OSX/sec/os_log/com.apple.security.trustedpeers.plist @@ -0,0 +1,35 @@ + + + + + DEFAULT-OPTIONS + + Enabled + True + Persist + Default + Enable-Oversize-Messages + + TTL + Default + Development + + Enabled + True + Persist + Default + TTL + Default + + Debug + + Enabled + True + Persist + True + TTL + 2 + + + + diff --git a/OSX/sec/securityd/CheckV12DevEnabled.h b/OSX/sec/securityd/CheckV12DevEnabled.h deleted file mode 100644 index 34c930d5..00000000 --- a/OSX/sec/securityd/CheckV12DevEnabled.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// CheckV12DevEnabled.h -// Security_ios -// -// Created by Wouter de Groot on 2018-10-20. -// - -#ifndef CHECKV12DEVENABLED_H_ -#define CHECKV12DEVENABLED_H_ - -void resetCheckV12DevEnabled(void); -extern int (*checkV12DevEnabled)(void); - -#endif diff --git a/OSX/sec/securityd/CheckV12DevEnabled.m b/OSX/sec/securityd/CheckV12DevEnabled.m deleted file mode 100644 index b211e141..00000000 --- a/OSX/sec/securityd/CheckV12DevEnabled.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// CheckV12DevEnabled.m -// Security_ios -// -// Created by Wouter de Groot on 2018-10-20. -// - -// TODO: remove me when keychain backup is enabled for all - -#include "CheckV12DevEnabled.h" - -#if __OBJC2__ - -#import -#import - -static int realCheckV12DevEnabled() { - static bool enabled = NO; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; - enabled = [defaults boolForKey:@"enableKeychainBackupDevelopment"]; - }); - return enabled ? 1 : 0; -} - -int (*checkV12DevEnabled)(void) = realCheckV12DevEnabled; - -void resetCheckV12DevEnabled(void) { - checkV12DevEnabled = realCheckV12DevEnabled; -} - -#endif diff --git a/OSX/sec/securityd/Info-macOS.plist b/OSX/sec/securityd/Info-macOS.plist deleted file mode 100644 index db4a61ea..00000000 --- a/OSX/sec/securityd/Info-macOS.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleAllowMixedLocalizations - - CFBundleDevelopmentRegion - English - CFBundleExecutable - secd - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - securityd - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/OSX/sec/securityd/OTATrustUtilities.h b/OSX/sec/securityd/OTATrustUtilities.h deleted file mode 100644 index 4b770f9d..00000000 --- a/OSX/sec/securityd/OTATrustUtilities.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * OTATrustUtilities.h - */ - -#ifndef _OTATRUSTUTILITIES_H_ -#define _OTATRUSTUTILITIES_H_ 1 - -#include -#include -#include -#include - -__BEGIN_DECLS - -// Opaque type that holds the data for a specific version of the OTA PKI assets -typedef struct _OpaqueSecOTAPKI *SecOTAPKIRef; - -// Returns a boolean for whether the current instance is the system trustd -bool SecOTAPKIIsSystemTrustd(void); - -// Returns the trust server workloop -dispatch_queue_t SecTrustServerGetWorkloop(void); - -// Convert a trusted CT log array to a trusted CT log dictionary, indexed by the LogID -CF_RETURNS_RETAINED -CFDictionaryRef SecOTAPKICreateTrustedCTLogsDictionaryFromArray(CFArrayRef trustedCTLogsArray); - -// Get a reference to the current OTA PKI asset data -// Caller is responsible for releasing the returned SecOTAPKIRef -CF_EXPORT CF_RETURNS_RETAINED -SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef(void); - -// Accessor to retrieve a copy of the current black listed key. -// Caller is responsible for releasing the returned CFSetRef -CF_EXPORT -CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve a copy of the current gray listed key. -// Caller is responsible for releasing the returned CFSetRef -CF_EXPORT -CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve a copy of the current allow list dictionary. -// Caller is responsible for releasing the returned CFDictionaryRef -CF_EXPORT -CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve a copy of the allow list for a specific authority key ID. -// Caller is responsible for releasing the returned CFArrayRef -CF_EXPORT -CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID); - -// Accessor to retrieve a copy of the current trusted certificate transparency logs. -// Caller is responsible for releasing the returned CFArrayRef -CF_EXPORT -CFDictionaryRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the path of the current pinning list. -// Caller is responsible for releasing the returned CFURLRef -CF_EXPORT -CFURLRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the array of Escrow certificates. -// Caller is responsible for releasing the returned CFArrayRef -CF_EXPORT -CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the dictionary of EV Policy OIDs to Anchor digest. -// Caller is responsible for releasing the returned CFDictionaryRef -CF_EXPORT -CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the dictionary of anchor digest to file offset. -// Caller is responsible for releasing the returned CFDictionaryRef -CF_EXPORT -CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the pointer to the top of the anchor certs file. -// Caller should NOT free the returned pointer. The caller should hold -// a reference to the SecOTAPKIRef object until finished with -// the returned pointer. -CF_EXPORT -const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the full path to the valid update snapshot resource. -// The return value may be NULL if the resource does not exist. -// Caller should NOT free the returned pointer. The caller should hold -// a reference to the SecOTAPKIRef object until finished with -// the returned pointer. -CF_EXPORT -const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the full path to the valid database snapshot resource. -// The return value may be NULL if the resource does not exist. -// Caller should NOT free the returned pointer. The caller should hold -// a reference to the SecOTAPKIRef object until finished with -// the returned pointer. -CF_EXPORT -const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the current valid snapshot version. -CF_EXPORT -CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the current valid snapshot format. -CF_EXPORT -CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the OTAPKI trust store version -// Note: Trust store is not mutable by assets -CF_EXPORT -uint64_t SecOTAPKIGetTrustStoreVersion(SecOTAPKIRef otapkiRef); - -// Accessor to retrieve the OTAPKI asset version -CF_EXPORT -uint64_t SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef); - -// Accessors to retrieve the last check in time for the OTAPKI asset -CF_EXPORT -CFDateRef SecOTAPKICopyLastAssetCheckInDate(SecOTAPKIRef otapkiRef); - -#define kSecOTAPKIAssetStalenessAtRisk (60*60*24*30) // 30 days -#define kSecOTAPKIAssetStalenessWarning (60*60*24*45) // 45 days -#define kSecOTAPKIAssetStalenessDisable (60*60*24*60) // 60 days -bool SecOTAPKIAssetStalenessLessThanSeconds(SecOTAPKIRef otapkiRef, CFTimeInterval seconds); - -#if __OBJC__ -// SPI to return the current sampling rate for the event name -// This rate is actually n where we sample 1 out of every n -NSNumber *SecOTAPKIGetSamplingRateForEvent(SecOTAPKIRef otapkiRef, NSString *eventName); -#endif // __OBJC__ - -CFArrayRef SecOTAPKICopyAppleCertificateAuthorities(SecOTAPKIRef otapkiRef); - -extern const CFStringRef kOTAPKIKillSwitchCT; -bool SecOTAPKIKillSwitchEnabled(SecOTAPKIRef otapkiRef, CFStringRef switchKey); - -// SPI to return the array of currently trusted Escrow certificates -CF_EXPORT -CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error); - -// SPI to return the array of currently trusted CT logs -CF_EXPORT -CFDictionaryRef SecOTAPKICopyCurrentTrustedCTLogs(CFErrorRef* error); - -// SPI to return dictionary of CT log matching specified key id */ -CF_EXPORT -CFDictionaryRef SecOTAPKICopyCTLogForKeyID(CFDataRef keyID, CFErrorRef* error); - -// SPI to return the current OTA PKI trust store version -// Note: Trust store is not mutable by assets -CF_EXPORT -uint64_t SecOTAPKIGetCurrentTrustStoreVersion(CFErrorRef* CF_RETURNS_RETAINED error); - -// SPI to return the current OTA PKI asset version -CF_EXPORT -uint64_t SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error); - -// SPI to return the current OTA SecExperiment asset version -CF_EXPORT -uint64_t SecOTASecExperimentGetCurrentAssetVersion(CFErrorRef* error); - -// SPI to reset the current OTA PKI asset version to the version shipped -// with the system -CF_EXPORT -uint64_t SecOTAPKIResetCurrentAssetVersion(CFErrorRef* CF_RETURNS_RETAINED error); - -// SPI to signal trustd to get a new set of trust data -// Always returns the current asset version. Returns an error with -// a reason if the update was not successful. -CF_EXPORT -uint64_t SecOTAPKISignalNewAsset(CFErrorRef* CF_RETURNS_RETAINED error); - -// SPI to signal trustd to get a new set of SecExperiment data -// Always returns the current asset version. Returns an error with -// a reason if the update was not successful. -CF_EXPORT -uint64_t SecOTASecExperimentGetNewAsset(CFErrorRef* error); - -// SPI to copy current SecExperiment asset data -CF_EXPORT -CFDictionaryRef SecOTASecExperimentCopyAsset(CFErrorRef* error); - -/* "Internal" interfaces for tests */ -#if !TARGET_OS_BRIDGE && __OBJC__ -BOOL UpdateOTACheckInDate(void); -void UpdateKillSwitch(NSString *key, bool value); -#endif - -__END_DECLS - -#endif /* _OTATRUSTUTILITIES_H_ */ diff --git a/OSX/sec/securityd/OTATrustUtilities.m b/OSX/sec/securityd/OTATrustUtilities.m deleted file mode 100644 index c9510aa0..00000000 --- a/OSX/sec/securityd/OTATrustUtilities.m +++ /dev/null @@ -1,2281 +0,0 @@ -/* - * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * OTATrustUtilities.m - */ - -#import -#include "OTATrustUtilities.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecFramework.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#import - -#if !TARGET_OS_BRIDGE -#import -#import -#include -#include -#include -#import -#endif - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR -#import -#include -#endif - -static inline bool isNSNumber(id nsType) { - return nsType && [nsType isKindOfClass:[NSNumber class]]; -} - -static inline bool isNSDictionary(id nsType) { - return nsType && [nsType isKindOfClass:[NSDictionary class]]; -} - -static inline bool isNSArray(id nsType) { - return nsType && [nsType isKindOfClass:[NSArray class]]; -} - -static inline bool isNSDate(id nsType) { - return nsType && [nsType isKindOfClass:[NSDate class]]; -} - -static inline bool isNSData(id nsType) { - return nsType && [nsType isKindOfClass:[NSData class]]; -} - -#define SECURITYD_ROLE_ACCOUNT 64 -#define ROOT_ACCOUNT 0 - -bool SecOTAPKIIsSystemTrustd() { - static bool result = false; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ -#ifdef NO_SERVER - // Test app running as trustd -#elif TARGET_OS_IPHONE - if (getuid() == SECURITYD_ROLE_ACCOUNT || - (getuid() == ROOT_ACCOUNT && gTrustd)) // Test app running as trustd -#else - if (getuid() == ROOT_ACCOUNT) -#endif - { - result = true; - } - }); - return result; -} - -dispatch_queue_t SecTrustServerGetWorkloop(void) { - static dispatch_workloop_t workloop = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - workloop = dispatch_workloop_create("com.apple.trustd.evaluation"); - }); - return workloop; -} - -/* MARK: - */ -/* MARK: System Trust Store */ -static CFStringRef kSecSystemTrustStoreBundlePath = CFSTR("/System/Library/Security/Certificates.bundle"); - -CFGiblisGetSingleton(CFBundleRef, SecSystemTrustStoreGetBundle, bundle, ^{ - CFStringRef bundlePath = NULL; -#if TARGET_OS_SIMULATOR - char *simulatorRoot = getenv("SIMULATOR_ROOT"); - if (simulatorRoot) - bundlePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s%@"), simulatorRoot, kSecSystemTrustStoreBundlePath); -#endif - if (!bundlePath) - bundlePath = CFRetainSafe(kSecSystemTrustStoreBundlePath); - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath, kCFURLPOSIXPathStyle, true); - *bundle = (url) ? CFBundleCreate(kCFAllocatorDefault, url) : NULL; - CFReleaseSafe(url); - CFReleaseSafe(bundlePath); -}) - -static CFURLRef SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName, - CFStringRef resourceType, CFStringRef subDirName) { - CFURLRef url = NULL; - CFBundleRef bundle = SecSystemTrustStoreGetBundle(); - if (bundle) { - url = CFBundleCopyResourceURL(bundle, resourceName, - resourceType, subDirName); - } - if (!url) { - secwarning("resource: %@.%@ in %@ not found", resourceName, - resourceType, subDirName); - } - return url; -} - -static NSURL *SecSystemTrustStoreCopyResourceNSURL(NSString *resourceFileName) { - CFBundleRef bundle = SecSystemTrustStoreGetBundle(); - if (!bundle) { - return NULL; - } - NSURL *resourceDir = CFBridgingRelease(CFBundleCopyResourcesDirectoryURL(bundle)); - if (!resourceDir) { - return NULL; - } - NSURL *fileURL = [NSURL URLWithString:resourceFileName - relativeToURL:resourceDir]; - if (!fileURL) { - secwarning("resource: %@ not found", resourceFileName); - } - return fileURL; -} - -static CFDataRef SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName, - CFStringRef resourceType, CFStringRef subDirName) { - CFURLRef url = SecSystemTrustStoreCopyResourceURL(resourceName, resourceType, subDirName); - CFDataRef data = NULL; - if (url) { - SInt32 error; - if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, - url, &data, NULL, NULL, &error)) { - secwarning("read: %ld", (long) error); - } - CFRelease(url); - } - return data; -} - -/* MARK: - */ -/* MARK: MobileAsset Updates */ -// MARK: Forward Declarations -static uint64_t GetAssetVersion(CFErrorRef *error); -static uint64_t GetSystemVersion(CFStringRef key); -#if !TARGET_OS_BRIDGE -static BOOL UpdateFromAsset(NSURL *localURL, NSNumber *asset_version, NSError **error); -static NSNumber *SecExperimentUpdateAsset(MAAsset *asset, NSNumber *asset_version, NSError **error); -static void TriggerUnlockNotificationOTATrustAssetCheck(NSString* assetType, dispatch_queue_t queue); -#endif - -/* This queue is for fetching changes to the OTAPKI reference or otherwise doing maintenance activities */ -static dispatch_queue_t kOTABackgroundQueue = NULL; - -// MARK: Constants -NSString *kOTATrustContentVersionKey = @"MobileAssetContentVersion"; -NSString *kOTATrustLastCheckInKey = @"MobileAssetLastCheckIn"; -NSString *kOTATrustContextFilename = @"OTAPKIContext.plist"; -NSString *kOTATrustTrustedCTLogsFilename = @"TrustedCTLogs.plist"; -NSString *kOTATrustAnalyticsSamplingRatesFilename = @"AnalyticsSamplingRates.plist"; -NSString *kOTATrustAppleCertifcateAuthoritiesFilename = @"AppleCertificateAuthorities.plist"; -NSString *kOTASecExperimentConfigFilename = @"SecExperimentAssets.plist"; - -const CFStringRef kOTAPKIKillSwitchCT = CFSTR("CTKillSwitch"); - -#if !TARGET_OS_BRIDGE -NSString *OTATrustMobileAssetType = @"com.apple.MobileAsset.PKITrustSupplementals"; -NSString *OTASecExperimentMobileAssetType = @"com.apple.MobileAsset.SecExperimentAssets"; -#define kOTATrustMobileAssetNotification "com.apple.MobileAsset.PKITrustSupplementals.ma.cached-metadata-updated" -#define kOTATrustOnDiskAssetNotification "com.apple.trustd.asset-updated" -#define kOTATrustCheckInNotification "com.apple.trustd.asset-check-in" -#define kOTATrustKillSwitchNotification "com.apple.trustd.kill-switch" -#define kOTASecExperimentNewAssetNotification "com.apple.trustd.secexperiment.asset-updated" -const NSUInteger OTATrustMobileAssetCompatibilityVersion = 1; -const NSUInteger OTASecExperimentMobileAssetCompatibilityVersion = 1; -#define kOTATrustDefaultUpdatePeriod 60*60*12 // 12 hours -#define kOTATrustMinimumUpdatePeriod 60*5 // 5 min -#define kOTATrustDefaultWaitPeriod 60 // 1 min - -#if TARGET_OS_OSX -const CFStringRef kSecSUPrefDomain = CFSTR("com.apple.SoftwareUpdate"); -const CFStringRef kSecSUScanPrefConfigDataInstallKey = CFSTR("ConfigDataInstall"); -#endif - -// MARK: Helper functions -typedef enum { - OTATrustLogLevelNone, - OTATrustLogLevelDebug, - OTATrustLogLevelInfo, - OTATrustLogLevelNotice, - OTATrustLogLevelError, -} OTATrustLogLevel; - -static void MakeOTATrustError(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, NSString *format,...) NS_FORMAT_FUNCTION(6,7); -static void MakeOTATrustErrorWithAttributes(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, - NSDictionary *attributes, NSString *format,...) - NS_FORMAT_FUNCTION(7,8); - -static void MakeOTATrustErrorArgs(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, - NSDictionary *attributes, NSString *format, va_list arguments) - NS_FORMAT_FUNCTION(7,0); - -static void LogLocally(OTATrustLogLevel level, NSString *errorString) { - switch (level) { - case OTATrustLogLevelNone: - break; - case OTATrustLogLevelDebug: - secdebug("OTATrust", "%@", errorString); - break; - case OTATrustLogLevelInfo: - secinfo("OTATrust", "%@", errorString); - break; - case OTATrustLogLevelNotice: - secnotice("OTATrust", "%@", errorString); - break; - case OTATrustLogLevelError: - secerror("OTATrust: %@", errorString); - break; - } -} - -static void LogRemotelyWithAttributes(OTATrustLogLevel level, NSError **error, NSDictionary *attributes) { -#if ENABLE_TRUSTD_ANALYTICS - /* only report errors and notices */ - if (error && level == OTATrustLogLevelError) { - [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:YES result:*error withAttributes:attributes]; - } else if (error && level == OTATrustLogLevelNotice) { - [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:NO result:*error withAttributes:attributes]; - } -#endif // ENABLE_TRUSTD_ANALYTICS -} - -static void LogRemotely(OTATrustLogLevel level, NSError **error) { - LogRemotelyWithAttributes(level, error, nil); -} - -static void MakeOTATrustErrorArgs(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, - NSDictionary *attributes, NSString *format, va_list args) { - NSString *formattedString = nil; - if (format) { - formattedString = [[NSString alloc] initWithFormat:format arguments:args]; - } - - NSError *localError = nil; - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; - if (format) { - [userInfo setObject:formattedString forKey:NSLocalizedDescriptionKey]; - } - if (error && *error) { - userInfo[NSUnderlyingErrorKey] = *error; - } - localError = [NSError errorWithDomain:errDomain - code:errCode - userInfo:userInfo]; - - LogLocally(level, formattedString); - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - LogRemotelyWithAttributes(level, &localError, attributes); - } - if (error) { *error = localError; } -} - -static void MakeOTATrustErrorWithAttributes(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, - NSDictionary *attributes, NSString *format,...) { - va_list args; - va_start(args, format); - MakeOTATrustErrorArgs(assetType, error, level, errDomain, errCode, attributes, format, args); - va_end(args); -} - -static void MakeOTATrustError(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, NSString *format,...) { - va_list args; - va_start(args, format); - MakeOTATrustErrorArgs(assetType, error, level, errDomain, errCode, nil, format, args); - va_end(args); -} - -static BOOL CanCheckMobileAsset(void) { - BOOL result = YES; -#if TARGET_OS_OSX - /* Check the user's SU preferences to determine if "Install system data files" is off */ - if (!CFPreferencesSynchronize(kSecSUPrefDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost)) { - secerror("OTATrust: unable to synchronize SoftwareUpdate prefs"); - return NO; - } - - id value = nil; - if (CFPreferencesAppValueIsForced(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)) { - value = CFBridgingRelease(CFPreferencesCopyAppValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)); - } else { - value = CFBridgingRelease(CFPreferencesCopyValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain, - kCFPreferencesAnyUser, kCFPreferencesCurrentHost)); - } - if (isNSNumber(value)) { - result = [value boolValue]; - } - - if (!result) { secnotice("OTATrust", "User has disabled system data installation."); } - - /* MobileAsset.framework isn't mastered into the BaseSystem. Check that the MA classes are linked. */ - if (![ASAssetQuery class] || ![ASAsset class] || ![MAAssetQuery class] || ![MAAsset class]) { - secnotice("OTATrust", "Weak-linked MobileAsset framework missing."); - result = NO; - } -#endif - return result; -} - -static BOOL ShouldUpdateWithAsset(NSString *assetType, NSNumber *asset_version) { - if (![asset_version isKindOfClass:[NSNumber class]]) { - return NO; - } - CFErrorRef error = nil; - uint64_t current_version; - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - current_version = SecOTAPKIGetCurrentAssetVersion(&error); - } else if ([assetType isEqualToString:OTASecExperimentMobileAssetType]) { - current_version = SecOTASecExperimentGetCurrentAssetVersion(&error); - } else { - return NO; - } - if (error) { - CFReleaseNull(error); - return NO; - } - if ([asset_version compare:[NSNumber numberWithUnsignedLongLong:current_version]] == NSOrderedDescending) { - return YES; - } - return NO; -} - -// MARK: File management functions -static bool verify_create_path(const char *path) { - int ret = mkpath_np(path, 0755); - if (!(ret == 0 || ret == EEXIST)) { - secerror("could not create path: %s (%s)", path, strerror(ret)); - return false; - } - return true; -} - -static NSURL *GetAssetFileURL(NSString *filename) { - /* Make sure the /Library/Keychains directory is there */ - NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(nil)); - NSURL *directory = [keychainsDirectory URLByAppendingPathComponent:@"SupplementalsAssets/" isDirectory:YES]; - if (!verify_create_path([directory fileSystemRepresentation])) { - return nil; - } - - if (filename) { - return [directory URLByAppendingPathComponent:filename]; - } else { - return directory; - } -} - -static void DeleteFileWithName(NSString *filename) { - NSURL *fileURL = GetAssetFileURL(filename); - if (remove([fileURL fileSystemRepresentation]) == -1) { - int error = errno; - if (error != ENOENT) { - secnotice("OTATrust", "failed to remove %@: %s", fileURL, strerror(error)); - } - } -} - -static BOOL UpdateOTAContextOnDisk(NSString *key, id value, NSError **error) { - if (SecOTAPKIIsSystemTrustd()) { - /* Get current context, if applicable, and update/add key/value */ - NSURL *otaContextFile = GetAssetFileURL(kOTATrustContextFilename); - NSDictionary *currentContext = [NSDictionary dictionaryWithContentsOfURL:otaContextFile]; - NSMutableDictionary *newContext = nil; - if (currentContext) { - newContext = [currentContext mutableCopy]; - } else { - newContext = [NSMutableDictionary dictionary]; - } - newContext[key] = value; - - /* Write dictionary to disk */ - if (![newContext writeToURL:otaContextFile error:error]) { - secerror("OTATrust: unable to write OTA Context to disk: %@", error ? *error : nil); - LogRemotely(OTATrustLogLevelError, error); - return NO; - } - return YES; - } - return NO; -} - -static BOOL UpdateOTAContext(NSNumber *asset_version, NSError **error) { - return UpdateOTAContextOnDisk(kOTATrustContentVersionKey, asset_version, error) && UpdateOTACheckInDate(); -} - -/* Delete only the asset data but not the check-in time. */ -static void DeleteOldAssetData(void) { - if (SecOTAPKIIsSystemTrustd()) { - /* Delete the asset files, but keep the check-in time and version */ - DeleteFileWithName(kOTATrustTrustedCTLogsFilename); - DeleteFileWithName(kOTATrustAnalyticsSamplingRatesFilename); - DeleteFileWithName(kOTATrustAppleCertifcateAuthoritiesFilename); - } -} - -/* Delete all asset data, intended for error cases */ -static BOOL DeleteAssetFromDisk(void) { - if (SecOTAPKIIsSystemTrustd()) { - DeleteOldAssetData(); - DeleteFileWithName(kOTATrustContextFilename); - return YES; - } - return NO; -} - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR -static bool ChangeFileProtectionToClassD(NSURL *fileURL, NSError **error) { - BOOL result = YES; - int file_fd = open([fileURL fileSystemRepresentation], O_RDONLY); - if (file_fd) { - int retval = fcntl(file_fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_D); - if (retval < 0) { - MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, - @"set proteciton class error for asset %d: %s", errno, strerror(errno)); - result = NO; - } - close(file_fd); - } else { - MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, - @"open error for asset %d: %s", errno, strerror(errno)); - result = NO; - } - return result; -} -#endif - -static BOOL CopyFileToDisk(NSString *filename, NSURL *localURL, NSError **error) { - if (SecOTAPKIIsSystemTrustd()) { - NSURL *toFileURL = GetAssetFileURL(filename); - secdebug("OTATrust", "will copy asset file data from \"%@\"", localURL); - copyfile_state_t state = copyfile_state_alloc(); - int retval = copyfile([localURL fileSystemRepresentation], [toFileURL fileSystemRepresentation], - state, COPYFILE_DATA); - copyfile_state_free(state); - if (retval < 0) { - MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, - @"copyfile error for asset %d: %s", errno, strerror(errno)); - return NO; - } else { - /* make sure we can read this file before first unlock */ -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - return ChangeFileProtectionToClassD(toFileURL, error); -#else - return YES; -#endif - } - } - return NO; -} - -static void GetKillSwitchAttributes(NSDictionary *attributes) { - bool killSwitchEnabled = false; - - // CT Kill Switch - NSNumber *ctKillSwitch = [attributes objectForKey:(__bridge NSString*)kOTAPKIKillSwitchCT]; - if (isNSNumber(ctKillSwitch)) { - NSError *error = nil; - UpdateOTAContextOnDisk((__bridge NSString*)kOTAPKIKillSwitchCT, ctKillSwitch, &error); - UpdateKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT, [ctKillSwitch boolValue]); - secnotice("OTATrust", "got CT kill switch = %d", [ctKillSwitch boolValue]); - killSwitchEnabled = true; - } - - /* Other kill switches TBD. - * When adding one, make sure to add to the Analytics Samplers since these kill switches - * are installed before the full asset is downloaded and installed. (A device can have the - * kill switches without having the asset version that contained them.) */ - - // notify the other trustds if any kill switch was read - if (SecOTAPKIIsSystemTrustd() && killSwitchEnabled) { - notify_post(kOTATrustKillSwitchNotification); - } -} - -// MARK: Fetch and Update Functions -static NSNumber *PKIUpdateAndPurgeAsset(MAAsset *asset, NSNumber *asset_version, NSError **error) { - if (SecPinningDbUpdateFromURL([asset getLocalFileUrl], error) && - UpdateFromAsset([asset getLocalFileUrl], asset_version, error)) { - secnotice("OTATrust", "finished update to version %@ from installed asset. purging asset.", asset_version); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logSuccessForEventNamed:TrustdHealthAnalyticsEventOTAPKIEvent]; -#endif // ENABLE_TRUSTD_ANALYTICS - [asset purge:^(MAPurgeResult purge_result) { - if (purge_result != MAPurgeSucceeded) { - secerror("OTATrust: purge failed: %ld", (long)purge_result); - } - }]; - return asset_version; - } else { - MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecCallbackFailed, - @"Failed to install new asset version %@ from %@", asset_version, [asset getLocalFileUrl]); - return nil; - } -} - -static NSNumber *UpdateAndPurgeAsset(NSString* assetType, MAAsset *asset, NSNumber *asset_version, NSError **error) { - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - return PKIUpdateAndPurgeAsset(asset, asset_version, error); - } else if ([assetType isEqualToString:OTASecExperimentMobileAssetType]) { - return SecExperimentUpdateAsset(asset, asset_version, error); - } else { - return nil; - } -} - -static MADownloadOptions *GetMADownloadOptions(BOOL wait) { - /* default behavior */ - MADownloadOptions *options = [[MADownloadOptions alloc] init]; - options.discretionary = YES; - options.allowsCellularAccess = NO; - - /* If an XPC interface is waiting on this, all expenses allowed */ - if (wait) { - options.discretionary = NO; - options.allowsCellularAccess = YES; - return options; - } - - /* If last asset check-in was too long ago, use more expensive options */ - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (!SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessWarning)) { - secnotice("OTATrust", "Asset staleness state: warning"); - options.allowsCellularAccess = YES; - options.discretionary = NO; - } else if (!SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessAtRisk)) { - secnotice("OTATrust", "Asset staleness state: at risk"); - options.discretionary = NO; - } - CFReleaseNull(otapkiref); - return options; -} - -static BOOL assetVersionCheck(NSString *assetType, MAAsset *asset) { - NSUInteger compatVersion; - NSError *ma_error = nil; - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - compatVersion = OTATrustMobileAssetCompatibilityVersion; - } else { - compatVersion = OTASecExperimentMobileAssetCompatibilityVersion; - } - /* Check Compatibility Version against this software version */ - NSNumber *compatibilityVersion = [asset assetProperty:@"_CompatibilityVersion"]; - if (!isNSNumber(compatibilityVersion) || - [compatibilityVersion unsignedIntegerValue] != compatVersion) { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecIncompatibleVersion, - @"skipping asset %@ because Compatibility Version doesn't match %@", assetType, compatibilityVersion); - return NO; - } - /* Check Content Version against the current content version */ - NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; - if (!ShouldUpdateWithAsset(assetType, asset_version)) { - /* write the version and last (successful) check-in time */ - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - UpdateOTAContext(asset_version, &ma_error); - NSDictionary *eventAttributes = @{ - @"assetVersion" : asset_version, - @"systemVersion" : @(GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey)), - @"installedVersion" : @(SecOTAPKIGetCurrentAssetVersion(nil)), - }; - MakeOTATrustErrorWithAttributes(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecDuplicateItem, eventAttributes, - @"skipping asset %@ because we already have _ContentVersion %@ (or newer)", assetType, asset_version); - } else { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecDuplicateItem, - @"skipping asset %@ because we already have _ContentVersion %@ (or newer)", assetType, asset_version); - } - return NO; - } - return YES; -} - -static int downloadWaitTime(void) { - NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; - NSNumber *updateTimeout = [defaults valueForKey:@"TrustdAssetDownloadWaitTimeout"]; - int timeout = kOTATrustDefaultWaitPeriod; - if (isNSNumber(updateTimeout)) { - timeout = [updateTimeout intValue]; - } - return timeout; -} - -static BOOL DownloadOTATrustAsset(BOOL isLocalOnly, BOOL wait, NSString *assetType, NSError **error) { - if (!CanCheckMobileAsset()) { - MakeOTATrustError(assetType, error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecServiceNotAvailable, - @"MobileAsset disabled, skipping check."); - return NO; - } - - __block NSNumber *updated_version = nil; - __block dispatch_semaphore_t done = wait ? dispatch_semaphore_create(0) : nil; - __block NSError *ma_error = nil; - - secnotice("OTATrust", "begin MobileAsset query for catalog %@", assetType); - [MAAsset startCatalogDownload:assetType options:GetMADownloadOptions(wait) then:^(MADownLoadResult result) { - @autoreleasepool { - os_transaction_t transaction = os_transaction_create("com.apple.trustd.asset.download"); - if (result != MADownloadSuccessful) { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MADownLoadResult", (OSStatus)result, - @"failed to download catalog for asset %@: %ld", assetType, (long)result); - if (result == MADownloadDaemonNotReady && ([assetType isEqualToString:OTATrustMobileAssetType])) { - /* mobileassetd has to wait for first unlock to download. trustd usually launches before first unlock. */ - TriggerUnlockNotificationOTATrustAssetCheck(assetType, kOTABackgroundQueue); - } - return; - } - MAAssetQuery *query = [[MAAssetQuery alloc] initWithType:(NSString *)assetType]; - [query augmentResultsWithState:true]; - - secnotice("OTATrust", "begin MobileAsset metadata sync request %{public}@", assetType); - MAQueryResult queryResult = [query queryMetaDataSync]; - if (queryResult != MAQuerySuccessful) { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MAQueryResult", (OSStatus)queryResult, - @"failed to query MobileAsset %@ metadata: %ld", assetType, (long)queryResult); - return; - } - - if (!query.results) { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, - @"no results in MobileAsset query for %@", assetType); - return; - } - - bool began_async_job = false; - for (MAAsset *asset in query.results) { - /* Check Compatibility Version against this software version */ - NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; - if (!assetVersionCheck(assetType, asset)) { - continue; - } - - if ([assetType isEqualToString:OTATrustMobileAssetType]) { - GetKillSwitchAttributes(asset.attributes); - } - - switch (asset.state) { - default: - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, - @"unknown asset state %ld", (long)asset.state); - continue; - case MAInstalled: - /* The asset is already in the cache, get it from disk. */ - secdebug("OTATrust", "OTATrust asset %{public}@ already installed", assetType); - updated_version = UpdateAndPurgeAsset(assetType, asset, asset_version, &ma_error); - break; - case MAUnknown: - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MAAssetState", (OSStatus)asset.state, - @"asset %@ is unknown", assetType); - continue; - case MADownloading: - secnotice("OTATrust", "asset %{public}@ is downloading", assetType); - /* fall through */ - case MANotPresent: - secnotice("OTATrust", "begin download of OTATrust asset"); - began_async_job = true; - [asset startDownload:GetMADownloadOptions(wait) then:^(MADownLoadResult downloadResult) { - @autoreleasepool { - os_transaction_t inner_transaction = os_transaction_create("com.apple.trustd.asset.downloadAsset"); - if (downloadResult != MADownloadSuccessful) { - MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MADownLoadResult", (OSStatus)downloadResult, - @"failed to download asset %@: %ld", assetType, (long)downloadResult); - return; - } - updated_version = UpdateAndPurgeAsset(assetType, asset, asset_version, &ma_error); - if (wait) { - dispatch_semaphore_signal(done); - } - (void)inner_transaction; // dead store - inner_transaction = nil; - } - }]; - break; - } /* switch (asset.state) */ - } /* for (MAAsset.. */ - if (wait && !began_async_job) { - dispatch_semaphore_signal(done); - } - /* Done with the transaction */ - (void)transaction; // dead store - transaction = nil; - } /* autoreleasepool */ - }]; /* [MAAsset startCatalogDownload: ] */ - - /* If the caller is waiting for a response, wait up to one minute for the update to complete. - * If the MAAsset callback does not complete in that time, report a timeout. - * If the MAAsset callback completes and did not successfully update, it should report an error; - * forward that error to the caller. - * If the MAAsset callback completes and did not update and did not provide an error; report - * an unknown error. */ - BOOL result = NO; - if (wait) { - if (dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * downloadWaitTime())) != 0) { - MakeOTATrustError(assetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecNetworkFailure, - @"Failed to get asset %@ metadata within %d seconds.", assetType, downloadWaitTime()); - } else { - result = (updated_version != nil); - if (error && ma_error) { - *error = ma_error; - } else if (!result) { - MakeOTATrustError(assetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternalComponent, - @"Unknown error occurred."); - } - } - } - return result; -} - -static void TriggerUnlockNotificationOTATrustAssetCheck(NSString* assetType, dispatch_queue_t queue) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - /* If the last check-in is recent enough, wait for our regularly scheduled check-in. */ - if (SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessAtRisk)) { - CFReleaseNull(otapkiref); - return; - } - CFReleaseNull(otapkiref); -#if !TARGET_OS_SIMULATOR - /* register for unlock notifications */ - int out_token = 0; - notify_register_dispatch(kMobileKeyBagLockStatusNotificationID, &out_token, queue, ^(int token) { - secnotice("OTATrust", "Got lock status notification for at-risk last check-in after MA daemon error"); - (void)DownloadOTATrustAsset(NO, NO, assetType, nil); - notify_cancel(token); - }); -#endif -} - -static bool InitializeKillSwitch(NSString *key) { -#if !TARGET_OS_BRIDGE - NSError *error = nil; - NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&error]; - if (isNSDictionary(OTAPKIContext)) { - NSNumber *killSwitchValue = OTAPKIContext[key]; - if (isNSNumber(killSwitchValue)) { - secinfo("OTATrust", "found on-disk kill switch %{public}@ with value %d", key, [killSwitchValue boolValue]); - return [killSwitchValue boolValue]; - } else { - MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, - @"OTAContext.plist missing check-in"); - } - } else { - MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, - @"OTAContext.plist missing dictionary"); - } -#endif - return false; -} - -static void InitializeOTATrustAsset(dispatch_queue_t queue) { - /* Only the "system" trustd does updates */ - if (SecOTAPKIIsSystemTrustd()) { - /* Asynchronously ask MobileAsset for most recent asset. */ - dispatch_async(queue, ^{ - secnotice("OTATrust", "Initial check with MobileAsset for newer PKITrustSupplementals asset"); - (void)DownloadOTATrustAsset(NO, NO, OTATrustMobileAssetType, nil); - }); - - /* Register for changes in our asset */ - if (CanCheckMobileAsset()) { - int out_token = 0; - notify_register_dispatch(kOTATrustMobileAssetNotification, &out_token, queue, ^(int __unused token) { - secnotice("OTATrust", "Got notification about a new PKITrustSupplementals asset from mobileassetd."); - (void)DownloadOTATrustAsset(YES, NO, OTATrustMobileAssetType, nil); - }); - } - } else { - /* Register for changes signaled by the system trustd */ - secnotice("OTATrust", "Initializing listener for PKI Asset changes from system trustd."); - int out_token = 0; - notify_register_dispatch(kOTATrustOnDiskAssetNotification, &out_token, queue, ^(int __unused token) { - secnotice("OTATrust", "Got notification about a new PKITrustSupplementals asset from system trustd."); - NSError *nserror = nil; - CFErrorRef error = nil; - NSNumber *asset_version = [NSNumber numberWithUnsignedLongLong:GetAssetVersion(&error)]; - if (error) { - nserror = CFBridgingRelease(error); - } - if (!UpdateFromAsset(GetAssetFileURL(nil), asset_version, &nserror)) { - secerror("OTATrust: failed to update from asset after notification: %@", nserror); - /* Reset our last check-in time and reset the asset version to the system asset version -- even - * though we may be using something newer than that (but not as new as what's on disk). On re-launch - * (provided reading from disk still fails) we'd be using the system asset version anyway. */ - SecOTAPKIResetCurrentAssetVersion(&error); - } - }); - int out_token2 = 0; - notify_register_dispatch(kOTATrustCheckInNotification, &out_token2, queue, ^(int __unused token) { - secinfo("OTATrust", "Got notification about successful PKITrustSupplementals asset check-in"); - (void)UpdateOTACheckInDate(); - }); - int out_token3 = 0; - notify_register_dispatch(kOTATrustKillSwitchNotification, &out_token3, queue, ^(int __unused token) { - UpdateKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT, InitializeKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT)); - }); - } -} - -static void InitializeOTASecExperimentAsset(dispatch_queue_t queue) { - /* Only the "system" trustd does updates */ - if (SecOTAPKIIsSystemTrustd()) { - /* Asynchronously ask MobileAsset for most recent asset. */ - dispatch_async(queue, ^{ - secnotice("OTATrust", "Initial check with MobileAsset for newer SecExperiment asset"); - (void)DownloadOTATrustAsset(NO, NO, OTASecExperimentMobileAssetType, nil); - }); - } else { - /* Register for changes signaled by the system trustd */ - secnotice("OTATrust", "Initializing listener for SecExperiment Asset changes from system trustd."); - int out_token = 0; - notify_register_dispatch(kOTASecExperimentNewAssetNotification, &out_token, queue, ^(int __unused token) { - NSError *error = nil; - secnotice("OTATrust", "Got notification about a new SecExperiment asset from system trustd."); - MAAssetQuery *assetQuery = [[MAAssetQuery alloc] initWithType:OTASecExperimentMobileAssetType]; - [assetQuery returnTypes:MAInstalledOnly]; - MAQueryResult queryResult = [assetQuery queryMetaDataSync]; - - if (queryResult != MAQuerySuccessful) { - secerror("OTATrust: failed to update SecExperiment Asset after notification: %ld", (long)queryResult); - } else { - secnotice("OTATrust", "Updated SecExperiment asset successfully"); - for (MAAsset *asset in assetQuery.results) { - NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; - if (!assetVersionCheck(OTASecExperimentMobileAssetType, asset)) { - continue; - } - UpdateAndPurgeAsset(OTASecExperimentMobileAssetType, asset, asset_version, &error); - } - } - }); - } -} - -static void TriggerPeriodicOTATrustAssetChecks(dispatch_queue_t queue) { - if (SecOTAPKIIsSystemTrustd()) { - static sec_action_t action; - static bool first_launch = true; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; - NSNumber *updateDeltas = [defaults valueForKey:@"PKITrustSupplementalsUpdatePeriod"]; - int delta = kOTATrustDefaultUpdatePeriod; - if (isNSNumber(updateDeltas)) { - delta = [updateDeltas intValue]; - if (delta < kOTATrustMinimumUpdatePeriod) { - delta = kOTATrustMinimumUpdatePeriod; - } - } - secnotice("OTATrust", "Setting periodic update delta to %d seconds", delta); - action = sec_action_create_with_queue(queue,"OTATrust", delta); - sec_action_set_handler(action, ^{ - if (!first_launch) { - (void)DownloadOTATrustAsset(NO, NO, OTASecExperimentMobileAssetType, nil); - (void)DownloadOTATrustAsset(NO, NO, OTATrustMobileAssetType, nil); - } - first_launch = false; - }); - }); - sec_action_perform(action); - } -} -#endif /* !TARGET_OS_BRIDGE */ - -/* MARK: - */ -/* MARK: Initialization functions */ -static CFPropertyListRef CFPropertyListCopyFromSystem(CFStringRef asset) { - CFPropertyListRef plist = NULL; - CFDataRef xmlData = SecSystemTrustStoreCopyResourceContents(asset, CFSTR("plist"), NULL); - - if (xmlData) { - plist = CFPropertyListCreateWithData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL, NULL); - CFRelease(xmlData); - } - - return plist; -} - -static uint64_t GetSystemVersion(CFStringRef key) { - uint64_t system_version = 0; - int64_t asset_number = 0; - - CFDataRef assetVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL); - if (NULL != assetVersionData) { - CFPropertyListFormat propFormat; - CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, assetVersionData, 0, &propFormat, NULL); - if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist)) { - CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)key); - if (NULL != versionNumber){ - CFNumberGetValue(versionNumber, kCFNumberSInt64Type, &asset_number); - if (asset_number < 0) { // Not valid - asset_number = 0; - } - system_version = (uint64_t)asset_number; - } - } - CFReleaseSafe(versionPlist); - CFReleaseSafe(assetVersionData); - } - - return system_version; -} - -static bool initialization_error_from_asset_data = false; - -static bool ShouldInitializeWithAsset(void) { - uint64_t system_version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); - uint64_t asset_version = GetAssetVersion(nil); - - if (asset_version > system_version) { - secnotice("OTATrust", "Using asset v%llu instead of system v%llu", asset_version, system_version); - return !initialization_error_from_asset_data; - } - return false; -} - -static CFSetRef CFSetCreateFromPropertyList(CFPropertyListRef plist) { - CFSetRef result = NULL; - - if (plist) { - CFMutableSetRef tempSet = NULL; - if (CFGetTypeID(plist) == CFArrayGetTypeID()) { - tempSet = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks); - if (NULL == tempSet) { - return result; - } - CFArrayRef array = (CFArrayRef)plist; - CFIndex num_keys = CFArrayGetCount(array); - for (CFIndex idx = 0; idx < num_keys; idx++) { - CFDataRef data = (CFDataRef)CFArrayGetValueAtIndex(array, idx); - CFSetAddValue(tempSet, data); - } - } else { - return result; - } - - result = tempSet; - } - return result; -} - -static CF_RETURNS_RETAINED CFSetRef InitializeBlackList() { - CFPropertyListRef plist = CFPropertyListCopyFromSystem(CFSTR("Blocked")); - CFSetRef result = CFSetCreateFromPropertyList(plist); - CFReleaseSafe(plist); - - return result; -} - -static CF_RETURNS_RETAINED CFSetRef InitializeGrayList() { - CFPropertyListRef plist = CFPropertyListCopyFromSystem(CFSTR("GrayListedKeys")); - CFSetRef result = CFSetCreateFromPropertyList(plist); - CFReleaseSafe(plist); - - return result; -} - -static CF_RETURNS_RETAINED CFURLRef InitializePinningList() { - return SecSystemTrustStoreCopyResourceURL(CFSTR("CertificatePinning"), CFSTR("plist"), NULL); -} - -static CF_RETURNS_RETAINED CFDictionaryRef InitializeAllowList() { - CFPropertyListRef allowList = CFPropertyListCopyFromSystem(CFSTR("Allowed")); - - if (allowList && (CFGetTypeID(allowList) == CFDictionaryGetTypeID())) { - return allowList; - } else { - CFReleaseNull(allowList); - return NULL; - } -} - -static NSDictionary *ConvertTrustedCTLogsArrayToDictionary(NSArray *trustedLogsArray) { - NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:trustedLogsArray.count]; - [trustedLogsArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if (!isNSDictionary(obj)) { - secerror("OTATrust: failed to read entry from trusted CT logs array at index %lu", (unsigned long)idx); - return; - } - NSDictionary *log_data = (NSDictionary *)obj; - NSData *log_id = log_data[@"log_id"]; - if (!isNSData(log_id)) { - secinfo("OTATrust", "failed to read log_id from trusted CT log array entry at index %lu, computing log_id", (unsigned long)idx); - // We can make the log_id from the key - NSData *key = log_data[@"key"]; - if (!isNSData(key)) { - secerror("failed to read key from trusted CT log array entry at index %lu", (unsigned long)idx); - return; - } - log_id = CFBridgingRelease(SecSHA256DigestCreateFromData(NULL, (__bridge CFDataRef)key)); - } - [result setObject:log_data forKey:log_id]; - }]; - return result; -} - -CFDictionaryRef SecOTAPKICreateTrustedCTLogsDictionaryFromArray(CFArrayRef trustedCTLogsArray) -{ - @autoreleasepool { - return CFBridgingRetain(ConvertTrustedCTLogsArrayToDictionary((__bridge NSArray*)trustedCTLogsArray)); - } -} - -static CF_RETURNS_RETAINED CFDictionaryRef InitializeTrustedCTLogs() { - @autoreleasepool { - NSArray *trustedCTLogs = nil; - NSError *error = nil; -#if !TARGET_OS_BRIDGE - if (ShouldInitializeWithAsset()) { - trustedCTLogs = [NSArray arrayWithContentsOfURL:GetAssetFileURL(kOTATrustTrustedCTLogsFilename) error:&error]; - if (!isNSArray(trustedCTLogs)) { - secerror("OTATrust: failed to read CT list from asset data: %@", error); - LogRemotely(OTATrustLogLevelError, &error); - if (!DeleteAssetFromDisk()) { - initialization_error_from_asset_data = true; - } - } - } -#endif - if (!isNSArray(trustedCTLogs)) { - trustedCTLogs = [NSArray arrayWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustTrustedCTLogsFilename)]; - } - if (isNSArray(trustedCTLogs)) { - return CFBridgingRetain(ConvertTrustedCTLogsArrayToDictionary(trustedCTLogs)); - } - return NULL; - } -} - -static CF_RETURNS_RETAINED CFDictionaryRef InitializeEVPolicyToAnchorDigestsTable() { - CFDictionaryRef result = NULL; - CFPropertyListRef evroots = CFPropertyListCopyFromSystem(CFSTR("EVRoots")); - - if (evroots) { - if (CFGetTypeID(evroots) == CFDictionaryGetTypeID()) { - /* @@@ Ensure that each dictionary key is a dotted list of digits, - each value is an NSArrayRef and each element in the array is a - 20 byte digest. */ - result = (CFDictionaryRef)evroots; - } - else { - secwarning("EVRoot.plist is wrong type."); - CFRelease(evroots); - } - } - - return result; -} - -static CFIndex InitializeValidSnapshotVersion(CFIndex *outFormat) { - CFIndex validVersion = 0; - CFIndex validFormat = 0; - CFDataRef validVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("ValidUpdate"), CFSTR("plist"), NULL); - if (NULL != validVersionData) - { - CFPropertyListFormat propFormat; - CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, validVersionData, 0, &propFormat, NULL); - if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist)) - { - CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Version")); - if (NULL != versionNumber) - { - CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &validVersion); - } - CFNumberRef formatNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Format")); - if (NULL != formatNumber) - { - CFNumberGetValue(formatNumber, kCFNumberCFIndexType, &validFormat); - } - } - CFReleaseSafe(versionPlist); - CFReleaseSafe(validVersionData); - } - if (outFormat) { - *outFormat = validFormat; - } - return validVersion; -} - -static Boolean PathExists(const char* path, size_t* pFileSize) { - const char *checked_path = (path) ? path : ""; - Boolean result = false; - struct stat sb; - - if (NULL != pFileSize) { - *pFileSize = 0; - } - - int stat_result = stat(checked_path, &sb); - result = (stat_result == 0); - - if (result && !S_ISDIR(sb.st_mode)) { - // It is a file - if (NULL != pFileSize) { - *pFileSize = (size_t)sb.st_size; - } - } - - return result; -} - -static const char* InitializeValidSnapshotData(CFStringRef filename_str) { - char *result = NULL; - const char *base_error_str = "could not get valid snapshot"; - - CFURLRef valid_url = SecSystemTrustStoreCopyResourceURL(filename_str, CFSTR("sqlite3"), NULL); - if (NULL == valid_url) { - secerror("%s", base_error_str); - } else { - CFStringRef valid_str = CFURLCopyFileSystemPath(valid_url, kCFURLPOSIXPathStyle); - char file_path_buffer[PATH_MAX]; - memset(file_path_buffer, 0, PATH_MAX); - if (NULL == valid_str) { - secerror("%s path", base_error_str); - } else { - const char *valid_cstr = CFStringGetCStringPtr(valid_str, kCFStringEncodingUTF8); - if (NULL == valid_cstr) { - if (CFStringGetCString(valid_str, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8)) { - valid_cstr = file_path_buffer; - } - } - if (NULL == valid_cstr) { - secerror("%s path as UTF8 string", base_error_str); - } else { - asprintf(&result, "%s", valid_cstr); - } - } - CFReleaseSafe(valid_str); - } - CFReleaseSafe(valid_url); - if (result && !PathExists(result, NULL)) { - free(result); - result = NULL; - } - return (const char*)result; -} - -static const char* InitializeValidDatabaseSnapshot() { - return InitializeValidSnapshotData(CFSTR("valid")); -} - -static const uint8_t* MapFile(const char* path, size_t* out_file_size) { - int rtn, fd; - const uint8_t *buf = NULL; - struct stat sb; - size_t size = 0; - - if (NULL == path || NULL == out_file_size) { - return NULL; - } - - *out_file_size = 0; - - fd = open(path, O_RDONLY); - if (fd < 0) { return NULL; } - rtn = fstat(fd, &sb); - if (rtn || (sb.st_size > (off_t) ((UINT32_MAX >> 1)-1))) { - close(fd); - return NULL; - } - size = (size_t)sb.st_size; - - buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (!buf || buf == MAP_FAILED) { - secerror("unable to map %s (errno %d)", path, errno); - close(fd); - return NULL; - } - - close(fd); - *out_file_size = size; - return buf; -} - -static void UnMapFile(void* mapped_data, size_t data_size) { - if (!mapped_data) { - return; - } - int rtn = munmap(mapped_data, data_size); - if (rtn != 0) { - secerror("unable to unmap %ld bytes at %p (error %d)", data_size, mapped_data, rtn); - } -} - -struct index_record { - unsigned char hash[CC_SHA1_DIGEST_LENGTH]; - uint32_t offset; -}; -typedef struct index_record index_record; - -static bool InitializeAnchorTable(CFDictionaryRef* pLookupTable, const char** ppAnchorTable) { - - bool result = false; - - if (NULL == pLookupTable || NULL == ppAnchorTable) { - return result; - } - - *pLookupTable = NULL; - *ppAnchorTable = NULL;; - - CFDataRef cert_index_file_data = NULL; - char file_path_buffer[PATH_MAX]; - CFURLRef table_data_url = NULL; - CFStringRef table_data_cstr_path = NULL; - const char* table_data_path = NULL; - const index_record* pIndex = NULL; - size_t index_offset = 0; - size_t index_data_size = 0; - CFMutableDictionaryRef anchorLookupTable = NULL; - uint32_t offset_int_value = 0; - CFNumberRef index_offset_value = NULL; - CFDataRef index_hash = NULL; - CFMutableArrayRef offsets = NULL; - Boolean release_offset = false; - - char* local_anchorTable = NULL; - size_t local_anchorTableSize = 0; - - // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used. - CFReleaseSafe(cert_index_file_data); - cert_index_file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL); - if (!cert_index_file_data) { - secerror("could not find certsIndex"); - } - table_data_url = SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL); - if (!table_data_url) { - secerror("could not find certsTable"); - } - - if (NULL != table_data_url) { - table_data_cstr_path = CFURLCopyFileSystemPath(table_data_url, kCFURLPOSIXPathStyle); - if (NULL != table_data_cstr_path) { - memset(file_path_buffer, 0, PATH_MAX); - table_data_path = CFStringGetCStringPtr(table_data_cstr_path, kCFStringEncodingUTF8); - if (NULL == table_data_path) { - if (CFStringGetCString(table_data_cstr_path, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8)) { - table_data_path = file_path_buffer; - } - } - local_anchorTable = (char *)MapFile(table_data_path, &local_anchorTableSize); - CFReleaseSafe(table_data_cstr_path); - } - } - CFReleaseSafe(table_data_url); - - if (NULL == local_anchorTable || NULL == cert_index_file_data) { - // we are in trouble - if (NULL != local_anchorTable) { - UnMapFile(local_anchorTable, local_anchorTableSize); - local_anchorTable = NULL; - local_anchorTableSize = 0; - } - CFReleaseSafe(cert_index_file_data); - return result; - } - - // ------------------------------------------------------------------------ - // Now that the locations of the files are known and the table file has - // been mapped into memory, create a dictionary that maps the SHA1 hash of - // normalized issuer to the offset in the mapped anchor table file which - // contains a index_record to the correct certificate - // ------------------------------------------------------------------------ - pIndex = (const index_record*)CFDataGetBytePtr(cert_index_file_data); - index_data_size = CFDataGetLength(cert_index_file_data); - - anchorLookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - for (index_offset = index_data_size; index_offset > 0; index_offset -= sizeof(index_record), pIndex++) { - offset_int_value = pIndex->offset; - - index_offset_value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &offset_int_value); - index_hash = CFDataCreate(kCFAllocatorDefault, pIndex->hash, CC_SHA1_DIGEST_LENGTH); - - // see if the dictionary already has this key - release_offset = false; - offsets = (CFMutableArrayRef)CFDictionaryGetValue(anchorLookupTable, index_hash); - if (NULL == offsets) { - offsets = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - release_offset = true; - } - - // Add the offset - CFArrayAppendValue(offsets, index_offset_value); - - // set the key value pair in the dictionary - CFDictionarySetValue(anchorLookupTable, index_hash, offsets); - - CFRelease(index_offset_value); - CFRelease(index_hash); - if (release_offset) { - CFRelease(offsets); - } - } - - CFRelease(cert_index_file_data); - - if (NULL != anchorLookupTable && NULL != local_anchorTable) { - *pLookupTable = anchorLookupTable; - *ppAnchorTable = local_anchorTable; - result = true; - } else { - CFReleaseSafe(anchorLookupTable); - if (NULL != local_anchorTable) { - UnMapFile(local_anchorTable, local_anchorTableSize); - local_anchorTable = NULL; - local_anchorTableSize = 0; - } - } - - return result; -} - -static void InitializeEscrowCertificates(CFArrayRef *escrowRoots, CFArrayRef *escrowPCSRoots) { - CFDataRef file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL); - - if (NULL == file_data) { - return; - } - - CFPropertyListFormat propFormat; - CFDictionaryRef certsDictionary = CFPropertyListCreateWithData(kCFAllocatorDefault, file_data, 0, &propFormat, NULL); - if (NULL != certsDictionary && CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef)certsDictionary)) { - CFArrayRef certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionEscrowKey")); - if (NULL != certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)certs) && CFArrayGetCount(certs) > 0) { - *escrowRoots = CFArrayCreateCopy(kCFAllocatorDefault, certs); - } - CFArrayRef pcs_certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionPCSEscrowKey")); - if (NULL != pcs_certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)pcs_certs) && CFArrayGetCount(pcs_certs) > 0) { - *escrowPCSRoots = CFArrayCreateCopy(kCFAllocatorDefault, pcs_certs); - } - } - CFReleaseSafe(certsDictionary); - CFRelease(file_data); -} - -static CF_RETURNS_RETAINED CFDictionaryRef InitializeEventSamplingRates() { - NSDictionary *analyticsSamplingRates = nil; - NSDictionary *eventSamplingRates = nil; - NSError *error = nil; -#if !TARGET_OS_BRIDGE - if (ShouldInitializeWithAsset()) { - analyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustAnalyticsSamplingRatesFilename) error:&error]; - if (!isNSDictionary(analyticsSamplingRates)) { - secerror("OTATrust: failed to read sampling rates from asset data: %@", error); - LogRemotely(OTATrustLogLevelError, &error); - if (!DeleteAssetFromDisk()) { - initialization_error_from_asset_data = true; - } - } - eventSamplingRates = analyticsSamplingRates[@"Events"]; - } -#endif - if (!isNSDictionary(eventSamplingRates)) { - analyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustAnalyticsSamplingRatesFilename)]; - } - if (isNSDictionary(analyticsSamplingRates)) { - eventSamplingRates = analyticsSamplingRates[@"Events"]; - if (isNSDictionary(eventSamplingRates)) { - return CFBridgingRetain(eventSamplingRates); - } - } - return NULL; -} - -static CF_RETURNS_RETAINED CFArrayRef InitializeAppleCertificateAuthorities() { - NSArray *appleCAs = nil; - NSError *error = nil; -#if !TARGET_OS_BRIDGE - if (ShouldInitializeWithAsset()) { - appleCAs = [NSArray arrayWithContentsOfURL:GetAssetFileURL(kOTATrustAppleCertifcateAuthoritiesFilename) error:&error]; - if (!isNSArray(appleCAs)) { - secerror("OTATrust: failed to read Apple CAs list from asset data: %@", error); - LogRemotely(OTATrustLogLevelError, &error); - if (!DeleteAssetFromDisk()) { - initialization_error_from_asset_data = true; - } - } - } -#endif - if (!isNSArray(appleCAs)) { - appleCAs = [NSArray arrayWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustAppleCertifcateAuthoritiesFilename)]; - } - if (isNSArray(appleCAs)) { - return CFBridgingRetain(appleCAs); - } - return NULL; -} - -/* MARK: - */ -/* MARK: SecOTA */ - -/* We keep track of one OTAPKI reference */ -static SecOTAPKIRef kCurrentOTAPKIRef = NULL; -/* This queue is for making changes to the OTAPKI reference */ -static dispatch_queue_t kOTAQueue = NULL; - -struct _OpaqueSecOTAPKI { - CFRuntimeBase _base; - CFSetRef _blackListSet; - CFSetRef _grayListSet; - CFDictionaryRef _allowList; - CFDictionaryRef _trustedCTLogs; - CFURLRef _pinningList; - CFArrayRef _escrowCertificates; - CFArrayRef _escrowPCSCertificates; - CFDictionaryRef _evPolicyToAnchorMapping; - CFDictionaryRef _anchorLookupTable; - const char* _anchorTable; - uint64_t _trustStoreVersion; - const char* _validDatabaseSnapshot; - CFIndex _validSnapshotVersion; - CFIndex _validSnapshotFormat; - uint64_t _assetVersion; - CFDateRef _lastAssetCheckIn; - CFDictionaryRef _eventSamplingRates; - CFArrayRef _appleCAs; - CFDictionaryRef _secExperimentConfig; - uint64_t _secExperimentAssetVersion; - bool _ctKillSwitch; -}; - -CFGiblisFor(SecOTAPKI) - -static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf; - return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR(""), - otapkiRef->_trustStoreVersion, otapkiRef->_assetVersion); -} - -static void SecOTAPKIDestroy(CFTypeRef cf) { - SecOTAPKIRef otapkiref = (SecOTAPKIRef)cf; - - CFReleaseNull(otapkiref->_blackListSet); - CFReleaseNull(otapkiref->_grayListSet); - CFReleaseNull(otapkiref->_escrowCertificates); - CFReleaseNull(otapkiref->_escrowPCSCertificates); - - CFReleaseNull(otapkiref->_evPolicyToAnchorMapping); - CFReleaseNull(otapkiref->_anchorLookupTable); - - CFReleaseNull(otapkiref->_trustedCTLogs); - CFReleaseNull(otapkiref->_pinningList); - CFReleaseNull(otapkiref->_eventSamplingRates); - CFReleaseNull(otapkiref->_appleCAs); - CFReleaseNull(otapkiref->_lastAssetCheckIn); - CFReleaseNull(otapkiref->_secExperimentConfig); - - if (otapkiref->_anchorTable) { - free((void *)otapkiref->_anchorTable); - otapkiref->_anchorTable = NULL; - } - if (otapkiref->_validDatabaseSnapshot) { - free((void *)otapkiref->_validDatabaseSnapshot); - otapkiref->_validDatabaseSnapshot = NULL; - } -} - -static uint64_t GetSystemTrustStoreVersion(void) { - return GetSystemVersion(CFSTR("VersionNumber")); -} - -static uint64_t GetAssetVersion(CFErrorRef *error) { - @autoreleasepool { - /* Get system asset version */ - uint64_t version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); - -#if !TARGET_OS_BRIDGE - uint64_t asset_version = 0; - NSError *nserror = nil; - NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&nserror]; - if (isNSDictionary(OTAPKIContext)) { - NSNumber *tmpNumber = OTAPKIContext[kOTATrustContentVersionKey]; - if (isNSNumber(tmpNumber)) { - asset_version = [tmpNumber unsignedLongLongValue]; - } else if (error) { - MakeOTATrustError(OTATrustMobileAssetType, &nserror, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, - @"OTAContext.plist missing version"); - } - } else if (error) { - MakeOTATrustError(OTATrustMobileAssetType, &nserror, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, - @"OTAContext.plist missing dictionary"); - } - - if (asset_version > version) { - return asset_version; - } else { - /* Don't delete the last check-in time so that we know we're up to date with the MobileAsset. */ - if (error) { - /* only log this if we're tracking errors */ - secnotice("OTATrust", "asset (%llu) is not newer than the system version (%llu); deleting stale data", asset_version, version); - *error = CFRetainSafe((__bridge CFErrorRef)nserror); - } - DeleteOldAssetData(); - } -#endif - return version; - } -} - -static CF_RETURNS_RETAINED CFDateRef InitializeLastAssetCheckIn(void) { -#if !TARGET_OS_BRIDGE - NSError *error = nil; - NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&error]; - if (isNSDictionary(OTAPKIContext)) { - NSDate *checkIn = OTAPKIContext[kOTATrustLastCheckInKey]; - if (isNSDate(checkIn)) { - return CFRetainSafe((__bridge CFDateRef)checkIn); - } else { - MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, - @"OTAContext.plist missing check-in"); - } - } else { - MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, - @"OTAContext.plist missing dictionary"); - } -#endif - return NULL; -} - -static SecOTAPKIRef SecOTACreate() { - - SecOTAPKIRef otapkiref = NULL; - - otapkiref = CFTypeAllocate(SecOTAPKI, struct _OpaqueSecOTAPKI , kCFAllocatorDefault); - - if (NULL == otapkiref) { - return otapkiref; - } - - // Make sure that if this routine has to bail that the clean up - // will do the right thing - memset(otapkiref, 0, sizeof(*otapkiref)); - - // Start off by getting the trust store version - otapkiref->_trustStoreVersion = GetSystemTrustStoreVersion(); - - // Get the set of black listed keys - CFSetRef blackKeysSet = InitializeBlackList(); - if (NULL == blackKeysSet) { - CFReleaseNull(otapkiref); - return otapkiref; - } - otapkiref->_blackListSet = blackKeysSet; - - // Get the set of gray listed keys - CFSetRef grayKeysSet = InitializeGrayList(); - if (NULL == grayKeysSet) { - CFReleaseNull(otapkiref); - return otapkiref; - } - otapkiref->_grayListSet = grayKeysSet; - - // Get the allow list dictionary - // (now loaded lazily in SecOTAPKICopyAllowList) - - // Get the trusted Certificate Transparency Logs - otapkiref->_trustedCTLogs = InitializeTrustedCTLogs(); - - // Get the pinning list - otapkiref->_pinningList = InitializePinningList(); - - // Get the Event Sampling Rates - otapkiref->_eventSamplingRates = InitializeEventSamplingRates(); - - // Get the list of CAs used by Apple - otapkiref->_appleCAs = InitializeAppleCertificateAuthorities(); - - // Get the asset version (after possible reset due to missing asset data) - if (!initialization_error_from_asset_data) { - CFErrorRef error = nil; - otapkiref->_assetVersion = GetAssetVersion(&error); - otapkiref->_lastAssetCheckIn = InitializeLastAssetCheckIn(); - CFReleaseNull(error); - } else { - otapkiref->_assetVersion = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); - } - otapkiref->_secExperimentAssetVersion = 0; - // Get the valid update snapshot version and format - CFIndex update_format = 0; - otapkiref->_validSnapshotVersion = InitializeValidSnapshotVersion(&update_format); - otapkiref->_validSnapshotFormat = update_format; - - // Get the valid database snapshot path (if it exists, NULL otherwise) - otapkiref->_validDatabaseSnapshot = InitializeValidDatabaseSnapshot(); - - CFArrayRef escrowCerts = NULL; - CFArrayRef escrowPCSCerts = NULL; - InitializeEscrowCertificates(&escrowCerts, &escrowPCSCerts); - if (NULL == escrowCerts || NULL == escrowPCSCerts) { - CFReleaseNull(escrowCerts); - CFReleaseNull(escrowPCSCerts); - CFReleaseNull(otapkiref); - return otapkiref; - } - otapkiref->_escrowCertificates = escrowCerts; - otapkiref->_escrowPCSCertificates = escrowPCSCerts; - - // Get the mapping of EV Policy OIDs to Anchor digest - CFDictionaryRef evOidToAnchorDigestMap = InitializeEVPolicyToAnchorDigestsTable(); - if (NULL == evOidToAnchorDigestMap) { - CFReleaseNull(otapkiref); - return otapkiref; - } - otapkiref->_evPolicyToAnchorMapping = evOidToAnchorDigestMap; - - CFDictionaryRef anchorLookupTable = NULL; - const char* anchorTablePtr = NULL; - - if (!InitializeAnchorTable(&anchorLookupTable, &anchorTablePtr)) { - CFReleaseSafe(anchorLookupTable); - if (anchorTablePtr) { - free((void *)anchorTablePtr); - } - CFReleaseNull(otapkiref); - return otapkiref; - } - otapkiref->_anchorLookupTable = anchorLookupTable; - otapkiref->_anchorTable = anchorTablePtr; - -#if !TARGET_OS_BRIDGE - /* Initialize our update handling */ - InitializeOTATrustAsset(kOTABackgroundQueue); - otapkiref->_ctKillSwitch = InitializeKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT); - InitializeOTASecExperimentAsset(kOTABackgroundQueue); -#else // TARGET_OS_BRIDGE - otapkiref->_ctKillSwitch = true; // bridgeOS never enforces CT -#endif // TARGET_OS_BRIDGE - - return otapkiref; -} - -SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef() { - __block SecOTAPKIRef result = NULL; - static dispatch_once_t kInitializeOTAPKI = 0; - dispatch_once(&kInitializeOTAPKI, ^{ - @autoreleasepool { - kOTAQueue = dispatch_queue_create("com.apple.security.OTAPKIQueue", NULL); - dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, - QOS_CLASS_BACKGROUND, 0); - attr = dispatch_queue_attr_make_with_autorelease_frequency(attr, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM); - kOTABackgroundQueue = dispatch_queue_create("com.apple.security.OTAPKIBackgroundQueue", attr); - if (!kOTAQueue || !kOTABackgroundQueue) { - secerror("Failed to create OTAPKI Queues. May crash later."); - } - dispatch_sync(kOTAQueue, ^{ - kCurrentOTAPKIRef = SecOTACreate(); - }); - } - }); - - dispatch_sync(kOTAQueue, ^{ - result = kCurrentOTAPKIRef; - CFRetainSafe(result); - }); - return result; -} - -#if !TARGET_OS_BRIDGE -BOOL UpdateOTACheckInDate(void) { - __block NSDate *checkIn = [NSDate date]; - dispatch_sync(kOTAQueue, ^{ - CFRetainAssign(kCurrentOTAPKIRef->_lastAssetCheckIn, (__bridge CFDateRef)checkIn); - }); - - if (SecOTAPKIIsSystemTrustd()) { - /* Let the other trustds know we successfully checked in */ - notify_post(kOTATrustCheckInNotification); - - /* Update the on-disk check-in date, so when we re-launch we remember */ - NSError *error = nil; - BOOL result = NO; - if (!(result = UpdateOTAContextOnDisk(kOTATrustLastCheckInKey, checkIn, &error))) { - secerror("OTATrust: failed to write last check-in time: %@", error); - } - return result; - } else { - return NO; - } -} - -void UpdateKillSwitch(NSString *key, bool value) { - dispatch_sync(kOTAQueue, ^{ - if ([key isEqualToString:(__bridge NSString*)kOTAPKIKillSwitchCT]) { - kCurrentOTAPKIRef->_ctKillSwitch = value; - } - }); -} - -static BOOL UpdateFromAsset(NSURL *localURL, NSNumber *asset_version, NSError **error) { - if (!localURL || !asset_version) { - MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, - @"missing url and version for downloaded asset"); - return NO; - } - __block NSArray *newTrustedCTLogs = NULL; - __block uint64_t version = [asset_version unsignedLongLongValue]; - __block NSDictionary *newAnalyticsSamplingRates = NULL; - __block NSArray *newAppleCAs = NULL; - - NSURL *TrustedCTLogsFileLoc = [NSURL URLWithString:kOTATrustTrustedCTLogsFilename - relativeToURL:localURL]; - newTrustedCTLogs = [NSArray arrayWithContentsOfURL:TrustedCTLogsFileLoc error:error]; - if (!newTrustedCTLogs) { - secerror("OTATrust: unable to create TrustedCTLogs from asset file: %@", error ? *error: nil); - LogRemotely(OTATrustLogLevelError, error); - return NO; - } - - NSURL *AnalyticsSamplingRatesFileLoc = [NSURL URLWithString:kOTATrustAnalyticsSamplingRatesFilename - relativeToURL:localURL]; - newAnalyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:AnalyticsSamplingRatesFileLoc error:error]; - if (!newAnalyticsSamplingRates) { - secerror("OTATrust: unable to create AnalyticsSamplingRates from asset file: %@", error ? *error: nil); - LogRemotely(OTATrustLogLevelError, error); - return NO; - } - - NSURL *AppleCAsFileLoc = [NSURL URLWithString:kOTATrustAppleCertifcateAuthoritiesFilename - relativeToURL:localURL]; - newAppleCAs = [NSArray arrayWithContentsOfURL:AppleCAsFileLoc error:error]; - if (!newAppleCAs) { - secerror("OTATrust: unable to create AppleCAs from asset file: %@", error ? *error: nil); - LogRemotely(OTATrustLogLevelError, error); - return NO; - } - - /* Update the Current OTAPKIRef with the new data */ - dispatch_sync(kOTAQueue, ^{ - secnotice("OTATrust", "updating asset version from %llu to %llu", kCurrentOTAPKIRef->_assetVersion, version); - CFRetainAssign(kCurrentOTAPKIRef->_trustedCTLogs, (__bridge CFDictionaryRef)ConvertTrustedCTLogsArrayToDictionary(newTrustedCTLogs)); - CFRetainAssign(kCurrentOTAPKIRef->_eventSamplingRates, (__bridge CFDictionaryRef)newAnalyticsSamplingRates); - CFRetainAssign(kCurrentOTAPKIRef->_appleCAs, (__bridge CFArrayRef)newAppleCAs); - kCurrentOTAPKIRef->_assetVersion = version; - }); - - /* Write the data to disk (so that we don't have to re-download the asset on re-launch) */ - DeleteAssetFromDisk(); - if (CopyFileToDisk(kOTATrustTrustedCTLogsFilename, TrustedCTLogsFileLoc, error) && - CopyFileToDisk(kOTATrustAnalyticsSamplingRatesFilename, AnalyticsSamplingRatesFileLoc, error) && - CopyFileToDisk(kOTATrustAppleCertifcateAuthoritiesFilename, AppleCAsFileLoc, error) && - UpdateOTAContext(asset_version, error)) { // Set version and check-in time last (after success) - /* If we successfully updated the "asset" on disk, signal the other trustds to pick up the changes */ - notify_post(kOTATrustOnDiskAssetNotification); - } else { - return NO; - } - - return YES; -} -#endif // !TARGET_OS_BRIDGE - -#if !TARGET_OS_BRIDGE -static NSNumber *SecExperimentUpdateAsset(MAAsset *asset, NSNumber *asset_version, NSError **error) { - NSURL *localURL = [asset getLocalFileUrl]; - if (!localURL || !asset_version) { - MakeOTATrustError(OTASecExperimentMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, - @"missing url and version for downloaded SecExperiment asset"); - return nil; - } - NSDictionary *newSecExpConfig = NULL; - uint64_t version = [asset_version unsignedLongLongValue]; - - NSURL *secExpConfigFileLoc = [NSURL URLWithString:kOTASecExperimentConfigFilename - relativeToURL:localURL]; - newSecExpConfig = [NSDictionary dictionaryWithContentsOfURL:secExpConfigFileLoc error:error]; - if (!newSecExpConfig) { - secerror("OTATrust: unable to create SecExperiment from asset file: %@", error ? *error: nil); - return nil; - } - /* Update the Current OTAPKIRef with the new data */ - dispatch_sync(kOTAQueue, ^{ - secnotice("OTATrust", "updating SecExperiment asset version from %llu to %llu", kCurrentOTAPKIRef->_secExperimentAssetVersion, version); - CFRetainAssign(kCurrentOTAPKIRef->_secExperimentConfig, (__bridge CFDictionaryRef)newSecExpConfig); - kCurrentOTAPKIRef->_secExperimentAssetVersion = version; - }); - /* Signal the other trustds to pick up the changes */ - notify_post(kOTASecExperimentNewAssetNotification); - return asset_version; -} -#endif // !TARGET_OS_BRIDGE - -CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return CFRetainSafe(otapkiRef->_blackListSet); -} - - -CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return CFRetainSafe(otapkiRef->_grayListSet); -} - -CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - CFDictionaryRef result = otapkiRef->_allowList; - if (!result) { - result = InitializeAllowList(); - otapkiRef->_allowList = result; - } - - return CFRetainSafe(result); -} - -CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID) { - // %%% temporary performance optimization: - // only load dictionary if we know an allow list exists for this key - const CFStringRef keyIDs[3] = { - CFSTR("7C724B39C7C0DB62A54F9BAA183492A2CA838259"), - CFSTR("65F231AD2AF7F7DD52960AC702C10EEFA6D53B11"), - CFSTR("D2A716207CAFD9959EEB430A19F2E0B9740EA8C7") - }; - CFArrayRef result = NULL; - bool hasAllowList = false; - CFIndex count = (sizeof(keyIDs) / sizeof(keyIDs[0])); - for (CFIndex ix=0; ix_trustedCTLogs; - CFRetainSafe(result); - return result; -} - -CFURLRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return CFRetainSafe(otapkiRef->_pinningList); -} - - -/* Returns an array of certificate data (CFDataRef) */ -CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef) { - CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if (NULL == otapkiRef) { - return result; - } - - switch (escrowRootType) { - // Note: we shouldn't be getting called to return baseline roots, - // since this function vends production roots by definition. - case kSecCertificateBaselineEscrowRoot: - case kSecCertificateProductionEscrowRoot: - case kSecCertificateBaselineEscrowBackupRoot: - case kSecCertificateProductionEscrowBackupRoot: - if (otapkiRef->_escrowCertificates) { - CFArrayRef escrowCerts = otapkiRef->_escrowCertificates; - CFArrayAppendArray(result, escrowCerts, CFRangeMake(0, CFArrayGetCount(escrowCerts))); - } - break; - case kSecCertificateBaselineEscrowEnrollmentRoot: - case kSecCertificateProductionEscrowEnrollmentRoot: - if (otapkiRef->_escrowCertificates) { - // for enrollment purposes, exclude the v100 root - static const unsigned char V100EscrowRoot[] = { - 0x65,0x5C,0xB0,0x3C,0x39,0x3A,0x32,0xA6,0x0B,0x96, - 0x40,0xC0,0xCA,0x73,0x41,0xFD,0xC3,0x9E,0x96,0xB3 - }; - CFArrayRef escrowCerts = otapkiRef->_escrowCertificates; - CFIndex idx, count = CFArrayGetCount(escrowCerts); - for (idx=0; idx < count; idx++) { - CFDataRef tmpData = (CFDataRef) CFArrayGetValueAtIndex(escrowCerts, idx); - SecCertificateRef tmpCert = (tmpData) ? SecCertificateCreateWithData(NULL, tmpData) : NULL; - CFDataRef sha1Hash = (tmpCert) ? SecCertificateGetSHA1Digest(tmpCert) : NULL; - const uint8_t *dp = (sha1Hash) ? CFDataGetBytePtr(sha1Hash) : NULL; - if (!(dp && !memcmp(V100EscrowRoot, dp, sizeof(V100EscrowRoot))) && tmpData) { - CFArrayAppendValue(result, tmpData); - } - CFReleaseSafe(tmpCert); - } - } - break; - case kSecCertificateBaselinePCSEscrowRoot: - case kSecCertificateProductionPCSEscrowRoot: - if (otapkiRef->_escrowPCSCertificates) { - CFArrayRef escrowPCSCerts = otapkiRef->_escrowPCSCertificates; - CFArrayAppendArray(result, escrowPCSCerts, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts))); - } - break; - default: - break; - } - - return result; -} - - -CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return CFRetainSafe(otapkiRef->_evPolicyToAnchorMapping); -} - - -CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return CFRetainSafe(otapkiRef->_anchorLookupTable); -} - -const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return otapkiRef->_anchorTable; -} - -const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - - return otapkiRef->_validDatabaseSnapshot; -} - -CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return 0; - } - - return otapkiRef->_validSnapshotVersion; -} - -CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return 0; - } - - return otapkiRef->_validSnapshotFormat; -} - -uint64_t SecOTAPKIGetTrustStoreVersion(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return 0; - } - - return otapkiRef->_trustStoreVersion; -} - -uint64_t SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return 0; - } - - return otapkiRef->_assetVersion; -} - -CFDateRef SecOTAPKICopyLastAssetCheckInDate(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - return CFRetainSafe(otapkiRef->_lastAssetCheckIn); -} - -bool SecOTAPKIAssetStalenessLessThanSeconds(SecOTAPKIRef otapkiRef, CFTimeInterval seconds) { - if (NULL == otapkiRef) { - return false; - } - - bool result = false; - CFDateRef lastCheckIn = CFRetainSafe(otapkiRef->_lastAssetCheckIn); - if (isDate(lastCheckIn) && (fabs([(__bridge NSDate *)lastCheckIn timeIntervalSinceNow]) < seconds)) { - result = true; - } - CFReleaseNull(lastCheckIn); - return result; -} - -NSNumber *SecOTAPKIGetSamplingRateForEvent(SecOTAPKIRef otapkiRef, NSString *eventName) { - if (NULL == otapkiRef) { - return nil; - } - -#if !TARGET_OS_BRIDGE - /* Trigger periodic background MA checks in system trustd - * We also check on trustd launch and listen for notifications. */ - TriggerPeriodicOTATrustAssetChecks(kOTABackgroundQueue); -#endif - - if (otapkiRef->_eventSamplingRates) { - CFTypeRef value = CFDictionaryGetValue(otapkiRef->_eventSamplingRates, (__bridge CFStringRef)eventName); - if (isNumberOfType(value, kCFNumberSInt64Type)) { - return (__bridge NSNumber *)value; - } - } - return nil; -} - -CFArrayRef SecOTAPKICopyAppleCertificateAuthorities(SecOTAPKIRef otapkiRef) { - if (NULL == otapkiRef) { - return NULL; - } - -#if !TARGET_OS_BRIDGE - /* Trigger periodic background MA checks in system trustd - * We also check on trustd launch and listen for notifications. */ - TriggerPeriodicOTATrustAssetChecks(kOTABackgroundQueue); -#endif - - return CFRetainSafe(otapkiRef->_appleCAs); -} - -bool SecOTAPKIKillSwitchEnabled(SecOTAPKIRef otapkiRef, CFStringRef key) { - if (NULL == otapkiRef || NULL == key) { - return false; - } - if (CFEqualSafe(key, kOTAPKIKillSwitchCT)) { - return otapkiRef->_ctKillSwitch; - } - return false; -} - -/* Returns an array of certificate data (CFDataRef) */ -CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return NULL; - } - - CFArrayRef result = SecOTAPKICopyEscrowCertificates(escrowRootType, otapkiref); - CFRelease(otapkiref); - - if (NULL == result) { - SecError(errSecInternal, error, CFSTR("Could not get escrow certificates from the current OTAPKIRef")); - } - return result; -} - -static CF_RETURNS_RETAINED CFDictionaryRef convertDataKeysToBase64Strings(CFDictionaryRef CF_CONSUMED dictionaryWithDataKeys) { - @autoreleasepool { - NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:((__bridge NSDictionary*)dictionaryWithDataKeys).count]; - NSDictionary *input = CFBridgingRelease(dictionaryWithDataKeys); - for (NSData *key in input) { - id obj = [input objectForKey:key]; - NSString *base64Key = [key base64EncodedStringWithOptions:0]; - result[base64Key] = obj; - } - return CFBridgingRetain(result); - } -} - -/* Returns an dictionary of dictionaries for currently trusted CT logs, indexed by the base64-encoded LogID */ -CFDictionaryRef SecOTAPKICopyCurrentTrustedCTLogs(CFErrorRef* error) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return NULL; - } - - CFDictionaryRef result = convertDataKeysToBase64Strings(SecOTAPKICopyTrustedCTLogs(otapkiref)); - CFReleaseSafe(otapkiref); - - if (NULL == result) { - SecError(errSecInternal, error, CFSTR("Could not get CT logs from the current OTAPKIRef")); - } - return result; -} - -/* Returns a dictionary for the CT log matching specified LogID */ -CFDictionaryRef SecOTAPKICopyCTLogForKeyID(CFDataRef keyID, CFErrorRef* error) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return NULL; - } - - CFDictionaryRef trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref); - CFReleaseNull(otapkiref); - if (!trustedLogs) { - return NULL; - } - CFDictionaryRef logDict = CFDictionaryGetValue(trustedLogs, keyID); - CFRetainSafe(logDict); - CFReleaseSafe(trustedLogs); - return logDict; -} - -uint64_t SecOTAPKIGetCurrentTrustStoreVersion(CFErrorRef* error){ - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return 0; - } - - uint64_t result = otapkiref->_trustStoreVersion; - CFReleaseNull(otapkiref); - return result; -} - -uint64_t SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return 0; - } - - uint64_t result = otapkiref->_assetVersion; - CFReleaseNull(otapkiref); - return result; -} - -uint64_t SecOTASecExperimentGetCurrentAssetVersion(CFErrorRef* error) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) { - SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); - return 0; - } - - uint64_t result = otapkiref->_secExperimentAssetVersion; - CFReleaseNull(otapkiref); - return result; - } - -uint64_t SecOTAPKIResetCurrentAssetVersion(CFErrorRef* error) { - uint64_t system_version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); - - dispatch_sync(kOTAQueue, ^{ - kCurrentOTAPKIRef->_assetVersion = system_version; - CFReleaseNull(kCurrentOTAPKIRef->_lastAssetCheckIn); - kCurrentOTAPKIRef->_lastAssetCheckIn = NULL; - }); - -#if !TARGET_OS_BRIDGE - DeleteAssetFromDisk(); -#endif - return system_version; -} - -uint64_t SecOTAPKISignalNewAsset(CFErrorRef* error) { - NSError *nserror = nil; - uint64_t version = 0; -#if !TARGET_OS_BRIDGE - if (SecOTAPKIIsSystemTrustd()) { - if (!DownloadOTATrustAsset(NO, YES, OTATrustMobileAssetType, &nserror) && error) { - *error = CFRetainSafe((__bridge CFErrorRef)nserror); - } - } else { - SecError(errSecServiceNotAvailable, error, CFSTR("This function may only be performed by the system trustd.")); - } - version = GetAssetVersion(nil); -#else - SecError(errSecUnsupportedService, error, CFSTR("This function is not available on this platform")); - version = GetAssetVersion(error); -#endif - return version; -} - -uint64_t SecOTASecExperimentGetNewAsset(CFErrorRef* error) { - NSError *nserror = nil; -#if !TARGET_OS_BRIDGE - if (SecOTAPKIIsSystemTrustd()) { - if (!DownloadOTATrustAsset(NO, YES, OTASecExperimentMobileAssetType, &nserror) && error) { - *error = CFRetainSafe((__bridge CFErrorRef)nserror); - } - } else { - SecError(errSecServiceNotAvailable, error, CFSTR("This function may only be performed by the system trustd.")); - } -#else - SecError(errSecUnsupportedService, error, CFSTR("This function is not available on this platform")); -#endif - return SecOTASecExperimentGetCurrentAssetVersion(error); -} - -CFDictionaryRef SecOTASecExperimentCopyAsset(CFErrorRef* error) { - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiRef) { - secnotice("OTATrust", "Null otapkiref"); - return NULL; - } - CFDictionaryRef asset = NULL; - if (otapkiRef->_secExperimentConfig) { - asset = CFRetainSafe(otapkiRef->_secExperimentConfig); - secnotice("OTATrust", "asset found"); - } else { - secnotice("OTATrust", "asset NULL"); - } - CFReleaseNull(otapkiRef); - return asset; -} diff --git a/OSX/sec/securityd/PolicyReporter.h b/OSX/sec/securityd/PolicyReporter.h deleted file mode 100644 index bc9a3c15..00000000 --- a/OSX/sec/securityd/PolicyReporter.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _SECURITY_POLICY_REPORTER_H -#define _SECURITY_POLICY_REPORTER_H - -#include - -__BEGIN_DECLS -void InitPolicyReporter(void); -__END_DECLS - -#endif diff --git a/OSX/sec/securityd/PolicyReporter.m b/OSX/sec/securityd/PolicyReporter.m deleted file mode 100644 index c5b42c66..00000000 --- a/OSX/sec/securityd/PolicyReporter.m +++ /dev/null @@ -1,339 +0,0 @@ -#include "PolicyReporter.h" - -#import -#import -#import -#import -#import -#import -#import -#import - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#import "utilities/debugging.h" -#import "TrustedPeers/TrustedPeers.h" - -// Stolen from keychain/SecureObjectSync/SOSEngine.c - -static NSString* getSOSView(id object, NSString* itemClass) { - if (![object isKindOfClass:[NSDictionary class]]) { - return nil; - } - - NSString *viewHint = object[(NSString*)kSecAttrSyncViewHint]; - if (viewHint != nil) { - return viewHint; - } else { - NSString *ag = object[(NSString*)kSecAttrAccessGroup]; - if ([itemClass isEqualToString: (NSString*)kSecClassKey] && [ag isEqualToString: @"com.apple.security.sos"]) { - return (NSString*)kSOSViewiCloudIdentity; - } else if ([ag isEqualToString: @"com.apple.cfnetwork"]) { - return (NSString*)kSOSViewAutofillPasswords; - } else if ([ag isEqualToString: @"com.apple.safari.credit-cards"]) { - return (NSString*)kSOSViewSafariCreditCards; - } else if ([itemClass isEqualToString: (NSString*)kSecClassGenericPassword]) { - if ([ag isEqualToString: @"apple"] && - [object[(NSString*)kSecAttrService] isEqualToString: @"AirPort"]) { - return (NSString*)kSOSViewWiFi; - } else if ([ag isEqualToString: @"com.apple.sbd"]) { - return (NSString*)kSOSViewBackupBagV0; - } else { - return (NSString*)kSOSViewOtherSyncable; // (genp) - } - } else { - return (NSString*)kSOSViewOtherSyncable; // (inet || keys) - } - } -} - -static inline NSNumber *now_msecs() { - return @(((long)[[NSDate date] timeIntervalSince1970] * 1000)); -} - -static NSString* cloudKitDeviceID() { - __block NSString* ret = nil; - - if (!os_variant_has_internal_diagnostics("com.apple.security")) { - return nil; - } - CKContainer *container = [CKContainer containerWithIdentifier:@"com.apple.security.keychain"]; - dispatch_semaphore_t sem = dispatch_semaphore_create(0); - [container fetchCurrentDeviceIDWithCompletionHandler:^(NSString* deviceID, NSError* error) { - if (error != nil) { - NSLog(@"failed to fetch CK deviceID: %@", error); - } else { - ret = deviceID; - } - dispatch_semaphore_signal(sem); - }]; - dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); - return ret; -} - -static void reportStats(unsigned expected_mismatches, unsigned real_mismatches, NSArray* reportedMismatches) { - NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; - NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfiguration]; - NSURL *endpoint = [NSURL URLWithString:@"https://xp.apple.com/report/2/xp_sear_keysync"]; - NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init]; - req.URL = endpoint; - req.HTTPMethod = @"POST"; - NSMutableDictionary *dict = [@{ - @"expectedMismatches": @(expected_mismatches), - @"realMismatches": @(real_mismatches), - @"eventTime": now_msecs(), - @"topic": @"xp_sear_keysync", - @"eventType": @"policy-dryrun", - } mutableCopy]; - NSDictionary *version = CFBridgingRelease(_CFCopySystemVersionDictionary()); - NSString *build = version[(__bridge NSString *)_kCFSystemVersionBuildVersionKey]; - if (build != nil) { - dict[@"build"] = build; - } else { - NSLog(@"Unable to find out build version"); - } - NSString *product = version[(__bridge NSString *)_kCFSystemVersionProductNameKey]; - if (product != nil) { - dict[@"product"] = product; - } else { - NSLog(@"Unable to find out build product"); - } - NSString* ckDeviceID = cloudKitDeviceID(); - if (ckDeviceID) { - dict[@"SFAnalyticsDeviceID"] = ckDeviceID; - dict[@"ckdeviceID"] = ckDeviceID; - } else { - NSLog(@"Unable to fetch CK device ID"); - } - - dict[@"mismatches"] = reportedMismatches; - - NSArray* events = @[dict]; - NSDictionary *wrapper = @{ - @"postTime": @([[NSDate date] timeIntervalSince1970] * 1000), - @"events": events, - }; - NSError *encodeError = nil; - NSData* post_data = [NSJSONSerialization dataWithJSONObject:wrapper options:0 error:&encodeError]; - if (post_data == nil || encodeError != nil) { - NSLog(@"failed to encode data: %@", encodeError); - return; - } - NSLog(@"logging %@, %@", wrapper, post_data); - req.HTTPBody = post_data; - dispatch_semaphore_t sem = dispatch_semaphore_create(0); - NSURLSessionDataTask *task = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - if (error != nil) { - NSLog(@"splunk upload failed: %@", error); - return; - } - NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*)response; - if (httpResp.statusCode != 200) { - NSLog(@"HTTP Post error: %@", httpResp); - } - NSLog(@"%@", httpResp); - if (data != nil) { - size_t length = [data length]; - char *buf = malloc(length); - [data getBytes:buf length:length]; - NSLog(@"%.*s", (int)length, buf); - free(buf); - } - dispatch_semaphore_signal(sem); - }]; - [task resume]; - dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); -} - -static void oneReport(void) { - NSError* error = nil; - - // From Swift.policy, policy v5 - TPPolicyDocument *tpd = [TPPolicyDocument policyDocWithHash:@"SHA256:O/ECQlWhvNlLmlDNh2+nal/yekUC87bXpV3k+6kznSo=" - data:[[NSData alloc] initWithBase64EncodedString: - @"CAUSDgoGaVBob25lEgRmdWxsEgwKBGlQYWQSBGZ1bGwSDAoEaVBvZBIEZnVsbBILCgNNYWMSBGZ1bGwSDAoEaU1hYxIEZnVsbBINCgdBcHBsZVRWEgJ0dhIOCgVXYXRjaBIFd2F0Y2gSFwoOQXVkaW9BY2Nlc3NvcnkSBWF1ZGlvGhsKDEFwcGxpY2F0aW9ucxIEZnVsbBIFd2F0Y2gaHwoQU2VjdXJlT2JqZWN0U3luYxIEZnVsbBIFd2F0Y2gaHAoNRGV2aWNlUGFpcmluZxIEZnVsbBIFd2F0Y2gaGgoLQ3JlZGl0Q2FyZHMSBGZ1bGwSBXdhdGNoGhUKBkhlYWx0aBIEZnVsbBIFd2F0Y2gaLQoTTGltaXRlZFBlZXJzQWxsb3dlZBIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxokChVQcm90ZWN0ZWRDbG91ZFN0b3JhZ2USBGZ1bGwSBXdhdGNoGhcKCEFwcGxlUGF5EgRmdWxsEgV3YXRjaBoZCgpBdXRvVW5sb2NrEgRmdWxsEgV3YXRjaBoWCgdNYW5hdGVlEgRmdWxsEgV3YXRjaBoYCglQYXNzd29yZHMSBGZ1bGwSBXdhdGNoGhUKBkVuZ3JhbRIEZnVsbBIFd2F0Y2gaHgoEV2lGaRIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxoTCgRIb21lEgRmdWxsEgV3YXRjaCIbCgVhdWRpbxIEZnVsbBIFd2F0Y2gSBWF1ZGlvIhMKBGZ1bGwSBGZ1bGwSBXdhdGNoIhUKAnR2EgRmdWxsEgV3YXRjaBICdHYiFAoFd2F0Y2gSBGZ1bGwSBXdhdGNoMiIKFgAEIhICBHZ3aHQKCl5BcHBsZVBheSQSCEFwcGxlUGF5MiYKGAAEIhQCBHZ3aHQKDF5BdXRvVW5sb2NrJBIKQXV0b1VubG9jazIeChQABCIQAgR2d2h0CgheRW5ncmFtJBIGRW5ncmFtMh4KFAAEIhACBHZ3aHQKCF5IZWFsdGgkEgZIZWFsdGgyGgoSAAQiDgIEdndodAoGXkhvbWUkEgRIb21lMiAKFQAEIhECBHZ3aHQKCV5NYW5hdGVlJBIHTWFuYXRlZTI4CiEABCIdAgR2d2h0ChVeTGltaXRlZFBlZXJzQWxsb3dlZCQSE0xpbWl0ZWRQZWVyc0FsbG93ZWQyXQpQAAISHgAEIhoCBHZ3aHQKEl5Db250aW51aXR5VW5sb2NrJBIVAAQiEQIEdndodAoJXkhvbWVLaXQkEhUABCIRAgR2d2h0CgleQXBwbGVUViQSCU5vdFN5bmNlZDIrChsABCIXAgRhZ3JwCg9eWzAtOUEtWl17MTB9XC4SDEFwcGxpY2F0aW9uczLFAQqwAQACEjQAAQoTAAQiDwIFY2xhc3MKBl5nZW5wJAobAAQiFwIEYWdycAoPXmNvbS5hcHBsZS5zYmQkEj0AAQoTAAQiDwIFY2xhc3MKBl5rZXlzJAokAAQiIAIEYWdycAoYXmNvbS5hcHBsZS5zZWN1cml0eS5zb3MkEhkABCIVAgR2d2h0Cg1eQmFja3VwQmFnVjAkEhwABCIYAgR2d2h0ChBeaUNsb3VkSWRlbnRpdHkkEhBTZWN1cmVPYmplY3RTeW5jMmMKWwACEhIABCIOAgR2d2h0CgZeV2lGaSQSQwABChMABCIPAgVjbGFzcwoGXmdlbnAkChMABCIPAgRhZ3JwCgdeYXBwbGUkChUABCIRAgRzdmNlCgleQWlyUG9ydCQSBFdpRmkynQMKgwMAAhIYAAQiFAIEdndodAoMXlBDUy1CYWNrdXAkEhoABCIWAgR2d2h0Cg5eUENTLUNsb3VkS2l0JBIYAAQiFAIEdndodAoMXlBDUy1Fc2Nyb3ckEhUABCIRAgR2d2h0CgleUENTLUZERSQSGgAEIhYCBHZ3aHQKDl5QQ1MtRmVsZHNwYXIkEhoABCIWAgR2d2h0Cg5eUENTLU1haWxEcm9wJBIaAAQiFgIEdndodAoOXlBDUy1NYWlsZHJvcCQSGwAEIhcCBHZ3aHQKD15QQ1MtTWFzdGVyS2V5JBIXAAQiEwIEdndodAoLXlBDUy1Ob3RlcyQSGAAEIhQCBHZ3aHQKDF5QQ1MtUGhvdG9zJBIZAAQiFQIEdndodAoNXlBDUy1TaGFyaW5nJBIeAAQiGgIEdndodAoSXlBDUy1pQ2xvdWRCYWNrdXAkEh0ABCIZAgR2d2h0ChFeUENTLWlDbG91ZERyaXZlJBIaAAQiFgIEdndodAoOXlBDUy1pTWVzc2FnZSQSFVByb3RlY3RlZENsb3VkU3RvcmFnZTI6CisABCInAgRhZ3JwCh9eY29tLmFwcGxlLnNhZmFyaS5jcmVkaXQtY2FyZHMkEgtDcmVkaXRDYXJkczIuCiEABCIdAgRhZ3JwChVeY29tLmFwcGxlLmNmbmV0d29yayQSCVBhc3N3b3JkczJtClwAAhIeAAQiGgIEdndodAoSXkFjY2Vzc29yeVBhaXJpbmckEhoABCIWAgR2d2h0Cg5eTmFub1JlZ2lzdHJ5JBIcAAQiGAIEdndodAoQXldhdGNoTWlncmF0aW9uJBINRGV2aWNlUGFpcmluZzIOCgIABhIIQmFja3N0b3A=" options:0]]; - - TPPolicy *policy = [tpd policyWithSecrets:@{} decrypter:nil error:&error]; - if (error != nil) { - NSLog(@"policy error: %@", error); - return; - } - if (policy == nil) { - NSLog(@"policy is nil"); - return; - } - - unsigned real_mismatches = 0; - unsigned expected_mismatches = 0; - NSMutableArray* reportedMismatches = [[NSMutableArray alloc] init]; - - NSArray* keychainClasses = @[(id)kSecClassInternetPassword, - (id)kSecClassGenericPassword, - (id)kSecClassKey, - (id)kSecClassCertificate]; - - for(NSString* itemClass in keychainClasses) { - NSDictionary *query = @{ (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecClass : (id)itemClass, - (id)kSecReturnAttributes : @YES, - (id)kSecAttrSynchronizable: @YES, - (id)kSecUseDataProtectionKeychain: @YES, - (id)kSecUseAuthenticationUI : (id)kSecUseAuthenticationUISkip, - }; - - NSArray *result; - - OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (void*)&result); - if (status) { - if (status == errSecItemNotFound) { - NSLog(@"no items found matching: %@", query); - continue; - } else { - NSLog(@"SecItemCopyMatching(%@) failed: %d", query, (int)status); - return; - } - } - - if (![result isKindOfClass:[NSArray class]]) { - NSLog(@"expected NSArray result from SecItemCopyMatching"); - return; - } - - for (id a in result) { - NSLog(@"%@", a); - NSString *oldView = getSOSView(a, itemClass); - if (oldView != nil) { - NSLog(@"old: %@", oldView); - } - - NSMutableDictionary* mutA = [a mutableCopy]; - mutA[(id)kSecClass] = (id)itemClass; - - NSString* newView = [policy mapKeyToView:mutA]; - if (newView != nil) { - NSLog(@"new: %@", newView); - } - if(oldView == nil ^ newView == nil) { - NSLog(@"real mismatch: old view (%@) != new view (%@)", oldView, newView); - ++real_mismatches; - [reportedMismatches addObject: a]; - - } else if (oldView && newView && ![oldView isEqualToString: newView]) { - if ([oldView hasPrefix:@"PCS-"] && [newView isEqualToString: @"ProtectedCloudStorage"]) { - NSLog(@"(expected PCS mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else if([oldView isEqualToString:@"OtherSyncable"] && [newView isEqualToString: @"Applications"]) { - NSLog(@"(expected 3rd party mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else if([oldView isEqualToString:@"OtherSyncable"] && [newView isEqualToString: @"Backstop"]) { - NSLog(@"(expected backstop mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else if([newView isEqualToString:@"NotSynced"]) { - NSLog(@"(expected NotSynced mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else if(([oldView isEqualToString:@"BackupBagV0"] || [oldView isEqualToString:@"iCloudIdentity"]) && [newView isEqualToString:@"SecureObjectSync"]) { - NSLog(@"(expected BackupBag - SecureObjectSync mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else if(([oldView isEqualToString:@"AccessoryPairing"] - || [oldView isEqualToString:@"NanoRegistry"] - || [oldView isEqualToString:@"WatchMigration"]) && [newView isEqualToString:@"DevicePairing"]) { - NSLog(@"(expected DevicePairing mismatch): old view (%@) != new view (%@)", oldView, newView); - ++expected_mismatches; - - } else { - NSLog(@"real mismatch: old view (%@) != new view (%@)", oldView, newView); - ++real_mismatches; - [reportedMismatches addObject: a]; - } - } - } - } - - NSLog(@"%d expected_mismatches", expected_mismatches); - NSLog(@"%d real_mismatches", real_mismatches); - reportStats(expected_mismatches, real_mismatches, reportedMismatches); -} - -static dispatch_queue_t queue; - -static void report(void); - -static void maybeReport(void) { - CFErrorRef error = NULL; - bool locked = true; - if (!SecAKSGetIsLocked(&locked, &error)) { - secerror("PolicyReporter: %@", error); - CFReleaseNull(error); - xpc_object_t options = xpc_dictionary_create(NULL, NULL, 0); - xpc_dictionary_set_uint64(options, XPC_ACTIVITY_DELAY, random() % 60); - xpc_dictionary_set_uint64(options, XPC_ACTIVITY_GRACE_PERIOD, 30); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REPEATING, false); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_ALLOW_BATTERY, true); - xpc_dictionary_set_string(options, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_UTILITY); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRE_NETWORK_CONNECTIVITY, true); -#if TARGET_OS_IPHONE - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRES_CLASS_A, true); -#endif - xpc_activity_register("com.apple.security.securityd.policy-reporting2", - options, ^(xpc_activity_t activity) { - report(); - }); - return; - } - - if (locked) { - int token = 0; - notify_register_dispatch(kUserKeybagStateChangeNotification, &token, queue, ^(int t) { - report(); - }); - return; - } - oneReport(); -} - -static void report() { - @autoreleasepool { - maybeReport(); - } -} - -void InitPolicyReporter(void) { - if (!os_feature_enabled(Security, securitydReportPolicy)) { - secnotice("securityd-PolicyReporter", "not enabled by feature flag"); - return; - } - - srandom(getpid() ^ (int)time(NULL)); - queue = dispatch_queue_create("com.apple.security.securityd_reporting", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); - xpc_object_t options = xpc_dictionary_create(NULL, NULL, 0); - xpc_dictionary_set_uint64(options, XPC_ACTIVITY_DELAY, random() % 3600); - xpc_dictionary_set_uint64(options, XPC_ACTIVITY_GRACE_PERIOD, 1800); - xpc_dictionary_set_uint64(options, XPC_ACTIVITY_INTERVAL, 3600); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REPEATING, true); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_ALLOW_BATTERY, true); - xpc_dictionary_set_string(options, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_UTILITY); - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRE_NETWORK_CONNECTIVITY, true); -#if TARGET_OS_IPHONE - xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRES_CLASS_A, true); -#endif - - xpc_activity_register("com.apple.security.securityd.policy-reporting", - options, ^(xpc_activity_t activity) { - report(); - }); -} diff --git a/OSX/sec/securityd/Regressions/SOSAccountTesting.h b/OSX/sec/securityd/Regressions/SOSAccountTesting.h deleted file mode 100644 index 37565454..00000000 --- a/OSX/sec/securityd/Regressions/SOSAccountTesting.h +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef SEC_SOSAccountTesting_h -#define SEC_SOSAccountTesting_h - -#include -#include "keychain/SecureObjectSync/SOSAccountPriv.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" -#include -#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" - -#include "SOSTestDataSource.h" -#include "SOSRegressionUtilities.h" - -#include "SOSTransportTestTransports.h" -#include "testmore.h" -#include -// -// Implicit transaction helpers -// - -static inline bool SOSAccountResetToOffering_wTxn(SOSAccount* acct, CFErrorRef* error) -{ - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); - if (!user_key) - return; - result = [acct.trust resetToOffering:txn key:user_key err:error]; - }]; - return result; -} - -static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccount* acct, CFErrorRef* error) -{ - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountJoinCirclesAfterRestore(txn, error); - }]; - return result; -} - -static inline bool SOSAccountJoinCircles_wTxn(SOSAccount* acct, CFErrorRef* error) -{ - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountJoinCircles(txn, error); - }]; - return result; -} - -static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccount* account) -{ - return SOSAccountHasCompletedInitialSync(account); -} - -static inline void SOSAccountPeerGotInSync_wTxn(SOSAccount* acct, SOSPeerInfoRef peer) -{ - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - CFMutableSetRef views = SOSPeerInfoCopyEnabledViews(peer); - SOSAccountPeerGotInSync(txn, SOSPeerInfoGetPeerID(peer), views); - CFReleaseNull(views); - }]; -} - -static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccount* acct, CFDataRef backupKey, CFErrorRef* error) -{ - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountSetBackupPublicKey(txn, backupKey, error); - }]; - return result; -} - -static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccount* acct, CFErrorRef* error) -{ - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountRemoveBackupPublickey(txn, error); - }]; - return result; -} - -static inline SOSViewResultCode SOSAccountUpdateView_wTxn(SOSAccount* acct, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error) { - __block SOSViewResultCode result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = [acct.trust updateView:acct name:viewname code:actionCode err:error]; - }]; - return result; -} - -// -// Account comparison -// - -#define kAccountsAgreeTestMin 9 -#define kAccountsAgreeTestPerPeer 1 -#define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x)) - -static void SOSAccountResetToTest(SOSAccount* a, CFStringRef accountName) { - SOSUnregisterTransportKeyParameter(a.key_transport); - SOSUnregisterTransportCircle((SOSCircleStorageTransport*)a.circle_transport); - SOSUnregisterTransportMessage((SOSMessage*)a.kvs_message_transport); - - if(key_transports) - CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(a.key_transport)); - if(message_transports){ - CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)a.kvs_message_transport); - } - if(circle_transports) - CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)a.circle_transport); - - a.circle_transport = nil; - a.key_transport = nil; - a.kvs_message_transport = nil; - - SOSAccountEnsureFactoryCirclesTest(a, accountName); -} - - -static SOSAccount* SOSAccountCreateBasicTest(CFAllocatorRef allocator, - CFStringRef accountName, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory) { - SOSAccount* a; - a = SOSAccountCreate(kCFAllocatorDefault, gestalt, factory); - - return a; -} - -static SOSAccount* SOSAccountCreateTest(CFAllocatorRef allocator, - CFStringRef accountName, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory) { - SOSAccount* a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory); - - SOSAccountResetToTest(a, accountName); - if(a) - SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); - return a; -} - -static SOSAccount* SOSAccountCreateTestFromData(CFAllocatorRef allocator, - CFDataRef data, - CFStringRef accountName, - SOSDataSourceFactoryRef factory) { - SOSAccount* a = [SOSAccount accountFromData:(__bridge NSData*) data - factory:factory - error:nil]; - if (!a) { - CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(accountName); - a = SOSAccountCreate(allocator, gestalt, factory); - CFReleaseNull(gestalt); - } - - SOSAccountResetToTest(a, accountName); - if(a) - SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); - - return a; -} - - -static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccount* account, - CFStringRef user_account, CFDataRef user_password, - CFErrorRef *error) -{ - bool success = false; - success = SOSAccountAssertUserCredentials(account, user_account, user_password, error); - require_quiet(success, done); - - success = SOSAccountGenerationSignatureUpdate(account, error); - -done: - return success; -} - - - -static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFSetRef allowed_peers) -{ - CFArrayForEach(peers, ^(const void *value) { - SOSPeerInfoRef pi = (SOSPeerInfoRef) value; - - CFErrorRef leftError = NULL; - CFErrorRef rightError = NULL; - - ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFSetContainsValue(allowed_peers, pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers); - - CFReleaseNull(leftError); - CFReleaseNull(rightError); - }); -} - -static void accounts_agree_internal(char *label, SOSAccount* left, SOSAccount* right, bool check_peers) -{ - CFErrorRef error = NULL; - { - CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error); - ok(leftPeers, "Left peers (%@) - %s", error, label); - CFReleaseNull(error); - - CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error); - ok(rightPeers, "Right peers (%@) - %s", error, label); - CFReleaseNull(error); - - ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers); - - if (check_peers) { - CFMutableSetRef allowed_identities = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - - SOSFullPeerInfoRef leftFullPeer = [left.trust CopyAccountIdentityPeerInfo]; - - if (leftFullPeer) - CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(leftFullPeer)); - CFReleaseNull(leftFullPeer); - - SOSFullPeerInfoRef rightFullPeer = [right.trust CopyAccountIdentityPeerInfo]; - - if (rightFullPeer) - CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(rightFullPeer)); - CFReleaseNull(rightFullPeer); - - unretired_peers_is_subset(label, leftPeers, allowed_identities); - - CFReleaseNull(allowed_identities); - } - - CFReleaseNull(leftPeers); - CFReleaseNull(rightPeers); - } - { - CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error); - ok(leftConcurringPeers, "Left peers (%@) - %s", error, label); - - CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error); - ok(rightConcurringPeers, "Right peers (%@) - %s", error, label); - - ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers); - - CFReleaseNull(leftConcurringPeers); - CFReleaseNull(rightConcurringPeers); - } - { - CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error); - ok(leftApplicants, "Left Applicants (%@) - %s", error, label); - - CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error); - ok(rightApplicants, "Left Applicants (%@) - %s", error, label); - - ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants); - - CFReleaseNull(leftApplicants); - CFReleaseNull(rightApplicants); - } -} - -static inline void accounts_agree(char *label, SOSAccount* left, SOSAccount* right) -{ - accounts_agree_internal(label, left, right, true); -} - - -// -// Change handling -// - -static inline CFStringRef CFArrayCopyCompactDescription(CFArrayRef array) { - if (!isArray(array)) - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), array); - - CFMutableStringRef result = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - - __block CFStringRef separator = CFSTR(""); - CFArrayForEach(array, ^(const void *value) { - CFStringAppendFormat(result, NULL, CFSTR("%@%@"), separator, value); - separator = CFSTR(","); - }); - - CFStringAppend(result, CFSTR("]")); - - CFReleaseSafe(separator); - - return result; -} - -static inline CFStringRef SOSAccountCopyName(SOSAccount* account) { - SOSPeerInfoRef pi = account.peerInfo; - - return pi ? CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerName(pi)) : CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%@"), account); -} - -static inline CFStringRef CopyChangesDescription(CFDictionaryRef changes) { - - CFStringRef pendingChanges = CFDictionaryCopyCompactDescription((CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull)); - - CFMutableStringRef peerTable = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - - __block CFStringRef separator = CFSTR(""); - - CFDictionaryForEach(changes, ^(const void *key, const void *value) { - if (CFGetTypeID(key) == SOSAccountGetTypeID()) { - CFStringRef accountName = SOSAccountCopyName((__bridge SOSAccount*)key); - CFStringRef arrayDescription = CFArrayCopyCompactDescription(value); - - CFStringAppendFormat(peerTable, NULL, CFSTR("%@%@:%@"), separator, accountName, arrayDescription); - separator = CFSTR(", "); - - CFReleaseSafe(accountName); - CFReleaseSafe(arrayDescription); - } - }); - - CFStringAppend(peerTable, CFSTR("]")); - - CFStringRef result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), pendingChanges, peerTable); - CFReleaseNull(pendingChanges); - CFReleaseNull(peerTable); - - return result; -}; - -static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFMutableDictionaryRef overlay) { - CFMutableSetRef keysToRemove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionaryForEach(overlay, ^(const void *key, const void *value) { - const void *current_value = CFDictionaryGetValue(target, key); - if (CFEqualSafe(current_value, value) || (isNull(value) && current_value == NULL)) { - CFSetAddValue(keysToRemove, key); - } else { - CFDictionarySetValue(target, key, value); - } - }); - - CFSetForEach(keysToRemove, ^(const void *value) { - CFDictionaryRemoveValue(overlay, value); - }); - - CFReleaseNull(keysToRemove); -} - -static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) { - CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) { - CFArrayAppendValue(keys, key); - }); -} - -static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccount* sender) -{ - __block bool changes_added = false; - CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary); - CFReleaseNull(emptyDictionary); - - CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues); - - CFDictionaryForEach(changesRecord, ^(const void *key, const void *value) { - if (isArray(value) && (sender == NULL || sender != key)) { - CFArrayAppendKeys((CFMutableArrayRef) value, newKeysAndValues); - if (CFDictionaryGetCount(newKeysAndValues)) - changes_added = true; - } - }); - - if (changes_added) - secnotice("changes", "Changes from %@: %@", sender, newKeysAndValues); - - CFDictionaryRemoveAllValues(newKeysAndValues); - - return changes_added; -} - -static bool FillAllChanges(CFMutableDictionaryRef changes) { - __block bool changed = false; - - CFMutableSetRef changedAccounts = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); - - CFArrayForEach(key_transports, ^(const void *value) { - CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; - if (AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt))) { - changed |= true; - CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt))); - } - SOSTransportKeyParameterTestClearChanges(tpt); - }); - CFArrayForEach(circle_transports, ^(const void *value) { - SOSCircleStorageTransportTest *tpt = (__bridge SOSCircleStorageTransportTest *) value; - if (AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], [tpt getAccount])) { - changed |= true; - CFSetAddValue(changedAccounts, (__bridge CFTypeRef)SOSTransportCircleTestGetAccount(tpt)); - } - SOSTransportCircleTestClearChanges(tpt); - }); - CFArrayForEach(message_transports, ^(const void *value) { - if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ - SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; - CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); - if (AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt))) { - changed |= true; - CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt))); - } - SOSTransportMessageTestClearChanges(tpt); - } - }); - - secnotice("process-changes", "Accounts with change (%@): %@", changed ? CFSTR("YES") : CFSTR("NO"), changedAccounts); - - CFReleaseNull(changedAccounts); - - return changed; -} - -static void FillChanges(CFMutableDictionaryRef changes, SOSAccount* forAccount) -{ - CFArrayForEach(key_transports, ^(const void *value) { - CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; - if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt)))){ - AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt)); - SOSTransportKeyParameterTestClearChanges(tpt); - } - }); - CFArrayForEach(circle_transports, ^(const void *value) { - SOSCircleStorageTransportTest* tpt = (__bridge SOSCircleStorageTransportTest*) value; - if([forAccount isEqual: SOSTransportCircleTestGetAccount(tpt)]){ - AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], SOSTransportCircleTestGetAccount(tpt)); - SOSTransportCircleTestClearChanges(tpt); - } - }); - CFArrayForEach(message_transports, ^(const void *value) { - if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ - SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; - if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt)))){ - CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); - AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt)); - SOSTransportMessageTestClearChanges(tpt); - } - } - }); - -} - -static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccount* account, ...) -{ - SOSAccount* next_account = account; - va_list argp; - va_start(argp, account); - while(next_account != NULL) { - FillChanges(changes, next_account); - next_account = va_arg(argp, SOSAccount*); - } -} - -static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary) -{ - CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - CFArrayAppendKeys(result, dictionary); - - return result; -} - -#define kFeedChangesToTestCount 1 -static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccount* acct) -{ - CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull); - - if (!isDictionary(full_list)) - return; // Nothing recorded to send! - - CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, (__bridge CFTypeRef)(acct)); - - if (!isArray(account_pending_keys)) { - account_pending_keys = CFDictionaryCopyKeys(full_list); - CFDictionaryAddValue(changes, (__bridge CFTypeRef)(acct), account_pending_keys); - CFReleaseSafe(account_pending_keys); // The dictionary keeps it, we don't retain it here. - } - - CFMutableDictionaryRef account_pending_messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayForEach(account_pending_keys, ^(const void *value) { - CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value)); - }); - - secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((CKKeyParameterTest*) acct.key_transport)); - - CFDictionaryForEach(account_pending_messages, ^(const void *key, const void *value) { - secnotice("changes", " %@", key); - }); - - if(CFDictionaryGetCount(account_pending_messages) == 0) { - CFReleaseNull(account_pending_messages); - return; - } - - __block CFMutableArrayRef handled = NULL; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - __block CFErrorRef error = NULL; - ok(handled = SOSTransportDispatchMessages(txn, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error); - CFReleaseNull(error); - }]; - - if (isArray(handled)) { - CFArrayForEach(handled, ^(const void *value) { - CFArrayRemoveAllValue(account_pending_keys, value); - }); - } - CFReleaseNull(account_pending_messages); - CFReleaseNull(handled); -} - -#define kFeedChangesToMultieTestCountPer 1 - -static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp) -{ - SOSAccount* account = NULL; - while((account = va_arg(argp, SOSAccount*)) != NULL) { - FeedChangesTo(changes, account); - } -} - -static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...) -{ - va_list argp; - va_start(argp, changes); - - FeedChangesToMultiV(changes, argp); - - va_end(argp); -} - -static inline void InjectChangeToMulti(CFMutableDictionaryRef changes, - CFStringRef changeKey, CFTypeRef changeValue, ...) -{ - CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - changeKey, changeValue, - NULL); - AddNewChanges(changes, changes_to_send, NULL); - CFReleaseNull(changes_to_send); - - va_list argp; - va_start(argp, changeValue); - FeedChangesToMultiV(changes, argp); - va_end(argp); -} - -static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp) -{ - bool result = FillAllChanges(changes); - - FeedChangesToMultiV(changes, argp); - - return result; -} - - -static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...) -{ - va_list argp; - va_start(argp, changes); - - bool result = ProcessChangesOnceV(changes, argp); - - va_end(argp); - - return result; -} - -static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...) -{ - va_list argp; - va_start(argp, changes); - - int result = 0; - bool new_data = false; - do { - va_list argp_copy; - va_copy(argp_copy, argp); - - new_data = ProcessChangesOnceV(changes, argp_copy); - - ++result; - - va_end(argp_copy); - } while (new_data); - - va_end(argp); - - return result; - -} - -// -// MARK: Account creation -// - -static CFStringRef modelFromType(SOSPeerInfoDeviceClass cls) { - switch(cls) { - case SOSPeerInfo_macOS: return CFSTR("Mac Pro"); - case SOSPeerInfo_iOS: return CFSTR("iPhone"); - case SOSPeerInfo_iCloud: return CFSTR("iCloud"); - case SOSPeerInfo_watchOS: return CFSTR("needWatchOSDeviceName"); - case SOSPeerInfo_tvOS: return CFSTR("needTVOSDeviceName"); - default: return CFSTR("GENERICOSTHING"); - } -} - -static inline SOSAccount* CreateAccountForLocalChangesWithStartingAttributes(CFStringRef name, CFStringRef data_source_name, SOSPeerInfoDeviceClass devclass, CFStringRef serial, CFBooleanRef preferIDS, CFBooleanRef preferIDSFragmentation, CFBooleanRef preferIDSACKModel, CFStringRef transportType, CFStringRef deviceID) { - - SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef ds = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds); - SOSEngineRef engine = SOSEngineCreate(ds, NULL); - ds->engine = engine; - - CFMutableDictionaryRef gestalt = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(gestalt, kPIUserDefinedDeviceNameKey, name); - CFDictionaryAddValue(gestalt, kPIDeviceModelNameKey, modelFromType(devclass)); - CFDictionaryAddValue(gestalt, kPIOSVersionKey, CFSTR("TESTRUN")); - - CFMutableDictionaryRef testV2dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(testV2dict, sSerialNumberKey, serial); - SOSAccount* result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory); - [result.trust updateV2Dictionary:result v2:testV2dict]; - - CFReleaseSafe(SOSAccountCopyUUID(result)); - - CFReleaseNull(gestalt); - CFReleaseNull(testV2dict); - - return result; -} - -static CFStringRef sGestaltTest = CFSTR("GestaltTest"); -static CFStringRef sV2Test = CFSTR("V2Test"); -static inline CFDictionaryRef SOSTestSaveStaticAccountState(SOSAccount* account) { - CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef gestalt = SOSAccountCopyGestalt(account); - CFDictionaryRef v2dictionary = SOSAccountCopyV2Dictionary(account); - CFDictionaryAddValue(retval, sGestaltTest, gestalt); - CFDictionaryAddValue(retval, sV2Test, v2dictionary); - CFReleaseNull(gestalt); - CFReleaseNull(v2dictionary); - return retval; -} - -static inline void SOSTestRestoreAccountState(SOSAccount* account, CFDictionaryRef saved) { - [account.trust updateGestalt:account newGestalt:CFDictionaryGetValue(saved, sGestaltTest)]; - [account.trust updateV2Dictionary:account v2:CFDictionaryGetValue(saved, sV2Test)]; -} - -static CFStringRef CFStringCreateRandomHexWithLength(size_t len) { - if(len%2) len++; - CFDataRef data = CFDataCreateWithRandomBytes(len/2); - CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, len); - CFStringAppendHexData(retval, data); - CFReleaseNull(data); - return retval; -} - -static inline SOSAccount* CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name) -{ - CFStringRef randomSerial = CFStringCreateRandomHexWithLength(8); - CFStringRef randomDevID = CFStringCreateRandomHexWithLength(16); - SOSAccount* retval = CreateAccountForLocalChangesWithStartingAttributes(name, data_source_name, SOSPeerInfo_iOS, randomSerial, - kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeKVS, randomDevID); - - CFReleaseNull(randomSerial); - CFReleaseNull(randomDevID); - return retval; -} - -static inline SOSAccount* CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name) -{ - SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef ds = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds); - SOSEngineRef engine = SOSEngineCreate(ds, NULL); - ds->engine = engine; - - SOSAccount* result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory); - - return result; -} - - - -static inline int countPeers(SOSAccount* account) { - CFErrorRef error = NULL; - CFArrayRef peers; - - peers = SOSAccountCopyPeers(account, &error); - if(!peers) - return 0; - int retval = (int) CFArrayGetCount(peers); - CFReleaseNull(error); - CFReleaseNull(peers); - return retval; -} - -static inline int countActivePeers(SOSAccount* account) { - CFErrorRef error = NULL; - CFArrayRef peers; - - peers = SOSAccountCopyActivePeers(account, &error); - if(!peers) - return 0; - int retval = (int) CFArrayGetCount(peers); - CFReleaseNull(error); - CFReleaseNull(peers); - return retval; -} - -static inline int countActiveValidPeers(SOSAccount* account) { - CFErrorRef error = NULL; - CFArrayRef peers; - - peers = SOSAccountCopyActiveValidPeers(account, &error); - if(!peers) - return 0; - int retval = (int) CFArrayGetCount(peers); - CFReleaseNull(error); - CFReleaseNull(peers); - return retval; -} - -static inline int countApplicants(SOSAccount* account) { - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - int retval = 0; - - if(applicants) retval = (int)CFArrayGetCount(applicants); - CFReleaseNull(error); - CFReleaseNull(applicants); - return retval; -} - - -static inline void showActiveValidPeers(SOSAccount* account) { - CFErrorRef error = NULL; - CFArrayRef peers; - - peers = SOSAccountCopyActiveValidPeers(account, &error); - CFArrayForEach(peers, ^(const void *value) { - SOSPeerInfoRef pi = (SOSPeerInfoRef) value; - ok(0, "Active Valid Peer %@", pi); - }); - CFReleaseNull(peers); -} - -#define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL - -static inline bool testAccountPersistence(SOSAccount* account) { - SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - NSError* error = nil; - - bool retval = false; - SOSAccount* reinflatedAccount = NULL; - NSData* accountDER = NULL; - - SOSAccountCheckHasBeenInSync_wTxn(account); - - // DER encode account to accountData - this allows checking discreet DER functions - size_t size = [account.trust getDEREncodedSize:account err:&error]; - error = nil; - uint8_t buffer[size]; - uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; - error = nil; - - ok_or_quit(start, "successful encoding", errOut); - ok_or_quit(start == buffer, "Used whole buffer", errOut); - - accountDER = [NSData dataWithBytes:buffer length:size]; - ok_or_quit(accountDER, "Made CFData for Account", errOut); - - - // Re-inflate to "inflated" - reinflatedAccount = [SOSAccount accountFromData:accountDER - factory:test_factory - error:&error]; - error = nil; - - ok(reinflatedAccount, "inflated"); - ok(CFEqualSafe((__bridge CFTypeRef)reinflatedAccount, (__bridge CFTypeRef)account), "Compares"); - - // Repeat through SOSAccountCopyEncodedData() interface - this is the normally called combined interface - accountDER = [account encodedData:&error]; - error = nil; - reinflatedAccount = [SOSAccount accountFromData:accountDER factory:test_factory error:&error]; - ok(reinflatedAccount, "inflated2: %@", error); - ok(CFEqual((__bridge CFTypeRef)account, (__bridge CFTypeRef)reinflatedAccount), "Compares"); - - error = nil; - retval = true; - -errOut: - return retval; -} - -static inline bool SOSTestStartCircleWithAccount(SOSAccount* account, CFMutableDictionaryRef changes, CFStringRef cfaccount, CFDataRef cfpassword) { - bool retval = false; - if(!SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, NULL)) - return retval; - is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); - if(!SOSAccountResetToOffering_wTxn(account, NULL)) - return retval; - is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); - retval = true; - - return retval; -} - -static inline bool SOSTestApproveRequest(SOSAccount* approver, CFIndex napplicants) { - bool retval = false; - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(approver, &error); - - ok(applicants && CFArrayGetCount(applicants) == napplicants, "See %ld applicant(s) %@ (%@)", napplicants, applicants, error); - CFStringRef approvername = SOSAccountCopyName(approver); - ok((retval = SOSAccountAcceptApplicants(approver, applicants, &error)), "%@ accepts (%@)", approvername, error); - CFReleaseNull(error); - CFReleaseNull(applicants); - CFReleaseNull(approvername); - - return retval; -} - -#define DROP_USERKEY true -#define KEEP_USERKEY false - -static inline bool SOSTestJoinWith(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* joiner) { - CFErrorRef error = NULL; - // retval will return op failures, not count failures - we'll still report those from in here. - bool retval = false; - - FeedChangesTo(changes, joiner); - - ok(SOSAccountAssertUserCredentialsAndUpdate(joiner, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ProcessChangesUntilNoChange(changes, joiner, NULL); - - ok(retval = SOSAccountJoinCircles_wTxn(joiner, &error), "Applying (%@)", error); - CFReleaseNull(error); - return retval; -} - -static inline bool SOSTestJoinWithApproval(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* approver, SOSAccount* joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { - //CFErrorRef error = NULL; - // retval will return op failures, not count failures - we'll still report those from in here. - bool retval = false; - - ok(retval = SOSTestJoinWith(cfpassword, cfaccount, changes, joiner), "Application Made"); - - ProcessChangesUntilNoChange(changes, approver, joiner, NULL); - - int nrounds = 2; - if(dropUserKey) SOSAccountPurgePrivateCredential(joiner); // lose the userKey so we don't "fix" the ghost problem yet. - else nrounds = 3; - - if(expectCleanup) nrounds++; - - ok(retval &= SOSTestApproveRequest(approver, 1), "Accepting Request to Join"); - ProcessChangesUntilNoChange(changes, approver, joiner, NULL); - - accounts_agree_internal("Successful join shows same circle view", joiner, approver, false); - is(countPeers(joiner), expectedCount, "There should be %d valid peers", expectedCount); - return retval; -} - - -static inline bool SOSTestChangeAccountDeviceName(SOSAccount* account, CFStringRef name) { - bool retval = false; - CFMutableDictionaryRef mygestalt = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerGetGestalt(account.peerInfo)); - require_quiet(mygestalt, retOut); - CFDictionarySetValue(mygestalt, kPIUserDefinedDeviceNameKey, name); - retval = [account.trust updateGestalt:account newGestalt:mygestalt]; -retOut: - CFReleaseNull(mygestalt); - return retval; -} - -/* - * this simulates a piggy-back join at the account level - */ - -static inline bool SOSTestJoinThroughPiggyBack(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* approver, SOSAccount* joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { - // retval will return op failures, not count failures - we'll still report those from in here. - bool retval = false; - CFErrorRef error = NULL; - - ok(SOSAccountAssertUserCredentialsAndUpdate(approver, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - // This makes sure the joiner sees the current key parameters - ProcessChangesUntilNoChange(changes, approver, joiner, NULL); - - SecKeyRef privKey = SOSAccountGetPrivateCredential(approver, &error); - ok(privKey, "got privkey from approver (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountTryUserPrivateKey(joiner, privKey, &error), "assert same credentials on joiner (%@)", error); - CFReleaseNull(error); - // This gives the joiner a chance to see the current circle - this is the account-level equivalent of the Flush added to stashAccountCredential - ProcessChangesUntilNoChange(changes, approver, joiner, NULL); - - SOSPeerInfoRef joinerPI = SOSAccountCopyApplication(joiner, &error); - ok(joinerPI, "Joiner peerinfo available as application %@", error); - CFReleaseNull(error); - - CFDataRef theBlob = SOSAccountCopyCircleJoiningBlob(approver, joinerPI, &error); - ok(theBlob, "Made a joining blob (%@)", error); - CFReleaseNull(error); - - - bool joined = SOSAccountJoinWithCircleJoiningBlob(joiner, theBlob, kPiggyV1, &error); - ok(joined, "Joiner posted circle with itself in it (%@)", error); - CFReleaseNull(error); - - CFReleaseNull(joinerPI); - CFReleaseNull(theBlob); - - is(ProcessChangesUntilNoChange(changes, approver, joiner, NULL), 2, "updates"); - - ok((retval = [joiner isInCircle:NULL]), "Joiner is in"); - - accounts_agree_internal("Successful join shows same circle view", joiner, approver, false); - is(countPeers(joiner), expectedCount, "There should be %d valid peers", expectedCount); - return retval; -} - - -static inline SOSAccount* SOSTestCreateAccountAsSerialClone(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID) { - return CreateAccountForLocalChangesWithStartingAttributes(name, CFSTR("TestSource"), devClass, serial, kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeKVS, idsID); -} - -static inline bool SOSTestMakeGhostInCircle(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID, - CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, - SOSAccount* approver, int expectedCount) { - bool retval = false; - SOSAccount* ghostAccount = SOSTestCreateAccountAsSerialClone(name, devClass, serial, idsID); - ok(ghostAccount, "Created Ghost Account"); - require_quiet(ghostAccount, retOut); - if(!ghostAccount) return false; - ok(retval = SOSTestJoinWithApproval(cfpassword, cfaccount, changes, approver, ghostAccount, DROP_USERKEY, expectedCount, true), "Ghost Joined Circle with expected result"); -retOut: - return retval; -} - -static inline void SOSTestCleanup() { - SOSUnregisterAllTransportMessages(); - SOSUnregisterAllTransportCircles(); - SOSUnregisterAllTransportKeyParameters(); - CFArrayRemoveAllValues(key_transports); - CFArrayRemoveAllValues(circle_transports); - CFArrayRemoveAllValues(message_transports); -} - - -#endif diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h deleted file mode 100644 index e702ad6f..00000000 --- a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SEC_SOSTransportTestTransports_h -#define SEC_SOSTransportTestTransports_h - -#import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" -#import "keychain/SecureObjectSync/SOSTransportMessageKVS.h" - -extern CFMutableArrayRef key_transports; -extern CFMutableArrayRef circle_transports; -extern CFMutableArrayRef message_transports; - -void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt); - -@interface CKKeyParameterTest : CKKeyParameter - -@property (nonatomic) CFMutableDictionaryRef changes; -@property (nonatomic) CFStringRef name; -@property (nonatomic) CFStringRef circleName; --(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; --(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error; --(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameter*) transport data:(CFDataRef) data err:(CFErrorRef) error; - -@end - -@interface SOSMessageKVSTest : SOSMessageKVS -@property (nonatomic) CFMutableDictionaryRef changes; -@property (nonatomic) CFStringRef name; - --(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; --(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error; --(CFIndex) SOSTransportMessageGetTransportType; --(CFStringRef) SOSTransportMessageGetCircleName; --(CFTypeRef) SOSTransportMessageGetEngine; --(SOSAccount*) SOSTransportMessageGetAccount; -@end - -@interface SOSCircleStorageTransportTest : SOSKVSCircleStorageTransport -{ - NSString *accountName; -} -@property (nonatomic) NSString *accountName; - --(id) init; --(id) initWithAccount:(SOSAccount*)account andWithAccountName:(CFStringRef)accountName andCircleName:(CFStringRef)circleName; - -bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error); -CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport); -bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName); -SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport); -void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport); -void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef accountName); -bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error); --(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates; --(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef)message_data; --(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges; -@end - -void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport); - -void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n); -CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport); -CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport); - -CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport); -CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport); -void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName); -void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport); -SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport); -SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport); -#endif diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m deleted file mode 100644 index e354c55f..00000000 --- a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m +++ /dev/null @@ -1,587 +0,0 @@ -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include "keychain/SecureObjectSync/SOSAccountPriv.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#import "keychain/SecureObjectSync/SOSTransportKeyParameter.h" -#import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" -#import "keychain/SecureObjectSync/SOSTransportMessageKVS.h" -#include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include "keychain/SecureObjectSync/SOSPeerCoder.h" -#include -#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" - -#include "SOSTransportTestTransports.h" -#include "SOSAccountTesting.h" - -CFMutableArrayRef key_transports = NULL; -CFMutableArrayRef circle_transports = NULL; -CFMutableArrayRef message_transports = NULL; - -/// -//Mark Test Key Parameter Transport -/// - -@implementation CKKeyParameterTest - --(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN -{ - self = [super init]; - if(self){ - self.name = CFRetainSafe(n); - self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - self.account = acct; - self.circleName = CFRetainSafe(cN); - - if(!key_transports) - key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(key_transports, (__bridge CFTypeRef)((CKKeyParameter*)self)); - - SOSRegisterTransportKeyParameter((CKKeyParameter*)self); - } - return self; -} - --(void)dealloc { - if(self) { - CFReleaseNull(self->_changes); - CFReleaseNull(self->_circleName); - } -} - -- (void)setChanges:(CFMutableDictionaryRef)changes -{ - CFRetainAssign(self->_changes, changes); -} - --(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameterTest*) transport data:(CFDataRef) data err:(CFErrorRef) error -{ - SOSAccount* acct = transport.account; - return SOSAccountHandleParametersChange(acct, data, &error); -} - - --(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameterTest*) transport acct:(SOSAccount*) acct -{ - - if(key_transports){ - CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(acct.key_transport)); - } - if(message_transports){ - CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.kvs_message_transport); - } - if(circle_transports) - CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)(acct.circle_transport)); - - SOSAccountSetToNew(acct); - SOSAccountResetToTest(acct, transport.name); -} - -CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport){ - return transport.name; -} - -void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName){ - transport.name = accountName; -} - -SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport){ - return ((CKKeyParameter*)transport).account; -} - -CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport){ - return transport.changes; -} - -void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport){ - transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); -} - --(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error -{ - if(!transport.changes) - transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionarySetValue(transport.changes, kSOSKVSKeyParametersKey, newParameters); - - return true; -} -@end - - -/// -//MARK: Test Circle Transport -/// -@implementation SOSCircleStorageTransportTest -@synthesize accountName = accountName; - --(id)init -{ - return [super init]; -} - -CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport){ - return (__bridge CFStringRef)(transport.accountName); -} -void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef name){ - transport.accountName = nil; - transport.accountName = (__bridge NSString *)(name); -} - --(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges -{ - return (__bridge CFMutableDictionaryRef)(self.pending_changes); -} - -void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport){ - transport.pending_changes = [NSMutableDictionary dictionary]; -} - --(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName -{ - self = [super init]; - if(self){ - self.account = acct; - self.accountName = (__bridge NSString *)(acctName); - self.circleName = (__bridge NSString*)cName; - self.pending_changes = [NSMutableDictionary dictionary]; - if(!circle_transports) - circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(circle_transports, (__bridge CFTypeRef)self); - - SOSRegisterTransportCircle((SOSCircleStorageTransportTest*)self); - } - return self; -} - --(bool) kvsRingFlushChanges:(CFErrorRef*) error -{ - return true; -} - --(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error -{ - CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); - CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; - CFDictionaryAddValue(changes, ringKey, ring); - CFReleaseNull(ringKey); - return true; -} - --(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error -{ - CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; - CFDictionaryAddValue(changes, type, debugInfo); - return true; -} - --(bool) postRetirement:(CFStringRef)cName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error -{ - CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(cName, SOSPeerInfoGetPeerID(peer)); - CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error); - - if (retirement_key) - [self testAddToChanges:retirement_key data:retirement_data]; - - CFReleaseNull(retirement_key); - CFReleaseNull(retirement_data); - return true; -} - --(bool) flushChanges:(CFErrorRef *)error -{ - return true; -} - --(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef) message_data -{ - if (self.pending_changes == NULL) { - self.pending_changes = [NSMutableDictionary dictionary]; - } - if (message_data == NULL) { - [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)(message_key)]; - } else { - [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key]; - } - secnotice("circle-changes", "Adding circle change %@ %@->%@", self.accountName, message_key, message_data); -} - --(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates -{ - if (self.pending_changes == NULL) { - self.pending_changes = [[NSMutableDictionary alloc]initWithDictionary:(__bridge NSDictionary * _Nonnull)(updates)]; - - } - else{ - CFDictionaryForEach(updates, ^(const void *key, const void *value) { - [self.pending_changes setObject:(__bridge id _Nonnull)value forKey:(__bridge id _Nonnull)key]; - }); - } -} - - --(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error -{ - bool success = true; - CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionaryForEach(retirements, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef retirees = (CFArrayRef) value; - - CFArrayForEach(retirees, ^(const void *value) { - if (isString(value)) { - CFStringRef retiree_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); - - CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); - - CFReleaseSafe(kvsKey); - } - }); - } - }); - - if(CFDictionaryGetCount(keysToWrite)) { - [self SOSTransportCircleTestAddBulkToChanges:keysToWrite]; - } - CFReleaseNull(keysToWrite); - - return success; -} - -bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error){ - CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); - if (circle_key) - [transport.pending_changes removeObjectForKey:(__bridge NSString*)circle_key]; - CFReleaseNull(circle_key); - return true; -} - --(bool) postCircle:(CFStringRef)cName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error -{ - CFStringRef circle_key = SOSCircleKeyCreateWithName(cName, error); - if (circle_key) - [self testAddToChanges:circle_key data:circle_data]; - CFReleaseNull(circle_key); - - return true; -} - --(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error -{ - return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error); -} - --(CFArrayRef)CF_RETURNS_RETAINED handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error -{ -CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { - CFErrorRef circleMessageError = NULL; - if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) { - secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); - } - else{ - CFStringRef circle_id = (CFStringRef) key; - CFArrayAppendValue(handledKeys, circle_id); - } - CFReleaseNull(circleMessageError); - }); - - return handledKeys; -} - -SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport) { - return transport.account; -} - -@end - -/// -//MARK KVS Message Test Transport -/// - - - -@implementation SOSMessageKVSTest - - --(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN -{ - self = [super init]; - if(self){ - self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL); - self.account = acct; - self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - self.name = CFRetainSafe(n); - self.circleName = (__bridge NSString*)cN; - - if(!message_transports) - message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(message_transports, (__bridge const void *)((SOSMessageKVSTest*)self)); - SOSRegisterTransportMessage((SOSMessageKVSTest*)self); - } - - return self; -} - -- (void)setChanges:(CFMutableDictionaryRef)changes -{ - CFRetainAssign(self->_changes, changes); -} - --(CFIndex) SOSTransportMessageGetTransportType -{ - return kKVSTest; -} --(CFStringRef) SOSTransportMessageGetCircleName -{ - return (__bridge CFStringRef)circleName; -} --(CFTypeRef) SOSTransportMessageGetEngine -{ - return engine; -} --(SOSAccount*) SOSTransportMessageGetAccount -{ - return self.account; -} - -void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n) -{ - transport.name = n; -} - -CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport) -{ - return transport.name; -} - -CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport) -{ - return transport.changes; -} - -void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport) -{ - transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); -} - -static void SOSTransportMessageTestAddBulkToChanges(SOSMessageKVSTest* transport, CFDictionaryRef updates) -{ -#ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why. - if (transport.changes == NULL) { - transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); - } - else{ - CFDictionaryForEach(updates, ^(const void *key, const void *value) { - CFDictionarySetValue(transport.changes, key, value); - }); - } -#endif // __clang_analyzer__ -} - -static void SOSTransportMessageTestAddToChanges(SOSMessageKVSTest* transport, CFStringRef message_key, CFDataRef message_data) -{ - if (transport.changes == NULL) { - transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - } - if (message_data == NULL) { - CFDictionarySetValue(transport.changes, message_key, kCFNull); - } else { - CFDictionarySetValue(transport.changes, message_key, message_data); - } -} - --(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageKVSTest*) transport peers:(CFDictionaryRef)circle_to_peer_ids err:(CFErrorRef*) error -{ - if(!transport.engine) - return true; - CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)transport.engine); - - CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; - - CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { - if (isString(value)) { - CFStringRef cleanup_id = (CFStringRef) value; - // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers - if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { - if (isString(value)) { - CFStringRef in_circle_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); - SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - - kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); - SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - } - }); - - } - }); - } - }); - - return [transport SOSTransportMessageFlushChanges:transport err:error]; - return true; -} - -static bool sendToPeer(SOSMessageKVSTest* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { - bool result = true; - NSString* myID = transport.account.peerID; - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSMessage*)transport, (__bridge CFStringRef) myID, peerID); - CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); - - SOSTransportMessageTestAddBulkToChanges(transport, a_message_to_a_peer); - CFReleaseNull(a_message_to_a_peer); - CFReleaseNull(message_to_peer_key); - - return result; -} - --(bool) SOSTransportMessageSyncWithPeers:(SOSMessageKVSTest*) transport p:(CFSetRef) peers err:(CFErrorRef *)error -{ - // Each entry is keyed by circle name and contains a list of peerIDs - - __block bool result = true; - - CFSetForEach(peers, ^(const void *value) { - CFStringRef peerID = asString(value, NULL); - - if (peerID) { - SOSEngineWithPeerID((SOSEngineRef)transport.engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { - SOSEnginePeerMessageSentCallback* sentCallback = NULL; - CFDataRef message_to_send = NULL; - bool ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peerID, false, &sentCallback, error); - if (message_to_send) { - CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL); - CFDictionarySetValue(SOSTransportMessageKVSTestGetChanges(transport), (__bridge CFStringRef)self->circleName, peer_dict); - SOSEngineMessageCallCallback(sentCallback, ok); - CFReleaseSafe(peer_dict); - } - - SOSEngineFreeMessageCallback(sentCallback); - CFReleaseSafe(message_to_send); - }); - } - }); - return result; -} - --(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error -{ - __block bool result = true; - - CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { - if (isString(key) && isData(value)) { - CFStringRef peerID = (CFStringRef) key; - CFDataRef message = (CFDataRef) value; - bool rx = sendToPeer(transport, (__bridge CFStringRef)transport->circleName, peerID, message, error); - result &= rx; - } - }); - - return result; -} - --(bool) SOSTransportMessageFlushChanges:(SOSMessageKVSTest*) transport err:(CFErrorRef *)error -{ - return true; -} - -SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport) { - return transport.account; -} -@end - - -void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt){ - CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey); - - SOSTransportKeyParameterTestSetName((CKKeyParameterTest*)account.key_transport, new_name); - SOSTransportCircleTestSetName((SOSCircleStorageTransportTest*)account.circle_transport, new_name); - SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name); -} - -static CF_RETURNS_RETAINED SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName) -{ - CFErrorRef localError = NULL; - SOSAccountTrustClassic *trust = a.trust; - - SOSCircleRef circle = CFRetainSafe([a.trust getCircle:&localError]); - if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){ - secnotice("circle", "Error retrieving the circle: %@", localError); - CFReleaseNull(localError); - CFReleaseNull(circle); - - circle = SOSCircleCreate(kCFAllocatorDefault, name, &localError); - if (circle){ - [trust setTrustedCircle:circle]; - } - else{ - secnotice("circle", "Could not create circle: %@", localError); - } - CFReleaseNull(localError); - } - - if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError]) - { - secnotice("circle", "had an error building full peer: %@", localError); - CFReleaseNull(localError); - return circle; - } - - CFReleaseNull(localError); - return circle; -} - -bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName) -{ - bool result = false; - if (a) - { - if(!a.factory) - return result; - CFStringRef circle_name = SOSDataSourceFactoryCopyName(a.factory); - if(!circle_name) - return result; - CFReleaseSafe(SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName)); - - CFReleaseNull(circle_name); - result = true; - } - return result; -} - -bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){ - bool success = false; - - if(account.key_transport == nil){ - account.key_transport = (CKKeyParameter*)[[CKKeyParameterTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; - require_quiet(account.key_transport, fail); - } - - if(account.circle_transport == nil){ - account.circle_transport = (SOSKVSCircleStorageTransport*)[[SOSCircleStorageTransportTest alloc] initWithAccount:account andWithAccountName:accountName andCircleName:circleName]; - require_quiet(account.circle_transport, fail); - } - if(account.kvs_message_transport == nil){ - account.kvs_message_transport = (SOSMessageKVS*)[[SOSMessageKVSTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; - } - - success = true; -fail: - return success; -} - - diff --git a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c b/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c deleted file mode 100644 index ae4e9877..00000000 --- a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "SecdTestKeychainUtilities.h" - -#include -#include -#include -#include -#include - - -#include - -//#include -#include -#include -#include - -void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_in_reset) -{ - CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random()); - CFStringRef keychain_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@Library/Keychains"), tmp_dir); - - CFStringPerformWithCString(keychain_dir, ^(const char *keychain_dir_string) { - errno_t err = mkpath_np(keychain_dir_string, 0755); - ok(err == 0 || err == EEXIST, "Create temp dir %s (%d)", keychain_dir_string, err); - }); - - - /* set custom keychain dir, reset db */ - SetCustomHomeURLString(tmp_dir); - - SecKeychainDbReset(do_in_reset); - - CFReleaseNull(tmp_dir); - CFReleaseNull(keychain_dir); -} - -CFStringRef kTestView1 = CFSTR("TestView1"); -CFStringRef kTestView2 = CFSTR("TestView2"); - -void secd_test_setup_testviews(void) { - CFMutableSetRef testViews = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetAddValue(testViews, kTestView1); - CFSetAddValue(testViews, kTestView2); - - SOSViewsSetTestViewsSet(testViews); - CFReleaseNull(testViews); -} - -void secd_test_clear_testviews(void) { - SOSViewsSetTestViewsSet(NULL); -} - - diff --git a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h b/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h deleted file mode 100644 index e11ed683..00000000 --- a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef _SECDTESTKEYCHAINUTILITIES_ -#define _SECDTESTKEYCHAINUTILITIES_ - -#include -#include - -#define kSecdTestSetupTestCount 1 -void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_before_reset); - -extern CFStringRef kTestView1; -extern CFStringRef kTestView2; - -void secd_test_setup_testviews(void); -void secd_test_clear_testviews(void); - -#endif diff --git a/OSX/sec/securityd/Regressions/ios6_1_keychain_2_db.h b/OSX/sec/securityd/Regressions/ios6_1_keychain_2_db.h deleted file mode 100644 index a4eec207..00000000 --- a/OSX/sec/securityd/Regressions/ios6_1_keychain_2_db.h +++ /dev/null @@ -1,10586 +0,0 @@ -unsigned char ios6_1_keychain_2_db[] = { - 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x20, 0x33, 0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x40, 0x20, 0x20, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, - 0x00, 0x2d, 0xe2, 0x25, 0x0d, 0x0f, 0xfc, 0x00, 0x17, 0x04, 0x99, 0x00, - 0x0e, 0x72, 0x0f, 0xd3, 0x0e, 0x20, 0x0b, 0xed, 0x0d, 0xf7, 0x0a, 0x89, - 0x0b, 0xc4, 0x07, 0xa8, 0x0a, 0x60, 0x07, 0x64, 0x07, 0x2d, 0x06, 0xf6, - 0x06, 0xbf, 0x06, 0x88, 0x06, 0x51, 0x06, 0x1a, 0x05, 0xe3, 0x05, 0xac, - 0x05, 0x75, 0x05, 0x3e, 0x05, 0x07, 0x04, 0xd0, 0x04, 0x99, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x35, 0x17, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x18, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, - 0x20, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, - 0x79, 0x73, 0x28, 0x75, 0x6e, 0x77, 0x70, 0x29, 0x35, 0x16, 0x06, 0x17, - 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x77, 0x72, - 0x61, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x17, 0x43, 0x52, 0x45, 0x41, 0x54, - 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x77, 0x72, 0x61, - 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x77, 0x72, - 0x61, 0x70, 0x29, 0x35, 0x15, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x69, 0x76, 0x72, 0x66, 0x79, 0x6b, 0x65, 0x79, - 0x73, 0x16, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, - 0x45, 0x58, 0x20, 0x69, 0x76, 0x72, 0x66, 0x79, 0x20, 0x4f, 0x4e, 0x20, - 0x6b, 0x65, 0x79, 0x73, 0x28, 0x76, 0x72, 0x66, 0x79, 0x29, 0x35, 0x14, - 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, - 0x73, 0x69, 0x67, 0x6e, 0x6b, 0x65, 0x79, 0x73, 0x15, 0x43, 0x52, 0x45, - 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, - 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, - 0x73, 0x69, 0x67, 0x6e, 0x29, 0x35, 0x13, 0x06, 0x17, 0x17, 0x15, 0x01, - 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, 0x72, 0x76, 0x65, 0x6b, - 0x65, 0x79, 0x73, 0x14, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, - 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x72, 0x76, 0x65, 0x20, 0x4f, - 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, 0x72, 0x76, 0x65, 0x29, - 0x35, 0x12, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x69, 0x64, 0x65, 0x63, 0x72, 0x6b, 0x65, 0x79, 0x73, 0x13, 0x43, - 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, - 0x69, 0x64, 0x65, 0x63, 0x72, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, - 0x73, 0x28, 0x64, 0x65, 0x63, 0x72, 0x29, 0x35, 0x11, 0x06, 0x17, 0x17, - 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x65, 0x6e, 0x63, - 0x72, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, - 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x65, 0x6e, 0x63, 0x72, - 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x65, 0x6e, 0x63, - 0x72, 0x29, 0x35, 0x10, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x6b, 0x65, 0x79, 0x73, - 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, - 0x58, 0x20, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x4f, 0x4e, 0x20, 0x6b, - 0x65, 0x79, 0x73, 0x28, 0x6b, 0x6c, 0x62, 0x6c, 0x29, 0x35, 0x0f, 0x06, - 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x6b, - 0x63, 0x6c, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x10, 0x43, 0x52, 0x45, 0x41, - 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x6b, 0x63, - 0x6c, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6b, - 0x63, 0x6c, 0x73, 0x29, 0x35, 0x0e, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x70, 0x6b, 0x68, 0x68, 0x63, 0x65, - 0x72, 0x74, 0x0f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, - 0x44, 0x45, 0x58, 0x20, 0x69, 0x70, 0x6b, 0x68, 0x68, 0x20, 0x4f, 0x4e, - 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x70, 0x6b, 0x68, 0x68, 0x29, 0x35, - 0x0d, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x69, 0x73, 0x6b, 0x69, 0x64, 0x63, 0x65, 0x72, 0x74, 0x0e, 0x43, 0x52, - 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, - 0x73, 0x6b, 0x69, 0x64, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, - 0x28, 0x73, 0x6b, 0x69, 0x64, 0x29, 0x35, 0x0c, 0x06, 0x17, 0x17, 0x15, - 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x73, 0x75, 0x62, 0x6a, - 0x63, 0x65, 0x72, 0x74, 0x0d, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, - 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, 0x75, 0x62, 0x6a, 0x20, - 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x75, 0x62, 0x6a, - 0x29, 0x35, 0x0b, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x63, 0x65, 0x72, 0x74, 0x0c, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, - 0x20, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, - 0x72, 0x74, 0x28, 0x61, 0x6c, 0x69, 0x73, 0x29, 0x42, 0x0a, 0x06, 0x17, - 0x1d, 0x1d, 0x01, 0x59, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x0b, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, - 0x4c, 0x45, 0x20, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x28, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x29, 0x85, 0x35, 0x08, 0x07, 0x17, 0x15, 0x15, 0x01, - 0x8a, 0x4d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x6b, - 0x65, 0x79, 0x73, 0x09, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, - 0x41, 0x42, 0x4c, 0x45, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x72, 0x6f, - 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, - 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, - 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, - 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, - 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6b, 0x63, - 0x6c, 0x73, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, - 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, - 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, - 0x42, 0x2c, 0x70, 0x65, 0x72, 0x6d, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x2c, 0x70, 0x72, 0x69, 0x76, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x2c, 0x6d, 0x6f, 0x64, 0x69, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, - 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x61, - 0x74, 0x61, 0x67, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, - 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, - 0x54, 0x20, 0x27, 0x27, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, - 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, - 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x62, 0x73, 0x69, - 0x7a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, - 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, - 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, - 0x2c, 0x73, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, 0x4e, - 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, - 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x20, 0x52, - 0x45, 0x41, 0x4c, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, - 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, - 0x65, 0x6e, 0x73, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x61, 0x73, 0x65, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, - 0x2c, 0x65, 0x78, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x2c, 0x6e, 0x65, 0x78, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x2c, 0x65, 0x6e, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x2c, 0x64, 0x65, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x64, 0x72, 0x76, 0x65, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x72, 0x66, 0x79, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x6e, 0x72, 0x63, - 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x79, 0x72, - 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x77, 0x72, - 0x61, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x75, - 0x6e, 0x77, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, - 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, - 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, - 0x28, 0x6b, 0x63, 0x6c, 0x73, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x2c, 0x61, - 0x74, 0x61, 0x67, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x2c, 0x74, 0x79, 0x70, - 0x65, 0x2c, 0x62, 0x73, 0x69, 0x7a, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x2c, - 0x73, 0x64, 0x61, 0x74, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x2c, 0x61, 0x67, - 0x72, 0x70, 0x29, 0x29, 0x27, 0x09, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, - 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6b, 0x65, - 0x79, 0x73, 0x5f, 0x31, 0x6b, 0x65, 0x79, 0x73, 0x0a, 0x82, 0x38, 0x06, - 0x07, 0x17, 0x15, 0x15, 0x01, 0x84, 0x53, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x63, 0x65, 0x72, 0x74, 0x63, 0x65, 0x72, 0x74, 0x07, 0x43, 0x52, 0x45, - 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x63, 0x65, - 0x72, 0x74, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, - 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, - 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, - 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, - 0x41, 0x4c, 0x2c, 0x63, 0x74, 0x79, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, - 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x63, - 0x65, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, - 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x73, 0x75, 0x62, 0x6a, - 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x73, 0x73, 0x72, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, - 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, - 0x73, 0x6c, 0x6e, 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, - 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x6b, 0x69, 0x64, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x6b, 0x68, 0x68, 0x20, 0x42, 0x4c, 0x4f, - 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, - 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, - 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, - 0x55, 0x45, 0x28, 0x63, 0x74, 0x79, 0x70, 0x2c, 0x69, 0x73, 0x73, 0x72, - 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, - 0x27, 0x07, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x31, - 0x63, 0x65, 0x72, 0x74, 0x08, 0x84, 0x07, 0x04, 0x07, 0x17, 0x15, 0x15, - 0x01, 0x87, 0x71, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x74, - 0x69, 0x6e, 0x65, 0x74, 0x05, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, - 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x28, 0x72, - 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, - 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, - 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, - 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, - 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, - 0x65, 0x73, 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, - 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, - 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, - 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, - 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, - 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, - 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, - 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, - 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, - 0x2c, 0x73, 0x64, 0x6d, 0x6e, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, - 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, - 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, - 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, - 0x2c, 0x70, 0x74, 0x63, 0x6c, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x61, 0x74, 0x79, - 0x70, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x27, 0x27, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, - 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x70, - 0x61, 0x74, 0x68, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, - 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, - 0x54, 0x20, 0x27, 0x27, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, - 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, - 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, - 0x64, 0x6d, 0x6e, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x2c, 0x70, 0x74, 0x63, - 0x6c, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x2c, - 0x70, 0x61, 0x74, 0x68, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, 0x27, - 0x05, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x65, 0x74, 0x5f, 0x31, 0x69, - 0x6e, 0x65, 0x74, 0x06, 0x50, 0x03, 0x06, 0x17, 0x2b, 0x2b, 0x01, 0x59, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, - 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x71, 0x6c, 0x69, - 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x04, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, - 0x20, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x73, 0x65, - 0x71, 0x29, 0x82, 0x5e, 0x01, 0x07, 0x17, 0x15, 0x15, 0x01, 0x85, 0x1f, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x67, 0x65, 0x6e, 0x70, 0x67, 0x65, 0x6e, - 0x70, 0x02, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, - 0x4c, 0x45, 0x20, 0x67, 0x65, 0x6e, 0x70, 0x28, 0x72, 0x6f, 0x77, 0x69, - 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, - 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, - 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, - 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, - 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, 0x65, 0x73, 0x63, - 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, 0x74, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, 0x70, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, 0x42, 0x4c, 0x4f, - 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x76, - 0x63, 0x65, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, - 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, - 0x20, 0x27, 0x27, 0x2c, 0x67, 0x65, 0x6e, 0x61, 0x20, 0x42, 0x4c, 0x4f, - 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, - 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, - 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, - 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, 0x76, 0x63, 0x65, - 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, 0x27, 0x02, 0x06, 0x17, 0x3b, - 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, - 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x67, 0x65, 0x6e, 0x70, 0x5f, 0x31, 0x67, 0x65, 0x6e, 0x70, 0x03, - 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xfb, 0x00, - 0x00, 0x00, 0x00, 0x1a, 0x0f, 0xfb, 0x0f, 0xf6, 0x04, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x55, 0x07, - 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, - 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, - 0xaa, 0x7a, 0x0b, 0x66, 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, - 0x95, 0x22, 0xa7, 0xe3, 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, - 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, - 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, - 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, - 0x7c, 0xa5, 0xb2, 0x07, 0xf2, 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, - 0xc7, 0x85, 0xd2, 0x16, 0x2f, 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, - 0xbd, 0x3d, 0xd9, 0xc4, 0x98, 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, - 0x20, 0x7b, 0x97, 0xca, 0xe6, 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, - 0xc9, 0x46, 0x27, 0xd4, 0x4f, 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, - 0x3c, 0x4e, 0x8e, 0x37, 0x6e, 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, - 0x17, 0xdb, 0xd1, 0x96, 0xb9, 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, - 0xbf, 0x42, 0x46, 0xfc, 0x1c, 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, - 0x4c, 0x84, 0xde, 0x41, 0x9f, 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, - 0x9c, 0x59, 0xd6, 0xcf, 0xcd, 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, - 0x3b, 0x02, 0xcc, 0x1a, 0xed, 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, - 0x39, 0xa5, 0x82, 0x12, 0x04, 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, - 0xc0, 0x8d, 0xdb, 0xff, 0x46, 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, - 0x5e, 0xc1, 0xa3, 0xca, 0xd4, 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, - 0x22, 0xbf, 0xf6, 0x5a, 0xe6, 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, - 0xba, 0x8b, 0xd2, 0x39, 0x49, 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, - 0xdc, 0x0d, 0x73, 0x1b, 0xe6, 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, - 0x4b, 0x79, 0x8c, 0x23, 0x8d, 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, - 0x3f, 0x09, 0xec, 0xf3, 0xa8, 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, - 0x37, 0xc0, 0x2a, 0x7d, 0x25, 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, - 0x14, 0xd0, 0xa8, 0x1e, 0x2a, 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, - 0xa3, 0xb2, 0xee, 0x83, 0x36, 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, - 0x64, 0xb4, 0x07, 0x7c, 0x3d, 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, - 0x91, 0xf4, 0x32, 0xa8, 0xf1, 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, - 0x78, 0xca, 0xa4, 0x0c, 0xf8, 0x40, 0x9f, 0x86, 0xd9, 0x16, 0x56, 0x67, - 0x74, 0xd4, 0x33, 0x9e, 0xb7, 0xef, 0xa6, 0xdf, 0x32, 0xb2, 0x24, 0x20, - 0xe7, 0xe9, 0x80, 0xdf, 0x7b, 0xa3, 0x49, 0x04, 0xd7, 0x3f, 0x9f, 0xbe, - 0xa6, 0x2d, 0xd0, 0xec, 0xed, 0x04, 0x76, 0xc9, 0x38, 0x0b, 0x2c, 0x02, - 0xcc, 0xd0, 0x98, 0x02, 0x73, 0x96, 0x6b, 0x8b, 0xcb, 0x2b, 0x57, 0x2d, - 0xab, 0x0d, 0x5e, 0x97, 0xb8, 0xd9, 0x81, 0xa6, 0x09, 0x7c, 0x6a, 0x6a, - 0xbe, 0xed, 0x44, 0xe1, 0x87, 0x2a, 0xbd, 0xad, 0x61, 0xfa, 0xdc, 0x76, - 0xaa, 0xa5, 0xfd, 0x40, 0xee, 0x9f, 0xf1, 0xc6, 0x74, 0xe9, 0xba, 0xc1, - 0xaf, 0xf1, 0x5d, 0x16, 0x06, 0x27, 0x60, 0x2b, 0x96, 0x9d, 0x0d, 0xc1, - 0x7c, 0xc3, 0x7b, 0xfd, 0x33, 0xc2, 0xa6, 0x7c, 0xbc, 0xc3, 0x1c, 0xef, - 0x9d, 0xf4, 0xe2, 0x8c, 0x2d, 0xe3, 0x01, 0xc1, 0x95, 0x24, 0x66, 0x15, - 0x1a, 0xa1, 0xa0, 0x61, 0x28, 0x8f, 0x44, 0x77, 0x80, 0xfc, 0x11, 0xce, - 0xad, 0xe1, 0xf1, 0xe9, 0x80, 0x55, 0x6d, 0x77, 0x5d, 0xf7, 0x2a, 0xf8, - 0x15, 0x42, 0xdd, 0xf6, 0x62, 0xac, 0x68, 0x8f, 0xaa, 0x85, 0xd8, 0xfa, - 0xc6, 0x21, 0xe9, 0xa8, 0xa2, 0x1e, 0xe3, 0xd4, 0x32, 0x3e, 0xee, 0xec, - 0x96, 0x54, 0xe1, 0xb1, 0x8f, 0x64, 0x59, 0xc6, 0x49, 0x01, 0x3c, 0xc0, - 0x17, 0xa9, 0xf5, 0xf2, 0x6f, 0x8a, 0xec, 0x9b, 0x66, 0xa7, 0x1d, 0x98, - 0xff, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x84, 0x07, 0x06, - 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x86, 0x46, 0x17, 0x13, 0x41, 0xb7, - 0x59, 0x5c, 0x54, 0xdd, 0xc7, 0x58, 0x41, 0xb7, 0x59, 0x5c, 0x54, 0xdd, - 0xc7, 0x58, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, - 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, 0x0e, - 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, 0x36, - 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x1c, 0x32, 0x04, 0xe7, 0x79, 0xe1, - 0xe0, 0x05, 0x0b, 0xa0, 0xe7, 0xb9, 0xe1, 0x92, 0xbb, 0xa8, 0xae, 0xca, - 0xff, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x99, 0x02, 0x2d, 0xc5, 0xee, 0x94, 0x76, 0x6c, 0x0a, 0xe2, - 0xa1, 0xb1, 0x7a, 0x6d, 0x0c, 0xbf, 0x9d, 0xa2, 0x60, 0xdc, 0xb9, 0xf4, - 0xf9, 0x4e, 0x6f, 0x61, 0x37, 0x18, 0x86, 0xbf, 0xef, 0xe9, 0x55, 0x9e, - 0x44, 0x75, 0x32, 0x4c, 0x20, 0x82, 0xb5, 0x3d, 0x42, 0x72, 0x35, 0x69, - 0xba, 0x22, 0x95, 0x0c, 0xec, 0x46, 0xe8, 0x5b, 0x62, 0xe2, 0x07, 0xd4, - 0x80, 0x99, 0xc1, 0x83, 0x12, 0x3f, 0xcc, 0xd4, 0xf6, 0xcd, 0xc2, 0xb2, - 0xcd, 0x4d, 0x94, 0x4c, 0xab, 0x05, 0x48, 0x0c, 0x09, 0xe1, 0x82, 0x1a, - 0x6c, 0x0a, 0xf5, 0x16, 0x06, 0x57, 0x23, 0x9e, 0x18, 0xe8, 0xd9, 0xbb, - 0x4a, 0x8a, 0xcd, 0x69, 0xed, 0xc3, 0xae, 0x71, 0xe8, 0x8f, 0xeb, 0xb5, - 0x76, 0x50, 0xca, 0xb5, 0x69, 0x05, 0xdc, 0x93, 0x5b, 0x49, 0xed, 0xa3, - 0xf8, 0x25, 0xfe, 0x6a, 0x83, 0x6f, 0x16, 0x1e, 0xef, 0x5b, 0xfd, 0x24, - 0x7f, 0x9f, 0x66, 0xf1, 0x65, 0x8c, 0x38, 0x43, 0xd1, 0xbc, 0x13, 0x14, - 0x45, 0x75, 0x66, 0x3b, 0xd7, 0xe1, 0x7a, 0xde, 0xb1, 0xf6, 0x27, 0xd6, - 0x3e, 0xf6, 0x44, 0x7d, 0xf3, 0x3e, 0xd2, 0x95, 0x49, 0xe5, 0x31, 0x6f, - 0x38, 0x95, 0xd0, 0x78, 0xc8, 0xca, 0x68, 0xaf, 0xec, 0xab, 0x1e, 0xcf, - 0x0c, 0xff, 0x3e, 0xc4, 0x12, 0x3e, 0x48, 0xb4, 0x7e, 0x70, 0xc6, 0xa0, - 0x9b, 0xf8, 0x80, 0x30, 0x75, 0x25, 0x1a, 0xf1, 0xdf, 0x3a, 0x37, 0xa1, - 0xac, 0x43, 0x5b, 0xa0, 0xae, 0x9b, 0x91, 0xb3, 0x4a, 0xfa, 0x5f, 0x4b, - 0xf1, 0xba, 0xcd, 0x41, 0x92, 0x38, 0x6a, 0x8d, 0x69, 0x9e, 0xd3, 0x09, - 0xaa, 0x4c, 0xb2, 0x60, 0xcf, 0xff, 0x37, 0xed, 0xa0, 0x39, 0x36, 0x03, - 0x1a, 0x6a, 0xb7, 0xed, 0xce, 0xc8, 0x4e, 0x46, 0xb1, 0x82, 0xfb, 0xe1, - 0x46, 0x2d, 0x12, 0xf4, 0x8a, 0x6c, 0x38, 0x5c, 0x6b, 0xaa, 0x05, 0xf1, - 0xc0, 0xf2, 0x14, 0x8d, 0x3e, 0xdc, 0xec, 0x04, 0x0c, 0x94, 0xe3, 0xbf, - 0x3b, 0x7b, 0x3f, 0xa2, 0x88, 0x98, 0xe6, 0x0c, 0x5f, 0x23, 0x6d, 0x0b, - 0x6f, 0x8e, 0xe9, 0xce, 0xc0, 0xe2, 0x3e, 0xc7, 0xcd, 0xa0, 0x7b, 0xda, - 0xf1, 0x26, 0xfd, 0x3d, 0xc6, 0xe7, 0xe8, 0xed, 0x9d, 0xeb, 0x74, 0xc5, - 0x14, 0x5c, 0xee, 0xcd, 0x4d, 0xc4, 0x4e, 0x1b, 0x2d, 0x09, 0xf4, 0x7b, - 0xdb, 0xf6, 0x96, 0x17, 0x17, 0xd1, 0x16, 0xd5, 0xea, 0xaf, 0x4f, 0x7b, - 0xc2, 0x1e, 0x0f, 0xe1, 0x2c, 0xd8, 0x26, 0xe1, 0xcc, 0x66, 0x64, 0xd1, - 0x3f, 0xd9, 0x16, 0x99, 0x0c, 0xb1, 0x11, 0xc2, 0x13, 0xe5, 0xab, 0x99, - 0x2a, 0x6f, 0x09, 0x37, 0xc5, 0x7c, 0x8e, 0xb8, 0x04, 0x73, 0x3b, 0x0b, - 0x58, 0x87, 0x10, 0x33, 0x1f, 0x5d, 0xea, 0xe9, 0xcd, 0x4e, 0x5b, 0x33, - 0x88, 0xc2, 0x9c, 0x01, 0x1a, 0xe6, 0x92, 0x57, 0xf9, 0xa8, 0x7d, 0x03, - 0x76, 0x79, 0x4e, 0x1e, 0x25, 0xe8, 0xae, 0x61, 0x70, 0x70, 0x6c, 0x65, - 0x64, 0x6b, 0x75, 0x83, 0x0b, 0x05, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, - 0x84, 0x3c, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, 0x6b, - 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, 0x6b, 0x65, 0x6d, 0xb0, 0x14, - 0x83, 0xdf, 0x17, 0xb6, 0x73, 0x59, 0x09, 0xd6, 0x8a, 0xed, 0x02, 0x13, - 0x5a, 0x8b, 0xd4, 0x99, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, - 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, - 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, 0x59, 0x31, 0xba, 0xaa, 0x89, - 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, 0x60, 0x02, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xdc, 0x97, 0xef, 0xa5, - 0xc0, 0xbc, 0x15, 0x38, 0x95, 0x35, 0x74, 0x61, 0x34, 0x68, 0xb9, 0x5c, - 0xef, 0x21, 0xad, 0xeb, 0xc9, 0x50, 0x73, 0xed, 0x31, 0x38, 0x33, 0x44, - 0x03, 0x44, 0x16, 0xaf, 0xa2, 0xba, 0x34, 0x58, 0x3f, 0x49, 0xaf, 0x93, - 0xf8, 0xe4, 0x6e, 0x6f, 0x7f, 0x23, 0x05, 0x46, 0x75, 0x49, 0xdf, 0x84, - 0xad, 0x64, 0x83, 0x11, 0x43, 0xd9, 0x80, 0x11, 0x93, 0x6d, 0xcf, 0xb4, - 0x72, 0x42, 0xc2, 0x5a, 0x78, 0x57, 0x37, 0x2d, 0x9e, 0x9a, 0x3e, 0x30, - 0x9b, 0x72, 0x7b, 0xfa, 0x1d, 0x9e, 0x2d, 0x53, 0x16, 0x85, 0x91, 0x3c, - 0xe9, 0xf1, 0x39, 0x60, 0x1d, 0x9e, 0xc6, 0xee, 0xb1, 0xdc, 0xb1, 0x0d, - 0xb8, 0x23, 0x68, 0xbf, 0xe5, 0x08, 0xc4, 0xac, 0x31, 0x4e, 0x2d, 0x0f, - 0x1f, 0xe1, 0xb3, 0xfe, 0xd2, 0x31, 0x4a, 0x52, 0x3e, 0x03, 0xe1, 0x1a, - 0x66, 0x58, 0x8b, 0x56, 0x99, 0x55, 0x7f, 0x6f, 0x5a, 0xa9, 0x8f, 0xcf, - 0xb3, 0x03, 0x96, 0x79, 0xb0, 0x6c, 0x67, 0x60, 0x35, 0xce, 0x8d, 0xc6, - 0x1c, 0x70, 0x05, 0xa4, 0x5e, 0x4f, 0x83, 0x4f, 0x1a, 0x98, 0x88, 0xdd, - 0x5a, 0x5d, 0xb3, 0x9b, 0xf6, 0xb2, 0xa3, 0x2e, 0x1c, 0x41, 0x81, 0x97, - 0xef, 0x16, 0xb3, 0x8e, 0xbe, 0x09, 0x08, 0x3d, 0x47, 0xaa, 0x2b, 0x90, - 0x61, 0xc7, 0x67, 0xcb, 0x0d, 0xa5, 0x7a, 0x58, 0x4d, 0xa7, 0x9f, 0xd4, - 0x21, 0xf2, 0x47, 0x65, 0x3b, 0x9e, 0x3b, 0xa4, 0xb4, 0x15, 0x05, 0x10, - 0xee, 0x90, 0xe5, 0xd9, 0x2e, 0xa0, 0xfe, 0x85, 0x9c, 0xad, 0x37, 0x71, - 0x51, 0xba, 0x0e, 0x91, 0x48, 0x3e, 0x54, 0xa0, 0x10, 0x1b, 0xc7, 0xff, - 0x4b, 0xd2, 0x24, 0xf8, 0x37, 0xd9, 0xc3, 0x17, 0x12, 0x05, 0x28, 0xbe, - 0xeb, 0xf5, 0xa3, 0x5a, 0x93, 0x7b, 0x9e, 0x59, 0xb2, 0x63, 0xbc, 0x71, - 0x61, 0x6a, 0x5a, 0x6c, 0xbd, 0xae, 0xeb, 0xff, 0x2a, 0x53, 0xf3, 0x44, - 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, - 0x73, 0x64, 0x64, 0x6b, 0x75, 0x00, 0x00, 0x01, 0x87, 0x00, 0x07, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, - 0x34, 0x34, 0x84, 0x40, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x51, 0x13, 0x75, - 0xf7, 0x83, 0x41, 0xb7, 0x59, 0x51, 0x13, 0x75, 0xf7, 0x83, 0x8e, 0xc3, - 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, 0x69, 0x08, 0x28, 0x2f, - 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, 0x0e, 0x4d, 0x78, 0x41, 0x89, - 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, 0x36, 0x7b, 0xf9, 0xc7, 0xb9, - 0x71, 0xe5, 0xce, 0x65, 0x7a, 0x52, 0xa0, 0x52, 0xa3, 0xaa, 0xf5, 0x34, - 0xec, 0xfb, 0xf7, 0xcb, 0xdd, 0xe4, 0xee, 0x33, 0x4c, 0x10, 0x02, 0x00, - 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xc9, 0xa4, - 0xb0, 0xbb, 0x30, 0xa3, 0x3d, 0x27, 0x05, 0x4f, 0x4c, 0x5e, 0x1f, 0x82, - 0x66, 0x8e, 0x02, 0x48, 0x36, 0x3c, 0x6b, 0xa3, 0x16, 0x82, 0x0c, 0x12, - 0x58, 0xe2, 0xb6, 0x5f, 0xe3, 0x0a, 0x20, 0xfd, 0xad, 0xa0, 0xc7, 0x99, - 0x65, 0x78, 0xfe, 0x99, 0xa5, 0xac, 0x48, 0x47, 0x0e, 0x2d, 0xc3, 0x76, - 0x76, 0xcb, 0xca, 0x9b, 0xb7, 0xe5, 0x3b, 0x4a, 0xca, 0x8a, 0xb6, 0x6f, - 0x22, 0x08, 0xcb, 0xb4, 0xc6, 0xf6, 0xba, 0x30, 0x52, 0x57, 0x1b, 0x09, - 0xc8, 0x9a, 0x3e, 0xde, 0x73, 0x81, 0xde, 0xb7, 0xc2, 0x2d, 0x46, 0xc9, - 0x52, 0x9f, 0x4b, 0xef, 0x2c, 0x2f, 0x5c, 0xa3, 0x10, 0x98, 0x0d, 0x57, - 0x0b, 0x4c, 0xc5, 0xeb, 0x49, 0x49, 0x7f, 0xae, 0xc3, 0x45, 0xbe, 0x0a, - 0x7d, 0x37, 0x94, 0xc4, 0xfe, 0x53, 0xdf, 0x10, 0x55, 0x98, 0xf9, 0x68, - 0x2a, 0xf7, 0x42, 0x48, 0x6b, 0xa7, 0x5b, 0x3d, 0xa3, 0x9f, 0xed, 0xf2, - 0x70, 0xcb, 0x64, 0x74, 0xa8, 0xfa, 0xdc, 0xe4, 0x5e, 0x90, 0x6f, 0x79, - 0x18, 0x19, 0xc8, 0xbf, 0xf3, 0x78, 0xd9, 0x35, 0x07, 0x42, 0x5f, 0xc6, - 0x04, 0x09, 0x62, 0x1f, 0xa4, 0xe2, 0x67, 0x06, 0x46, 0x47, 0xac, 0x53, - 0x7d, 0x0e, 0xbb, 0xd7, 0xbd, 0x51, 0x00, 0x60, 0x44, 0xa9, 0x47, 0x60, - 0xd5, 0x7f, 0xc4, 0x45, 0xdb, 0xd5, 0x42, 0xbe, 0x8e, 0x5d, 0x89, 0xbd, - 0xb4, 0xe7, 0x6e, 0xdf, 0xcc, 0x21, 0x10, 0x2c, 0x8d, 0xe8, 0x6e, 0x2c, - 0xb8, 0x72, 0x0e, 0x86, 0xe9, 0xd4, 0x08, 0x93, 0xf3, 0xb3, 0x2a, 0x00, - 0xa0, 0xe2, 0x1f, 0xc4, 0x09, 0x3b, 0x75, 0x81, 0x99, 0x17, 0x5b, 0x78, - 0x27, 0x32, 0x6d, 0x0b, 0x29, 0x31, 0x51, 0x70, 0x50, 0x95, 0x0c, 0x94, - 0x90, 0xba, 0x18, 0x17, 0x44, 0x6b, 0xd8, 0x50, 0x58, 0xe8, 0xe2, 0xff, - 0x80, 0xb9, 0x44, 0xfe, 0x1b, 0x8f, 0xdf, 0xa1, 0x91, 0xeb, 0x57, 0x86, - 0xd0, 0x61, 0x1a, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, - 0x84, 0x43, 0x02, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, 0x66, 0x17, - 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x41, 0xb7, 0x59, - 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x77, 0xac, 0x86, 0x8b, 0xf9, 0xb8, 0xa0, - 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, 0xe2, 0x63, 0x81, 0xf6, 0x85, 0xbc, - 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, - 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf6, 0xbc, 0x81, - 0x5b, 0x23, 0x66, 0x44, 0x13, 0x27, 0xcf, 0x98, 0xc2, 0xc0, 0x31, 0x38, - 0x98, 0xec, 0x01, 0x84, 0xbb, 0x38, 0xb1, 0x79, 0xd7, 0x91, 0x66, 0x5a, - 0x56, 0x22, 0x62, 0x6f, 0xb8, 0xf0, 0x68, 0x00, 0xe7, 0x1a, 0x7a, 0x93, - 0xfc, 0xa8, 0xd4, 0xd9, 0xaf, 0x21, 0x17, 0x71, 0xf3, 0x0c, 0xd6, 0x22, - 0x2f, 0xb0, 0xb7, 0xc3, 0x1e, 0x07, 0xe7, 0x53, 0x34, 0xc9, 0x17, 0x9d, - 0xe8, 0xd3, 0x07, 0x78, 0xe7, 0x74, 0xcd, 0xf0, 0xdd, 0x88, 0x0d, 0x30, - 0x9b, 0x3c, 0x78, 0xfb, 0x43, 0xb7, 0x4f, 0x79, 0xd1, 0x83, 0xcd, 0x56, - 0x60, 0xe7, 0x7e, 0x8d, 0xba, 0x61, 0x9d, 0x4f, 0xf2, 0x71, 0x9b, 0xbd, - 0x11, 0xfc, 0x82, 0x8f, 0xc2, 0x9b, 0x32, 0xb7, 0x4d, 0x5d, 0x93, 0x87, - 0x11, 0x7d, 0xbf, 0x3a, 0x06, 0x11, 0x15, 0xf5, 0x97, 0xf4, 0x03, 0x24, - 0x6a, 0xfb, 0x5e, 0x27, 0x2b, 0xb5, 0xac, 0x20, 0x84, 0xe8, 0x8d, 0x67, - 0xa9, 0xf5, 0x41, 0x8a, 0xbd, 0xea, 0x51, 0x91, 0x30, 0xd7, 0xf2, 0x81, - 0x12, 0xbc, 0x24, 0x61, 0x25, 0x58, 0x9e, 0x4a, 0x4c, 0x89, 0xa4, 0x19, - 0xf1, 0x12, 0xe2, 0x33, 0xf1, 0x37, 0x1f, 0x0f, 0xa0, 0x42, 0xa1, 0x0e, - 0xa2, 0xc4, 0x06, 0xb0, 0xba, 0x61, 0xef, 0xc5, 0x6b, 0x46, 0x33, 0x62, - 0x50, 0xe0, 0xe4, 0x2e, 0x74, 0x20, 0xf4, 0x54, 0xbb, 0xed, 0xa0, 0x73, - 0x51, 0xa5, 0xc6, 0x55, 0x90, 0x61, 0xe9, 0x9c, 0x76, 0x72, 0x21, 0xa9, - 0x19, 0x1a, 0xbd, 0xcf, 0x61, 0x29, 0x8a, 0xef, 0xdd, 0xe0, 0xc6, 0x0a, - 0xf0, 0xd8, 0x50, 0xb9, 0xe9, 0x92, 0x7d, 0xf3, 0xce, 0x7e, 0x9e, 0xcf, - 0x32, 0x92, 0xc7, 0x49, 0x59, 0x23, 0xb5, 0x4e, 0xf2, 0x71, 0xf0, 0xda, - 0xb3, 0x80, 0xe3, 0xb6, 0x7a, 0xe4, 0x14, 0x80, 0x25, 0x3e, 0xd0, 0x89, - 0x13, 0xf4, 0x70, 0x96, 0xee, 0xbe, 0xef, 0x31, 0x61, 0xa1, 0x8d, 0xf7, - 0x9a, 0x5c, 0x92, 0x0a, 0x9b, 0x1f, 0x8c, 0x5e, 0x3d, 0x37, 0x24, 0xc2, - 0x8d, 0x21, 0xe9, 0x47, 0x2e, 0x03, 0xee, 0x32, 0xbf, 0x46, 0xc7, 0x2c, - 0x6e, 0x7a, 0x81, 0x9e, 0x14, 0xb8, 0xbe, 0xdb, 0x22, 0x4f, 0xf1, 0x8d, - 0x47, 0x41, 0x84, 0xc9, 0xeb, 0x4f, 0xe9, 0xf4, 0xad, 0xc4, 0xbe, 0xf8, - 0x28, 0xcb, 0xe6, 0x16, 0xa8, 0x6b, 0xaf, 0xd5, 0x0a, 0x6d, 0x06, 0x59, - 0x4f, 0x7d, 0x53, 0xa6, 0x4e, 0x90, 0xa0, 0x23, 0x1b, 0x92, 0xf0, 0xe8, - 0xef, 0xed, 0x0d, 0xa7, 0x64, 0x01, 0x83, 0x4a, 0x3b, 0x2d, 0x18, 0x90, - 0x1d, 0x19, 0x1d, 0xa2, 0x98, 0xe9, 0xb5, 0xe4, 0x4a, 0x73, 0xcf, 0xdf, - 0x0c, 0x09, 0xd5, 0xf4, 0xd3, 0xd9, 0x12, 0x7c, 0xbb, 0x81, 0x51, 0x26, - 0x2a, 0xcb, 0xa7, 0xc9, 0x6a, 0xe9, 0xfb, 0x1d, 0xca, 0x43, 0xf1, 0xbe, - 0xfb, 0xc3, 0x6f, 0xb6, 0xa1, 0x0c, 0x42, 0x32, 0x18, 0x24, 0x63, 0xf9, - 0xa0, 0x7e, 0x71, 0x8c, 0xa5, 0x16, 0x16, 0x5a, 0x5e, 0x15, 0x5d, 0x6d, - 0x4b, 0x74, 0x5b, 0xde, 0x21, 0xd5, 0xe0, 0x11, 0xa6, 0x91, 0xc3, 0xb2, - 0xd7, 0x38, 0x70, 0xa2, 0x18, 0x29, 0x1b, 0xdc, 0x83, 0x3e, 0x37, 0x45, - 0xc4, 0x1b, 0x61, 0x98, 0x06, 0x12, 0x3e, 0xc0, 0xda, 0x1a, 0xc9, 0x18, - 0x9c, 0x50, 0x0e, 0xc5, 0xe1, 0xa7, 0x4d, 0x05, 0xc6, 0x99, 0x31, 0xab, - 0x17, 0x30, 0xb9, 0xb0, 0x01, 0x1f, 0x93, 0xd9, 0x76, 0xd4, 0x67, 0x0b, - 0xea, 0x7b, 0x2b, 0x0b, 0x42, 0x97, 0x40, 0x07, 0x94, 0x08, 0x61, 0x70, - 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x84, 0x3f, 0x01, 0x16, 0x00, 0x07, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x34, 0x00, 0x87, 0x5e, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, - 0x33, 0x2b, 0x24, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x83, - 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, 0x45, 0x30, 0xb3, 0x67, 0xc8, 0x32, - 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, 0xf4, 0x06, 0x98, 0x7e, 0x8b, 0x09, - 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, - 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x99, 0xb4, 0x79, 0xc1, 0x37, 0xc1, 0xe1, 0x5c, 0x49, - 0xa0, 0xe1, 0xf3, 0x17, 0xb8, 0x9c, 0x69, 0xe6, 0xba, 0xdc, 0xe7, 0x78, - 0xb2, 0x5d, 0xd6, 0x95, 0xbe, 0xb2, 0xda, 0x91, 0xd3, 0x9b, 0xf2, 0xd4, - 0xe3, 0x95, 0x3c, 0x53, 0x8d, 0x0e, 0x68, 0xe9, 0x02, 0xb3, 0xed, 0xeb, - 0x95, 0xdd, 0x11, 0xb2, 0x64, 0x69, 0x8a, 0xfe, 0x03, 0x05, 0xd5, 0x04, - 0x9b, 0xac, 0x8a, 0xb6, 0x98, 0x29, 0x56, 0x2e, 0xd3, 0xea, 0x4e, 0x84, - 0xee, 0x23, 0x44, 0x03, 0x12, 0x9d, 0x9c, 0x9c, 0x9f, 0x11, 0x62, 0xf0, - 0x86, 0x36, 0x52, 0x15, 0x0f, 0x27, 0x93, 0xdb, 0xde, 0x13, 0xc9, 0x94, - 0x93, 0xe4, 0xa4, 0x6f, 0x58, 0x9d, 0x58, 0x9f, 0x15, 0xba, 0x5f, 0x4c, - 0xf3, 0x9a, 0x90, 0xc0, 0xcb, 0x60, 0xce, 0x9b, 0x56, 0x0c, 0xfe, 0x5b, - 0xd2, 0x4e, 0x0e, 0x82, 0xe6, 0x4c, 0x62, 0x57, 0x08, 0x6e, 0x5d, 0x54, - 0x7b, 0x28, 0xbb, 0x88, 0xdc, 0xec, 0xaa, 0xd1, 0x6e, 0xd3, 0x94, 0x20, - 0x3e, 0x35, 0x81, 0x52, 0xf6, 0xe9, 0xee, 0x42, 0x89, 0xe9, 0xea, 0x61, - 0x2c, 0xd8, 0xdc, 0xe3, 0x82, 0xf7, 0xf0, 0xc0, 0xf6, 0xf9, 0xb7, 0xef, - 0x49, 0xc7, 0x8d, 0x6c, 0x8a, 0x6d, 0x6e, 0xbc, 0x2d, 0xc0, 0xb1, 0xec, - 0x0c, 0xdd, 0xe5, 0xbe, 0x65, 0x3f, 0x69, 0x81, 0xcf, 0xe8, 0xd8, 0xf3, - 0x57, 0x8e, 0xba, 0x73, 0x7f, 0xb0, 0x4e, 0x65, 0xa2, 0xa5, 0xa5, 0xbb, - 0x7b, 0xae, 0xaa, 0x88, 0x06, 0x4f, 0x2c, 0x43, 0xb9, 0x4c, 0x17, 0xa1, - 0x24, 0xfb, 0xe1, 0x90, 0x50, 0xdb, 0xcc, 0xd9, 0xe5, 0x7b, 0x09, 0xaf, - 0x5c, 0x5a, 0x4f, 0xb2, 0x2b, 0x30, 0x53, 0x0f, 0xd3, 0xe2, 0xbd, 0xcd, - 0xf7, 0xa3, 0x19, 0xdc, 0xba, 0xee, 0xd1, 0x49, 0xbc, 0xa6, 0xde, 0x1b, - 0xe6, 0xd3, 0xaf, 0xdd, 0x61, 0xf6, 0xfd, 0xef, 0xb7, 0xda, 0x9d, 0x93, - 0x45, 0x0a, 0xa2, 0xa8, 0x1a, 0xe5, 0x16, 0xb1, 0xaf, 0x20, 0x00, 0x86, - 0x6b, 0x66, 0x42, 0x97, 0x4e, 0x3a, 0xea, 0x0d, 0x33, 0xb2, 0x93, 0x87, - 0x9c, 0xd1, 0x6a, 0x20, 0xbc, 0xc9, 0x7d, 0x46, 0xb9, 0x0a, 0x26, 0x9a, - 0x09, 0x81, 0xc8, 0x6d, 0x9b, 0x63, 0xa5, 0x1f, 0x63, 0x72, 0x6c, 0xa8, - 0x65, 0x65, 0xa2, 0x8a, 0x81, 0x4d, 0x54, 0xd4, 0xa3, 0xc4, 0x86, 0x48, - 0x31, 0x5c, 0x4e, 0x15, 0xf3, 0x48, 0x30, 0xbc, 0x17, 0xac, 0x0b, 0x85, - 0x8f, 0x44, 0x62, 0xf4, 0x57, 0xc7, 0xbd, 0x18, 0xcf, 0xf5, 0xd8, 0xa9, - 0x2d, 0xf5, 0x57, 0xaf, 0x42, 0x09, 0xf7, 0x5b, 0x25, 0x56, 0xa1, 0x04, - 0x0c, 0xf7, 0xa7, 0xc9, 0x2d, 0xd7, 0x84, 0x78, 0x86, 0x82, 0x2d, 0xd3, - 0xaa, 0xd2, 0xbf, 0x77, 0xc0, 0x34, 0x7b, 0xdb, 0x7e, 0x4d, 0xde, 0x63, - 0x8f, 0xcc, 0xb6, 0x6d, 0x01, 0x80, 0x68, 0x51, 0x3e, 0x8f, 0x2a, 0x7c, - 0x0e, 0xaa, 0xc2, 0xbf, 0x77, 0x12, 0x06, 0x88, 0xdf, 0x3f, 0x6c, 0x7d, - 0x69, 0x05, 0x57, 0x71, 0xeb, 0xe7, 0xf3, 0xcb, 0x32, 0x4d, 0x33, 0x54, - 0x8a, 0x2a, 0x1b, 0xb5, 0x6e, 0xb6, 0xa4, 0x64, 0xcd, 0x34, 0x5c, 0xa9, - 0x3d, 0x92, 0xc8, 0x38, 0xbb, 0x84, 0xed, 0xde, 0xe4, 0xa2, 0xe1, 0x68, - 0x2f, 0xcb, 0x4b, 0x3c, 0x76, 0xb2, 0x3b, 0x84, 0x5f, 0x6b, 0x46, 0x72, - 0x2f, 0x7f, 0xf0, 0x6f, 0x6b, 0x7b, 0xd3, 0xc5, 0x4b, 0x20, 0x2b, 0xae, - 0x48, 0x7e, 0xcb, 0x22, 0x38, 0x44, 0x1f, 0x43, 0x1c, 0x55, 0x00, 0x00, - 0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x19, 0x07, 0x0a, 0x00, 0x00, 0x00, - 0x0a, 0x0d, 0xf1, 0x00, 0x0e, 0x8c, 0x0e, 0xf4, 0x0e, 0xc0, 0x0e, 0x24, - 0x0f, 0x99, 0x0e, 0x58, 0x0f, 0xcd, 0x0f, 0x65, 0x0d, 0xf1, 0x0f, 0x28, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x32, 0x05, 0x34, 0x34, 0x15, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0xa9, 0x4a, 0x8f, 0xe5, 0xcc, 0xb1, 0x9b, 0xa6, 0x1c, - 0x4c, 0x08, 0x73, 0xd3, 0x91, 0xe9, 0x87, 0x98, 0x2f, 0xbb, 0xd3, 0x74, - 0x65, 0x73, 0x74, 0x11, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x59, 0x27, - 0x33, 0x2f, 0x22, 0x90, 0x8f, 0xdf, 0x8f, 0x07, 0xfa, 0xa9, 0xeb, 0x8d, - 0x26, 0x20, 0xc7, 0xc6, 0x2a, 0x20, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, - 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, - 0xa1, 0xb8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x0d, 0x33, 0x05, 0x34, 0x34, - 0x17, 0x01, 0x7f, 0xda, 0x6a, 0xa0, 0x63, 0xf3, 0xfc, 0x5a, 0x86, 0x5c, - 0xa8, 0xf7, 0xa6, 0x9b, 0x5d, 0x69, 0x07, 0x3b, 0x91, 0x55, 0x72, 0x29, - 0x9c, 0x30, 0x4b, 0x50, 0xee, 0xe7, 0xb0, 0xc7, 0x1b, 0x05, 0x97, 0x70, - 0xac, 0x8e, 0x43, 0x5d, 0x69, 0x39, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x12, - 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x05, 0xc5, 0x64, 0xf0, 0xff, 0xc1, - 0x0a, 0xf4, 0x42, 0x83, 0x33, 0x33, 0x5d, 0x04, 0x75, 0x9c, 0x85, 0x9a, - 0x74, 0x0a, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, - 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x61, 0x70, - 0x70, 0x6c, 0x65, 0x09, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x51, 0x96, - 0x74, 0xbb, 0x0c, 0xef, 0x0c, 0xf3, 0x24, 0x61, 0xd2, 0x2c, 0xba, 0x9a, - 0xa9, 0xc8, 0x0e, 0x22, 0xff, 0x0b, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, - 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, - 0xa1, 0xb8, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x08, 0x33, 0x05, 0x34, 0x34, - 0x17, 0x01, 0x0b, 0x66, 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, - 0x95, 0x22, 0xa7, 0xe3, 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, - 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, - 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x07, - 0x3c, 0x05, 0x34, 0x34, 0x29, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, - 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, - 0x07, 0x09, 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, 0x59, 0x31, 0xba, - 0xaa, 0x89, 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, 0x60, 0x63, 0x6f, - 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, - 0x05, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, - 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, - 0x13, 0xa3, 0x59, 0xe5, 0x0e, 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, - 0x6d, 0xb9, 0x0a, 0x0b, 0x36, 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x61, - 0x70, 0x70, 0x6c, 0x65, 0x06, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x77, - 0xac, 0x86, 0x8b, 0xf9, 0xb8, 0xa0, 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, - 0xe2, 0x63, 0x81, 0xf6, 0x85, 0xbc, 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, - 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, - 0x41, 0xcb, 0x34, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x02, 0x32, 0x05, 0x34, - 0x34, 0x17, 0x09, 0x83, 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, 0x45, 0x30, - 0xb3, 0x67, 0xc8, 0x32, 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, 0xf4, 0x06, - 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, - 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x61, 0x70, 0x70, 0x6c, 0x65, - 0x0d, 0x0f, 0xe4, 0x00, 0x03, 0x0f, 0xda, 0x00, 0x0f, 0xf6, 0x0f, 0xda, - 0x0f, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x08, 0x02, 0x03, 0x15, 0x01, 0x63, 0x65, 0x72, 0x74, 0x02, - 0x00, 0x00, 0x00, 0x08, 0x09, 0x6b, 0x65, 0x79, 0x08, 0x03, 0x03, 0x15, - 0x01, 0x6b, 0x65, 0x79, 0x73, 0x06, 0x08, 0x01, 0x03, 0x15, 0x01, 0x67, - 0x65, 0x6e, 0x70, 0x12, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x02, 0x03, 0xfb, 0x00, 0x09, 0xed, 0x03, 0xfb, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, - 0x6f, 0x02, 0x11, 0x00, 0x07, 0x07, 0x01, 0x01, 0x34, 0x00, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x95, 0x12, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, - 0x9d, 0x7a, 0x35, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x9d, 0x7a, 0x35, 0x03, - 0x03, 0x37, 0xee, 0x5a, 0x85, 0xe1, 0xcb, 0xdd, 0xc8, 0xce, 0x07, 0x77, - 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, 0x30, 0x3a, 0xcd, 0x7e, 0x0b, 0xaa, - 0xec, 0xd2, 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, - 0x70, 0x20, 0x84, 0xa7, 0x17, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, 0x12, - 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, 0x0d, - 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, 0x5b, - 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0xda, 0xde, 0x08, - 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, 0xba, 0xe3, - 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, - 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, - 0x4b, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0xc4, 0xe8, 0xe5, 0xde, 0xeb, 0xd1, 0xbc, 0xae, 0x0f, 0x47, 0x6a, - 0xc0, 0xb4, 0xf8, 0x7a, 0xdc, 0xc1, 0x10, 0xb0, 0x90, 0xf2, 0x29, 0x16, - 0x8f, 0x90, 0xeb, 0x31, 0x83, 0x9b, 0x33, 0x91, 0x26, 0x16, 0x4c, 0xce, - 0xfe, 0x98, 0x25, 0x0d, 0xed, 0xe6, 0x9f, 0xc3, 0x91, 0xac, 0xbb, 0xf8, - 0xc0, 0xca, 0x25, 0x42, 0xd4, 0x5d, 0xfe, 0x1b, 0x4d, 0x60, 0x7f, 0x01, - 0xee, 0x5f, 0x16, 0xbd, 0xb8, 0xe7, 0xdc, 0xe1, 0x75, 0xf9, 0x1a, 0xc7, - 0x4f, 0xc5, 0xf1, 0x44, 0x46, 0xfe, 0xdd, 0x91, 0xf8, 0x25, 0xed, 0xbc, - 0x1a, 0xf1, 0x34, 0x71, 0x05, 0x4e, 0x13, 0xb9, 0x21, 0xbf, 0x04, 0x6d, - 0x1e, 0x0f, 0xe6, 0x63, 0x19, 0x0b, 0x77, 0xef, 0xf1, 0x24, 0xf4, 0x55, - 0xf3, 0x71, 0x53, 0x13, 0x8b, 0xbb, 0xd5, 0xdb, 0x3e, 0xcb, 0xc5, 0x3a, - 0x9a, 0xe9, 0x55, 0xa1, 0x75, 0xa1, 0x98, 0x40, 0x80, 0x3b, 0x1e, 0xe1, - 0xbc, 0x44, 0x59, 0xb9, 0xf2, 0x6b, 0xa9, 0x0d, 0x13, 0x0c, 0xd2, 0xb2, - 0x99, 0xbf, 0x1f, 0xa9, 0x86, 0x5b, 0x2b, 0x63, 0x65, 0x28, 0x2f, 0x11, - 0x96, 0x2b, 0xa1, 0x9d, 0x32, 0x5e, 0x55, 0xa1, 0xdf, 0x90, 0x3b, 0x5e, - 0x4e, 0xdd, 0x3f, 0x6f, 0x10, 0xb6, 0x7c, 0xad, 0x92, 0xeb, 0x9f, 0x72, - 0xe4, 0x37, 0x83, 0x59, 0x4b, 0x6c, 0x62, 0x2e, 0xf1, 0x11, 0x5a, 0x75, - 0x86, 0x5b, 0xe4, 0x79, 0x86, 0xca, 0xdb, 0xd8, 0x11, 0xf4, 0x5f, 0x65, - 0x8f, 0x7f, 0x66, 0xc4, 0xe0, 0x35, 0x97, 0x15, 0xe3, 0x13, 0x97, 0xa9, - 0x23, 0x20, 0xce, 0xfe, 0x1a, 0x3a, 0x3f, 0xce, 0xa3, 0x88, 0x36, 0xfa, - 0x58, 0xb2, 0x35, 0x9a, 0x07, 0x69, 0xcd, 0xc7, 0xc7, 0xf4, 0x93, 0x0d, - 0x11, 0x3f, 0xec, 0x74, 0x88, 0x55, 0xfc, 0x12, 0x08, 0x0d, 0xc1, 0xd1, - 0x1f, 0xf6, 0xdd, 0xff, 0xea, 0x75, 0x40, 0x21, 0x06, 0xf2, 0x8a, 0x6c, - 0x2e, 0xc4, 0x84, 0x5d, 0x67, 0x90, 0x29, 0x95, 0xed, 0x6e, 0x55, 0x19, - 0x12, 0xb0, 0x11, 0x41, 0x2e, 0x2b, 0xe0, 0xbb, 0xe4, 0x90, 0x8e, 0xa3, - 0x9f, 0x1c, 0x3d, 0xa0, 0xd1, 0x5c, 0xa3, 0x01, 0xf3, 0x0f, 0x09, 0x64, - 0x7c, 0x12, 0xbc, 0x43, 0x2a, 0x24, 0x32, 0x8c, 0x63, 0x6c, 0x4d, 0x91, - 0xff, 0xe8, 0x0c, 0xc3, 0x54, 0xa8, 0x9b, 0x01, 0x99, 0x56, 0xc3, 0x1c, - 0xe1, 0x8e, 0x18, 0xfb, 0xb7, 0xfe, 0x27, 0x8c, 0x83, 0x3b, 0x07, 0x5b, - 0x93, 0x35, 0xaa, 0xef, 0xda, 0xb5, 0x50, 0x29, 0x92, 0x64, 0x18, 0x5d, - 0x2d, 0x25, 0x13, 0x68, 0x11, 0x37, 0xa7, 0x9e, 0xb1, 0x82, 0xe5, 0x10, - 0x6c, 0x2e, 0x44, 0x23, 0x04, 0x88, 0x47, 0xf0, 0x8e, 0xbc, 0xb2, 0xda, - 0xe2, 0x58, 0x8e, 0x4a, 0xc9, 0x93, 0x28, 0x7a, 0x32, 0x8c, 0x3d, 0x9b, - 0x49, 0x45, 0xcd, 0x13, 0x15, 0x13, 0xef, 0xaa, 0x71, 0x76, 0x08, 0x31, - 0xdf, 0xf2, 0xce, 0xae, 0xc5, 0xf7, 0x01, 0xd4, 0x59, 0x76, 0x88, 0xa3, - 0x8b, 0xfc, 0x3a, 0x24, 0xb6, 0x98, 0x44, 0x51, 0x87, 0xff, 0x14, 0xa7, - 0xb0, 0x47, 0x15, 0xc0, 0x35, 0x9a, 0xb8, 0xf1, 0xff, 0xa8, 0x84, 0x5b, - 0x4e, 0x59, 0x02, 0x65, 0xbf, 0x6f, 0xd5, 0x4d, 0xa0, 0xdb, 0x50, 0x13, - 0x7f, 0x1f, 0x86, 0x3a, 0x7a, 0x6b, 0xfb, 0xf2, 0xb6, 0xa6, 0x3d, 0xac, - 0x97, 0x86, 0xbf, 0x29, 0xdb, 0xb6, 0x99, 0xe8, 0x22, 0xce, 0xea, 0x43, - 0x38, 0xab, 0xfa, 0x64, 0x6c, 0xcc, 0x45, 0x7a, 0xc0, 0x9f, 0x50, 0x7b, - 0x1f, 0x25, 0x33, 0xe6, 0xfc, 0x9f, 0xcc, 0xfb, 0xbb, 0x50, 0x33, 0x31, - 0xe8, 0x62, 0x33, 0x43, 0x7e, 0x8d, 0x82, 0x38, 0x0c, 0x2c, 0x6e, 0x57, - 0x5f, 0x08, 0x31, 0x96, 0x48, 0x02, 0xbb, 0x95, 0x9a, 0xea, 0xd4, 0xcd, - 0x54, 0x49, 0x65, 0x51, 0xf6, 0xc9, 0x39, 0x39, 0xab, 0xe3, 0x92, 0xc2, - 0x71, 0xbb, 0xb1, 0x25, 0x12, 0x96, 0x45, 0xb8, 0x14, 0x34, 0x82, 0x94, - 0x9f, 0xbd, 0xc7, 0xf7, 0x07, 0x4f, 0x7d, 0xb5, 0xa2, 0xe2, 0xd5, 0x91, - 0xbf, 0x9b, 0xde, 0x3d, 0xa2, 0xfe, 0x25, 0x76, 0x5e, 0xac, 0xde, 0xf1, - 0x5f, 0x00, 0xe5, 0x9f, 0x6f, 0x3d, 0xdd, 0xbc, 0x7f, 0xfd, 0x92, 0x52, - 0x56, 0x53, 0x5a, 0x04, 0xca, 0xdc, 0x23, 0x76, 0xe4, 0xc4, 0xeb, 0x00, - 0x5e, 0x3e, 0x71, 0xb9, 0x7c, 0x54, 0x81, 0x4d, 0x6e, 0xb3, 0x09, 0x39, - 0x6f, 0x67, 0x0e, 0xc6, 0x95, 0xdf, 0x03, 0xcc, 0x7e, 0x0b, 0x7c, 0x31, - 0x16, 0xbe, 0x4b, 0xfc, 0x0f, 0x17, 0xb4, 0x7a, 0x9c, 0x44, 0x36, 0x5a, - 0xaf, 0x42, 0x69, 0x40, 0x58, 0xe7, 0xa4, 0x07, 0x5b, 0xe5, 0xd6, 0x35, - 0xe5, 0x4a, 0xde, 0x35, 0x29, 0xc5, 0x69, 0x00, 0x47, 0xfa, 0x3d, 0x54, - 0xbc, 0x1f, 0xa5, 0x58, 0x86, 0xbf, 0xaa, 0x5d, 0x94, 0x60, 0x3b, 0x81, - 0x11, 0xa0, 0xa0, 0x19, 0xf3, 0x7a, 0xfd, 0x69, 0x5f, 0xac, 0xf6, 0x41, - 0xfd, 0x73, 0xff, 0x99, 0x2a, 0x41, 0xee, 0xda, 0x7f, 0xfe, 0x80, 0xcb, - 0x20, 0x9e, 0x8f, 0xdc, 0x6c, 0x3f, 0x71, 0xed, 0x07, 0xc5, 0xd9, 0x4f, - 0x32, 0x9e, 0xe5, 0x0b, 0x63, 0x70, 0x66, 0x2b, 0x42, 0x5d, 0xa3, 0xfa, - 0x81, 0x6a, 0x47, 0x40, 0xa6, 0xed, 0x8c, 0x7d, 0x71, 0x61, 0x74, 0xd3, - 0x40, 0x24, 0x1f, 0x2c, 0x4a, 0x89, 0xd3, 0xbb, 0xb8, 0x14, 0x6b, 0x8f, - 0xb2, 0x3d, 0x16, 0x99, 0xf5, 0x7f, 0x0a, 0x2e, 0x79, 0x6b, 0xb6, 0xe8, - 0x8f, 0xb3, 0x42, 0x67, 0x93, 0x59, 0xe8, 0x69, 0x66, 0x9e, 0x6d, 0x06, - 0x11, 0x5d, 0xfd, 0x0f, 0x19, 0x43, 0x9f, 0x5b, 0x82, 0xbc, 0x5f, 0x79, - 0xeb, 0x4f, 0x7f, 0xcc, 0xfa, 0x8e, 0xe5, 0xe6, 0xe4, 0x01, 0xf7, 0xa0, - 0x7a, 0xb8, 0xe6, 0xb6, 0x08, 0x19, 0x80, 0x30, 0xa4, 0x2f, 0x84, 0xd2, - 0x5e, 0xce, 0xde, 0x59, 0x26, 0xf6, 0x19, 0x19, 0x42, 0x13, 0x0e, 0xcb, - 0x3f, 0xfb, 0x22, 0xbb, 0x61, 0xc6, 0xf8, 0xc9, 0x68, 0x77, 0x60, 0x30, - 0x85, 0x34, 0x2a, 0x30, 0x3c, 0x09, 0xd9, 0x2f, 0xf7, 0x15, 0xdc, 0x50, - 0xc5, 0x05, 0x18, 0x12, 0x2c, 0x8b, 0x55, 0xad, 0x3e, 0x2a, 0xf9, 0x1f, - 0x77, 0xa3, 0xc6, 0x34, 0x47, 0x86, 0x7d, 0x85, 0x11, 0x1c, 0x04, 0x0c, - 0x4a, 0xae, 0xc0, 0x49, 0xba, 0x46, 0xa9, 0x75, 0xd5, 0x86, 0x1b, 0xa0, - 0x18, 0x63, 0xfe, 0x9c, 0x23, 0x6c, 0xb3, 0xfe, 0x06, 0x06, 0x6f, 0xdf, - 0x8b, 0x5b, 0x59, 0x2b, 0xd4, 0x97, 0x50, 0x1b, 0x79, 0x64, 0x57, 0xbe, - 0x62, 0x46, 0xda, 0x38, 0xf3, 0x06, 0x3c, 0xec, 0x3e, 0xcf, 0x14, 0x24, - 0xc6, 0x33, 0xf6, 0x08, 0x0e, 0xe9, 0xb1, 0xbc, 0x29, 0x37, 0x13, 0x96, - 0x79, 0x2a, 0x32, 0x8e, 0x93, 0xed, 0x97, 0xcf, 0x7e, 0x72, 0xb6, 0x60, - 0x6c, 0x68, 0x2a, 0xf2, 0xbf, 0xd2, 0xe0, 0x2b, 0x76, 0xd3, 0x88, 0x24, - 0xf7, 0xfc, 0xed, 0xf9, 0x59, 0xff, 0xd1, 0xd5, 0xf4, 0x69, 0x00, 0xd2, - 0xbd, 0xfc, 0xcb, 0x1e, 0x8b, 0x51, 0x7a, 0xd5, 0x46, 0x6e, 0x11, 0x33, - 0xf8, 0xee, 0xbd, 0xb5, 0x64, 0x8b, 0xf6, 0x31, 0xd4, 0x7f, 0xda, 0x2b, - 0xf0, 0x52, 0x92, 0xaa, 0xee, 0x4e, 0x2e, 0xea, 0xdd, 0x42, 0x14, 0x51, - 0xff, 0xc0, 0xb2, 0x6e, 0xc2, 0x77, 0x7a, 0x9d, 0xce, 0x74, 0xaa, 0xe9, - 0x46, 0x67, 0x40, 0x08, 0xfe, 0xf5, 0xc0, 0xd0, 0x33, 0x2b, 0x7a, 0x07, - 0xb0, 0x37, 0x22, 0x96, 0x0c, 0xe1, 0xe2, 0x97, 0x96, 0x1b, 0xcf, 0xfc, - 0xd3, 0x4a, 0x8f, 0x6e, 0x99, 0xc1, 0xb0, 0x43, 0xb7, 0x96, 0xd4, 0xab, - 0xe6, 0x8b, 0x90, 0x98, 0x8a, 0xed, 0x0f, 0xe1, 0x77, 0x20, 0x87, 0x39, - 0x66, 0x56, 0xfa, 0xa1, 0x58, 0xd1, 0x8a, 0x0e, 0x59, 0xc0, 0x21, 0xf7, - 0x14, 0x10, 0xe3, 0xbb, 0x2f, 0xcd, 0x09, 0xc2, 0x44, 0x04, 0x27, 0x3f, - 0x68, 0xec, 0xc2, 0xd0, 0x04, 0xb5, 0x0b, 0x14, 0x8f, 0xcf, 0x04, 0xc1, - 0x94, 0x65, 0xc2, 0xbc, 0x8f, 0x9c, 0x79, 0x0b, 0xe2, 0xd6, 0x5b, 0xe9, - 0x90, 0xa5, 0x0b, 0x8c, 0xa7, 0x27, 0xc5, 0x6d, 0x89, 0x62, 0x30, 0x3d, - 0x5b, 0x7a, 0xd4, 0xee, 0x33, 0x1c, 0x42, 0x09, 0x64, 0x95, 0x64, 0x25, - 0x79, 0x63, 0x5a, 0x10, 0x79, 0x5d, 0xb4, 0x86, 0x19, 0x84, 0x84, 0x61, - 0x43, 0x1d, 0x46, 0xef, 0xd5, 0x81, 0xc0, 0xe7, 0x3f, 0x64, 0xf1, 0xf0, - 0x36, 0x1b, 0x1f, 0xdf, 0xba, 0x7e, 0x6a, 0x8b, 0xdb, 0xc2, 0x48, 0xe3, - 0x07, 0x12, 0x9e, 0xc1, 0x9c, 0x85, 0xd0, 0xa5, 0x5e, 0xda, 0x88, 0x43, - 0xb3, 0xed, 0xbb, 0xd3, 0xdf, 0x8e, 0x6f, 0x13, 0x51, 0x52, 0x50, 0x73, - 0x97, 0xc1, 0xd0, 0xb7, 0xd7, 0x82, 0x31, 0xfd, 0xc2, 0x96, 0xc3, 0x37, - 0xd4, 0x1c, 0xfd, 0x90, 0x47, 0x1c, 0x7e, 0xc6, 0xb0, 0x0d, 0x6f, 0x96, - 0x65, 0x6b, 0x9d, 0xbd, 0x59, 0x13, 0xca, 0x32, 0xc3, 0x29, 0x39, 0xdc, - 0x6c, 0x26, 0x15, 0xc8, 0x83, 0xa8, 0x5d, 0x9d, 0x1d, 0x30, 0x64, 0x65, - 0x05, 0x48, 0xce, 0xaa, 0x69, 0xf7, 0x42, 0xa6, 0x1f, 0x9d, 0xcb, 0xc9, - 0x5b, 0xe7, 0x69, 0xcf, 0x29, 0xd1, 0xa5, 0xcf, 0x55, 0x79, 0xff, 0x6c, - 0xfa, 0xac, 0xb8, 0xec, 0x33, 0x61, 0xc1, 0x33, 0x5c, 0xef, 0x0f, 0x92, - 0x93, 0x4a, 0x83, 0x79, 0x48, 0x21, 0xba, 0xf7, 0xcb, 0x01, 0x63, 0x84, - 0x22, 0xc6, 0xec, 0x8c, 0x66, 0x8d, 0x97, 0x42, 0x56, 0x75, 0x73, 0x61, - 0xcb, 0xfa, 0xd4, 0x20, 0x66, 0xce, 0x6a, 0x81, 0x78, 0xa6, 0xc8, 0x72, - 0xeb, 0x15, 0x25, 0xb2, 0x06, 0xc0, 0xb2, 0xab, 0x18, 0x66, 0x4e, 0x5e, - 0x73, 0x21, 0x55, 0xd6, 0xe3, 0x60, 0x81, 0x56, 0x85, 0x1f, 0x5a, 0xce, - 0xff, 0xc0, 0x6a, 0xd3, 0x18, 0xdd, 0xfd, 0xaa, 0x73, 0x42, 0xb1, 0xd5, - 0x62, 0xda, 0x2e, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, - 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x8c, 0x10, 0x01, - 0x11, 0x00, 0x07, 0x07, 0x01, 0x01, 0x34, 0x00, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x95, 0x4a, 0x33, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x83, 0xb6, - 0x03, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x83, 0xb6, 0x03, 0x03, 0x03, 0xb1, - 0x0a, 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, 0xc7, 0x2e, 0xdb, - 0x0f, 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x7e, 0x0b, 0xaa, 0xec, 0xd2, - 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, 0x20, - 0x84, 0xa7, 0x17, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, 0x12, 0x4e, 0x73, - 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, 0x0d, 0x66, 0x6e, - 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, 0x5b, 0x9a, 0x6f, - 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0xda, 0xde, 0x08, 0x82, 0x7d, - 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, 0xba, 0xe3, 0x73, 0xe9, - 0x35, 0x6f, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, - 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, - 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x15, - 0x67, 0xb2, 0x55, 0xfa, 0x3d, 0xce, 0x31, 0x23, 0xdf, 0x93, 0xad, 0x9c, - 0x09, 0x8d, 0xbc, 0x7e, 0xb3, 0x84, 0x6c, 0x0a, 0x52, 0x6e, 0xab, 0x7d, - 0x13, 0x86, 0xcc, 0xbe, 0xf3, 0x30, 0x0b, 0x08, 0xf8, 0xa1, 0xcf, 0x62, - 0x7a, 0x7e, 0xaf, 0xd7, 0x55, 0x51, 0x92, 0x16, 0x1d, 0x3e, 0x5e, 0x37, - 0x86, 0xf2, 0xea, 0x51, 0xee, 0x6a, 0xe3, 0xa6, 0xe1, 0xc5, 0xce, 0x5f, - 0x86, 0x3e, 0x5a, 0x3d, 0x6d, 0x31, 0xf9, 0x10, 0xe3, 0xd6, 0x77, 0x76, - 0x33, 0x03, 0xfc, 0x2a, 0x0c, 0x45, 0x5c, 0x29, 0xa8, 0x9f, 0x96, 0x45, - 0xd5, 0xae, 0x9f, 0x21, 0x9a, 0x1a, 0x6d, 0x85, 0x4f, 0x3d, 0x35, 0x85, - 0xf1, 0x6a, 0x11, 0xf3, 0x54, 0x3e, 0x96, 0x4c, 0xbf, 0xa6, 0x01, 0xd4, - 0xc8, 0x67, 0xc1, 0x94, 0x16, 0x19, 0x39, 0x42, 0x28, 0xc9, 0x5b, 0x88, - 0x09, 0xbf, 0xba, 0xf2, 0x9b, 0x4f, 0x13, 0x73, 0x8b, 0x2c, 0x98, 0x07, - 0x70, 0xa7, 0x27, 0xae, 0x02, 0xa3, 0x63, 0x11, 0x5b, 0x1b, 0x8c, 0x85, - 0x8e, 0x0f, 0xde, 0xf9, 0x0b, 0x8f, 0x06, 0xfd, 0xab, 0x03, 0x34, 0x52, - 0x23, 0x52, 0x2e, 0xf1, 0xa8, 0x30, 0x89, 0xe8, 0xdc, 0x8f, 0xe4, 0x9f, - 0xd3, 0xa1, 0x09, 0x33, 0x5b, 0x07, 0xc8, 0x9c, 0x49, 0x47, 0x37, 0x53, - 0x35, 0xc5, 0x1e, 0x78, 0x9f, 0xc7, 0x65, 0x94, 0xf6, 0xb9, 0xcf, 0xcc, - 0xee, 0xfc, 0x73, 0x40, 0x42, 0xb8, 0x37, 0x12, 0xfd, 0x34, 0xea, 0xdd, - 0x89, 0x01, 0x51, 0xfe, 0xde, 0xb6, 0xb6, 0x1e, 0x40, 0x39, 0x12, 0xf8, - 0xdd, 0x5c, 0x96, 0xb6, 0x1b, 0x21, 0x08, 0xaf, 0x6e, 0x62, 0xbb, 0x3c, - 0x65, 0xd1, 0xa9, 0x15, 0xb0, 0xf6, 0x1b, 0xbb, 0xac, 0x26, 0xa5, 0x82, - 0xc6, 0x43, 0xa0, 0x88, 0xf1, 0x64, 0x64, 0x01, 0xd9, 0xa9, 0x5e, 0xf0, - 0x73, 0x52, 0xfb, 0xc9, 0x27, 0x81, 0x0e, 0xce, 0x8e, 0x4c, 0xc8, 0x3d, - 0xef, 0xe2, 0xdc, 0xe3, 0xe9, 0x23, 0x3c, 0x47, 0x93, 0xcb, 0x18, 0xe6, - 0x11, 0xe2, 0x40, 0xd7, 0x73, 0x18, 0x6b, 0xbd, 0x77, 0x56, 0x6e, 0x6c, - 0xe8, 0x25, 0xe7, 0xef, 0x12, 0xc7, 0x8f, 0x38, 0x80, 0x0e, 0xd1, 0x97, - 0x71, 0xef, 0xfa, 0x78, 0xac, 0x3d, 0x55, 0x45, 0x83, 0x45, 0x62, 0xb0, - 0x9a, 0xbf, 0x45, 0xd5, 0xbe, 0x45, 0x8a, 0xa2, 0x21, 0x88, 0xb9, 0xd0, - 0x3e, 0x59, 0xbb, 0x68, 0x77, 0xb7, 0x29, 0x65, 0x4a, 0x8d, 0xf4, 0x1d, - 0xf1, 0xd1, 0x00, 0x92, 0x2d, 0xcb, 0x6b, 0xaa, 0x9d, 0x1d, 0x0f, 0xf1, - 0x45, 0x0b, 0x13, 0x47, 0x2b, 0x47, 0x00, 0x30, 0x72, 0x0c, 0xa8, 0xb2, - 0xcb, 0x5b, 0xcd, 0xee, 0x30, 0x8d, 0xdb, 0x62, 0xd1, 0xb5, 0x5f, 0xe1, - 0x3e, 0xf8, 0x96, 0x09, 0x1e, 0x82, 0x2e, 0xf1, 0x8c, 0x20, 0x52, 0x33, - 0x2e, 0x42, 0x5c, 0x64, 0x39, 0xa2, 0x7b, 0x84, 0x2f, 0xff, 0x02, 0x24, - 0xdd, 0x40, 0x23, 0x9c, 0xec, 0xf0, 0xe9, 0x8f, 0x37, 0x15, 0xfd, 0xca, - 0xa5, 0xa6, 0x30, 0x1f, 0x4f, 0xa6, 0xf1, 0x05, 0xd8, 0x2f, 0x0b, 0xbf, - 0xa4, 0x3a, 0x9f, 0x57, 0x31, 0xb3, 0x9d, 0x64, 0xa5, 0xc9, 0x13, 0x64, - 0x7f, 0xb2, 0xe9, 0x38, 0x55, 0xe2, 0xd7, 0x6f, 0xad, 0xe5, 0x77, 0xf9, - 0xbe, 0x17, 0xcc, 0xec, 0xfb, 0xe4, 0xd1, 0x13, 0xa3, 0x20, 0x6e, 0xa6, - 0x64, 0x4e, 0xda, 0xa8, 0x86, 0xfc, 0xc8, 0x29, 0xb9, 0x47, 0xc1, 0xf0, - 0xe1, 0xc9, 0x62, 0x1d, 0x6a, 0x64, 0x8e, 0x1b, 0x76, 0x6a, 0x49, 0x22, - 0xeb, 0xfc, 0x33, 0xbc, 0x27, 0x8c, 0x84, 0x40, 0xe9, 0x3f, 0x46, 0x11, - 0x52, 0xf7, 0xe1, 0xbe, 0xbb, 0x48, 0x31, 0x28, 0x12, 0x62, 0x4a, 0x88, - 0x46, 0xf2, 0x4c, 0x1b, 0x03, 0xa6, 0x6f, 0xd3, 0x58, 0x35, 0x47, 0x24, - 0x53, 0x61, 0xc2, 0xa3, 0x6b, 0xc2, 0x6b, 0x73, 0x96, 0x2b, 0xd0, 0xd9, - 0x7d, 0x8e, 0xf1, 0x1a, 0x24, 0xfd, 0x34, 0x97, 0x02, 0xde, 0x0e, 0x79, - 0x29, 0xd2, 0x61, 0x2b, 0xca, 0x09, 0xea, 0xf2, 0xda, 0x17, 0x07, 0x8e, - 0x39, 0xc5, 0xee, 0x52, 0x76, 0x36, 0xce, 0x40, 0xee, 0xfa, 0x03, 0x40, - 0x9b, 0x91, 0xf6, 0x5e, 0x82, 0x46, 0x3e, 0x91, 0x13, 0xf2, 0x4e, 0x49, - 0x1d, 0x61, 0xf2, 0x6a, 0xcd, 0x5f, 0x06, 0xf0, 0xde, 0x9d, 0x5c, 0x8d, - 0xf5, 0xf6, 0xe5, 0x20, 0x1f, 0x1e, 0xd3, 0x37, 0x6f, 0x4a, 0xf5, 0x9e, - 0x93, 0x25, 0x27, 0xcc, 0x41, 0x53, 0x0c, 0xc7, 0x6b, 0x23, 0x42, 0xe0, - 0x3e, 0xe0, 0xb0, 0x06, 0x64, 0xc2, 0xf2, 0x6b, 0x45, 0x49, 0x25, 0x16, - 0x39, 0x9b, 0x67, 0xf8, 0xa0, 0x2f, 0x38, 0x48, 0x97, 0xd2, 0x59, 0x16, - 0x5b, 0x86, 0x10, 0xdd, 0x92, 0xa2, 0x26, 0x67, 0x46, 0xd8, 0x5f, 0x1a, - 0xe7, 0x16, 0x9f, 0x8e, 0xb5, 0x04, 0x4d, 0x1b, 0x14, 0xaf, 0x3e, 0xf6, - 0xf3, 0x2e, 0x9f, 0xb0, 0x9f, 0x93, 0x2a, 0x9e, 0xae, 0x2f, 0xeb, 0x23, - 0xf8, 0x34, 0xb4, 0x39, 0x0a, 0xbb, 0x58, 0x5a, 0x43, 0x1e, 0xf0, 0x33, - 0x2e, 0x78, 0x62, 0x69, 0xd6, 0x31, 0x01, 0xc2, 0xc9, 0x7e, 0xcd, 0x8f, - 0x2e, 0xab, 0x2d, 0x46, 0x5a, 0xfe, 0xdb, 0x44, 0x2f, 0x83, 0xbf, 0xd2, - 0x1a, 0x77, 0xd4, 0x1c, 0x9d, 0x6a, 0x72, 0xc1, 0xcd, 0x6c, 0x3a, 0x18, - 0xa7, 0x83, 0x71, 0x4a, 0x2b, 0x25, 0x79, 0xea, 0x34, 0x14, 0x7c, 0xe0, - 0xbf, 0xbc, 0x53, 0xf7, 0xa0, 0x5f, 0x70, 0xa8, 0x4e, 0x7d, 0xec, 0x82, - 0x16, 0x1d, 0xa5, 0x1f, 0x4c, 0xc6, 0xe7, 0xc3, 0x81, 0x9f, 0x1b, 0xd3, - 0x13, 0x5b, 0x22, 0x26, 0x1f, 0xc1, 0x63, 0xb0, 0xe7, 0x42, 0xc6, 0x74, - 0x3b, 0xb4, 0xbf, 0xa8, 0xb9, 0xf6, 0xaa, 0x67, 0x59, 0x96, 0x2d, 0xc1, - 0xd0, 0xf4, 0xe8, 0x84, 0xc7, 0x5e, 0xae, 0xca, 0xe8, 0x45, 0x68, 0xa8, - 0xd4, 0x87, 0x2f, 0x81, 0x08, 0x63, 0xd0, 0xb0, 0x5d, 0x04, 0x4d, 0x6a, - 0x72, 0xc4, 0x11, 0xc2, 0x05, 0x32, 0x20, 0xd6, 0x32, 0x44, 0x1d, 0xae, - 0xc9, 0x5d, 0x27, 0x67, 0xeb, 0xed, 0x63, 0xf6, 0x45, 0x25, 0xb8, 0x4c, - 0xf7, 0x63, 0xed, 0x18, 0x02, 0x0b, 0x53, 0x8d, 0x43, 0x45, 0x2f, 0x94, - 0x2f, 0x0f, 0xe9, 0x40, 0x41, 0x10, 0x57, 0x4f, 0x90, 0x29, 0x5b, 0x6e, - 0x8b, 0x72, 0x35, 0x25, 0xf9, 0x8c, 0xf1, 0x82, 0x3a, 0xa6, 0xcc, 0x8a, - 0xed, 0x3d, 0xfe, 0x85, 0xd7, 0xd9, 0x53, 0x42, 0x14, 0x34, 0x38, 0xef, - 0x1a, 0x8a, 0xbd, 0xd2, 0x17, 0x14, 0xac, 0x3e, 0xd8, 0x14, 0x26, 0xe7, - 0xc5, 0xdf, 0xd7, 0xad, 0x5c, 0xc9, 0x23, 0x46, 0x3d, 0xdb, 0xbd, 0xa0, - 0xc9, 0x12, 0x13, 0x9b, 0x45, 0x66, 0x6a, 0x96, 0xc3, 0x8b, 0xc5, 0x0a, - 0xc7, 0x38, 0x2f, 0x98, 0x4a, 0x32, 0x96, 0xbe, 0x14, 0xf7, 0x8b, 0x8d, - 0x45, 0x64, 0xf9, 0x94, 0x53, 0x1a, 0x00, 0x12, 0x9c, 0xc1, 0x0b, 0x7b, - 0x05, 0x3f, 0xaf, 0xc1, 0x79, 0x7f, 0x75, 0x54, 0xec, 0xc3, 0x1d, 0xd9, - 0xb5, 0x27, 0xed, 0xd9, 0x21, 0xfa, 0x42, 0xe5, 0x53, 0x40, 0xe5, 0x3a, - 0x51, 0x78, 0x8a, 0xe2, 0x80, 0xac, 0x5b, 0xff, 0xfd, 0x11, 0x4a, 0x58, - 0xc1, 0xb4, 0x4d, 0xdc, 0xc4, 0xa3, 0x4c, 0x57, 0x3d, 0x77, 0xb2, 0x98, - 0xdc, 0x9f, 0x7d, 0x97, 0x85, 0xd0, 0x16, 0x2a, 0x63, 0x2c, 0x79, 0x1a, - 0xce, 0xcf, 0x0c, 0x3b, 0x24, 0x2a, 0x39, 0x9f, 0x06, 0x1a, 0xc6, 0x49, - 0xf3, 0x86, 0xd4, 0x8d, 0x65, 0x77, 0x02, 0xc6, 0x35, 0x38, 0x97, 0x23, - 0x85, 0x7c, 0x6f, 0x5c, 0x0e, 0x78, 0xdd, 0xe7, 0x48, 0x40, 0xe5, 0x22, - 0xae, 0xef, 0x81, 0x02, 0xec, 0xc7, 0x0f, 0x12, 0x0f, 0x46, 0xd3, 0x7e, - 0x45, 0x17, 0xf7, 0xbe, 0x33, 0x84, 0x20, 0x08, 0xab, 0xdb, 0xa0, 0x01, - 0xcc, 0x8a, 0x0e, 0xfb, 0x81, 0x53, 0x44, 0x48, 0x07, 0xd5, 0x3e, 0xd2, - 0xcd, 0x3e, 0x6d, 0x00, 0x5d, 0x59, 0xeb, 0x15, 0x38, 0xb2, 0x49, 0x0e, - 0x85, 0x52, 0x93, 0x92, 0xd6, 0x27, 0x1f, 0x8f, 0x58, 0x54, 0x08, 0xc1, - 0x15, 0x66, 0x0a, 0x71, 0x6f, 0xe9, 0xf1, 0x5c, 0x3e, 0xcf, 0x9e, 0xde, - 0x1f, 0xdc, 0x79, 0xe9, 0xc1, 0x38, 0xa5, 0x3f, 0xe3, 0x60, 0x53, 0x0f, - 0xe6, 0xb3, 0x18, 0x67, 0x92, 0xff, 0x02, 0xa3, 0x20, 0x99, 0xda, 0xb2, - 0xa3, 0xa5, 0x72, 0x48, 0x1f, 0x76, 0x3e, 0xa2, 0x78, 0x37, 0xc2, 0xbf, - 0x00, 0x93, 0xdc, 0xa4, 0x96, 0xd1, 0xc8, 0xe9, 0xf1, 0xd2, 0xc7, 0x68, - 0x47, 0xdc, 0x36, 0x1c, 0x13, 0x34, 0xbd, 0xd9, 0x36, 0x9b, 0x70, 0x1a, - 0x56, 0x27, 0xd2, 0x7e, 0xe6, 0xd3, 0x74, 0x84, 0x24, 0x78, 0x68, 0xad, - 0x4c, 0x5e, 0xb9, 0xf2, 0x63, 0x80, 0x58, 0xc2, 0x93, 0xef, 0x7e, 0xf1, - 0xf7, 0x46, 0x4f, 0x89, 0xd3, 0x09, 0x07, 0x2c, 0x83, 0x44, 0x57, 0x7c, - 0x6d, 0x38, 0x27, 0x63, 0x22, 0x28, 0x55, 0xf5, 0x3e, 0xcb, 0x4d, 0x4f, - 0x4d, 0x82, 0x27, 0x96, 0x2d, 0xe9, 0x72, 0xeb, 0x86, 0x3a, 0x90, 0xa6, - 0xc4, 0x09, 0x6d, 0xbc, 0x13, 0x64, 0x58, 0x1e, 0xfc, 0xee, 0xee, 0x00, - 0x25, 0x92, 0x8d, 0x0b, 0x16, 0xf2, 0xd1, 0xd3, 0x2a, 0xb6, 0x00, 0xa3, - 0x4c, 0x58, 0xf9, 0x0b, 0x78, 0x9b, 0xc5, 0x11, 0xba, 0xa9, 0x36, 0xd7, - 0x74, 0xdd, 0x49, 0x30, 0x6d, 0x54, 0x6f, 0xb2, 0x0f, 0xf3, 0x7c, 0xc8, - 0x57, 0x55, 0x8e, 0x19, 0x09, 0x62, 0xaf, 0x34, 0x2e, 0x01, 0x65, 0xe3, - 0x15, 0x2c, 0xd6, 0x5f, 0x62, 0x50, 0xbf, 0xe9, 0xf6, 0x4a, 0xa8, 0x14, - 0x15, 0xe1, 0x22, 0xdc, 0x6d, 0x5e, 0x8b, 0x02, 0x86, 0x3d, 0xea, 0xcf, - 0x62, 0x9c, 0x70, 0xb1, 0x9e, 0x2e, 0x40, 0x62, 0x2d, 0x0d, 0x91, 0xac, - 0xaf, 0xcd, 0x3b, 0xa1, 0xf1, 0xfe, 0xaf, 0x16, 0xd4, 0xa3, 0xe5, 0x76, - 0xd9, 0x0e, 0x3e, 0x15, 0x59, 0x5d, 0x01, 0xc7, 0xf7, 0x57, 0xdb, 0x29, - 0x18, 0x03, 0x61, 0x00, 0xc5, 0x4b, 0xb1, 0x16, 0x3a, 0x9e, 0xa5, 0xc5, - 0x87, 0x88, 0x42, 0xda, 0xcd, 0x87, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, - 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, - 0x73, 0x64, 0x6b, 0x75, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x7e, 0x00, - 0x0f, 0x7e, 0x0f, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x06, - 0x01, 0x34, 0x34, 0x29, 0x01, 0x03, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, - 0x12, 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, - 0x0d, 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, - 0x5b, 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0x63, 0x6f, - 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, - 0x02, 0x42, 0x06, 0x01, 0x34, 0x34, 0x33, 0x09, 0x03, 0x2c, 0xf0, 0xfa, - 0xf2, 0x6b, 0xa9, 0x12, 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, - 0x72, 0xa1, 0x3b, 0x0d, 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, - 0x18, 0x44, 0x35, 0x5b, 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, - 0x4c, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x05, 0x00, 0x00, 0x00, - 0x01, 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0f, 0xfb, 0x00, 0x51, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x61, 0x04, 0x23, 0x00, 0x07, 0x07, - 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, - 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, - 0x08, 0x08, 0x09, 0x89, 0x56, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, - 0x2b, 0xa8, 0x0d, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0xdf, - 0xb4, 0xb1, 0x32, 0xb5, 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, - 0x28, 0x81, 0xd3, 0x73, 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, - 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, - 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, - 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, - 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x4e, 0x6b, 0x19, 0x54, 0xf5, 0xf0, 0xaf, 0x61, - 0xfa, 0x1e, 0x1f, 0x1f, 0x5e, 0x17, 0xd3, 0x8e, 0x04, 0x4b, 0xfa, 0x8d, - 0x34, 0x55, 0x45, 0x92, 0xd5, 0xd0, 0xb8, 0x8e, 0x56, 0xe9, 0x39, 0x37, - 0x8e, 0x7d, 0x7e, 0x88, 0x56, 0x30, 0x48, 0x61, 0xb4, 0xed, 0x1e, 0x15, - 0x64, 0xfc, 0xa8, 0xb1, 0x02, 0xbb, 0x9c, 0x14, 0xe9, 0xd1, 0xe0, 0xcf, - 0x40, 0x41, 0x46, 0x5d, 0xb0, 0xda, 0xba, 0x8c, 0x3a, 0x41, 0x12, 0x91, - 0xeb, 0x13, 0xdf, 0x2c, 0x6e, 0x25, 0x75, 0xb3, 0x92, 0xff, 0xb0, 0xa9, - 0xa5, 0xef, 0x3a, 0x4c, 0x6b, 0x54, 0x55, 0x0e, 0x7e, 0x93, 0x16, 0x7f, - 0xe6, 0x22, 0x22, 0x51, 0xe2, 0x22, 0xa4, 0x35, 0x33, 0xec, 0xdc, 0xa8, - 0x73, 0x64, 0x59, 0xc1, 0x4d, 0xad, 0xa0, 0x56, 0xbf, 0xad, 0x45, 0x64, - 0xda, 0xb0, 0x08, 0x4a, 0x82, 0xfc, 0x0d, 0x21, 0xb7, 0x8b, 0x59, 0x90, - 0xac, 0xb2, 0x08, 0x1b, 0x50, 0x82, 0x0c, 0x87, 0xd6, 0x48, 0x5c, 0xdd, - 0x6b, 0x02, 0x7f, 0xab, 0x3e, 0xdc, 0x25, 0x1f, 0x53, 0x49, 0xb5, 0x6d, - 0x0f, 0x0c, 0xbe, 0xae, 0x1d, 0xab, 0x8b, 0x13, 0x9d, 0xd7, 0x6c, 0x91, - 0xaa, 0x90, 0xe8, 0x63, 0x06, 0x6d, 0xa8, 0xf0, 0xea, 0x21, 0xf6, 0xa8, - 0xfd, 0x15, 0x6d, 0x78, 0x66, 0x42, 0xae, 0x4c, 0xa7, 0x7a, 0x85, 0x15, - 0x7d, 0xf9, 0xed, 0x92, 0x1c, 0xde, 0x7c, 0x71, 0xd0, 0x6b, 0x25, 0x24, - 0x22, 0x6b, 0xe4, 0x5e, 0x60, 0xda, 0xbd, 0x95, 0x32, 0x21, 0xe8, 0xb1, - 0xcb, 0x07, 0x1b, 0x08, 0xf5, 0x49, 0x4f, 0x60, 0x8c, 0xe8, 0xb0, 0x71, - 0x2a, 0x8b, 0x91, 0x17, 0x16, 0x93, 0x39, 0x49, 0x8d, 0x47, 0x1f, 0xe8, - 0x2b, 0x12, 0xa6, 0x4f, 0xa1, 0x77, 0x37, 0xe7, 0x39, 0x68, 0x5c, 0x68, - 0x2b, 0xad, 0xa8, 0x3c, 0xa0, 0x8a, 0xf5, 0xb7, 0x51, 0x9f, 0x2d, 0x85, - 0x1a, 0x99, 0x02, 0x4c, 0x84, 0x5f, 0x4d, 0xe6, 0x55, 0x64, 0xd7, 0x5b, - 0x00, 0x48, 0xde, 0xf2, 0x77, 0x39, 0x6e, 0x7b, 0x0e, 0x97, 0x81, 0xd2, - 0x8a, 0x1b, 0x20, 0x30, 0x60, 0xbe, 0x94, 0xf0, 0x09, 0x34, 0xfe, 0x64, - 0xbb, 0xbb, 0xcb, 0x97, 0x91, 0x43, 0x6d, 0x57, 0x45, 0x7d, 0xc5, 0x43, - 0x5a, 0x78, 0x0d, 0xd8, 0xb9, 0xf5, 0x43, 0x13, 0x21, 0xd6, 0x31, 0x6e, - 0x21, 0x9a, 0x3f, 0x8f, 0xe2, 0x57, 0x32, 0xdb, 0x50, 0x61, 0x45, 0x9f, - 0xb9, 0x7b, 0x73, 0x10, 0xb9, 0xd0, 0x66, 0xaf, 0xa0, 0x3a, 0x77, 0x93, - 0x9b, 0xd3, 0x32, 0xb0, 0xda, 0x01, 0x17, 0x90, 0x1a, 0xa5, 0x9f, 0x2b, - 0x9f, 0x8f, 0x93, 0x6e, 0x4d, 0x69, 0x40, 0xec, 0x56, 0x76, 0x61, 0x2d, - 0xcd, 0xdf, 0xc5, 0xfe, 0x9e, 0x26, 0x2f, 0x78, 0x78, 0xab, 0x5a, 0x32, - 0xa6, 0xe9, 0x7a, 0x85, 0x15, 0xc6, 0x2f, 0x10, 0x37, 0x35, 0xf6, 0xfa, - 0xc0, 0xdd, 0xb0, 0xa9, 0xa1, 0x0d, 0x22, 0xc1, 0xab, 0xc8, 0x8c, 0x2a, - 0x77, 0x0b, 0xd3, 0x52, 0xdb, 0x53, 0x33, 0x78, 0xf3, 0xf6, 0x33, 0x5d, - 0x9f, 0xb7, 0xb6, 0x46, 0xf6, 0x79, 0x9e, 0x08, 0x16, 0xd8, 0x48, 0xcf, - 0x70, 0x4d, 0x00, 0x36, 0x30, 0xdb, 0xb3, 0x76, 0xa5, 0x16, 0x78, 0xf8, - 0xaf, 0x71, 0x6b, 0x50, 0x92, 0xfc, 0x52, 0xd6, 0x2c, 0xee, 0xa8, 0xb0, - 0xbe, 0x89, 0x18, 0xc0, 0x7a, 0x72, 0xa5, 0x36, 0x31, 0x7b, 0x86, 0xca, - 0xc0, 0xe4, 0x08, 0x17, 0x1d, 0x6e, 0xe5, 0x4c, 0x82, 0x86, 0x3e, 0x8c, - 0x60, 0xf7, 0x04, 0x8f, 0x2c, 0x64, 0x3d, 0x2e, 0x23, 0x22, 0x10, 0x8e, - 0x88, 0x45, 0xcd, 0x18, 0xd6, 0xba, 0x4c, 0x40, 0x1e, 0x31, 0xfb, 0xbf, - 0xda, 0xe7, 0xae, 0x87, 0x72, 0x81, 0xb2, 0x69, 0x97, 0xe3, 0x2c, 0x5e, - 0xbb, 0x26, 0x1b, 0xe2, 0x83, 0xf3, 0x90, 0x37, 0x0d, 0xb1, 0xa2, 0x58, - 0x88, 0x63, 0xe7, 0x6e, 0x4a, 0xbd, 0x76, 0x90, 0x73, 0x65, 0x85, 0x96, - 0xcc, 0x2d, 0xb7, 0x51, 0x0d, 0xa7, 0x8a, 0xe2, 0x8c, 0x47, 0xb9, 0x44, - 0x09, 0xc3, 0x8f, 0x24, 0x65, 0x79, 0xf0, 0xd0, 0xc3, 0xa5, 0x1f, 0xc3, - 0xca, 0xd7, 0x57, 0xac, 0x1c, 0xcf, 0xa9, 0xfc, 0x81, 0x12, 0x53, 0x0b, - 0xe5, 0x9d, 0x38, 0x29, 0x14, 0xd6, 0xf5, 0x17, 0x06, 0xfb, 0xc2, 0x9d, - 0x25, 0x10, 0xf9, 0xde, 0x4b, 0x33, 0x0d, 0xf1, 0xdd, 0xf5, 0xbc, 0xa8, - 0x2b, 0xdc, 0xdb, 0x51, 0x7d, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, - 0x75, 0x85, 0x41, 0x03, 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, - 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, - 0x16, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0x41, - 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, - 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, - 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, - 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, - 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, - 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xe3, 0xb5, 0xfb, 0x0d, 0xa0, 0x75, 0xd1, 0xa9, 0x33, 0x31, 0xc6, 0x84, - 0xba, 0x58, 0x50, 0xb0, 0x71, 0x32, 0x4f, 0x72, 0x88, 0x46, 0x71, 0x06, - 0xb3, 0x82, 0x5e, 0x30, 0xfd, 0xc8, 0x5b, 0xc8, 0xf3, 0x24, 0x92, 0xe0, - 0xce, 0x8b, 0xf7, 0x50, 0x20, 0xc3, 0xeb, 0x1b, 0xf4, 0xef, 0x4f, 0xfa, - 0x28, 0x4d, 0x02, 0x4d, 0x7c, 0x46, 0xf1, 0x91, 0x89, 0xde, 0xc6, 0xfa, - 0x79, 0xc5, 0xbd, 0x17, 0xa1, 0xc6, 0x1d, 0x8c, 0xd4, 0x57, 0xa6, 0x58, - 0x66, 0xce, 0xe5, 0xb0, 0x8b, 0x54, 0xef, 0x3b, 0x24, 0x9b, 0xa4, 0xc4, - 0x6a, 0xa9, 0xf3, 0x1b, 0x73, 0x37, 0x10, 0xc0, 0xe1, 0xcb, 0xc8, 0x90, - 0x14, 0x88, 0x97, 0x25, 0x8b, 0x7c, 0xa2, 0x66, 0x36, 0x89, 0x55, 0x8d, - 0x68, 0xe7, 0x55, 0x20, 0x10, 0x68, 0x14, 0x2f, 0x05, 0x3b, 0xe3, 0x81, - 0x08, 0xfe, 0x54, 0x7d, 0xa5, 0x51, 0x2a, 0x39, 0x86, 0x11, 0xce, 0x26, - 0x8d, 0xe1, 0xec, 0x30, 0x3f, 0xf9, 0xa3, 0x3d, 0x43, 0x6c, 0xad, 0x23, - 0x54, 0x20, 0x7d, 0x60, 0xa5, 0x42, 0xbd, 0x3d, 0x22, 0xc8, 0x95, 0x9b, - 0xab, 0x5b, 0xf7, 0xc1, 0x11, 0xfb, 0xf1, 0x70, 0xa2, 0x43, 0xcb, 0x53, - 0x8c, 0x18, 0x0d, 0x8a, 0xb2, 0xa5, 0xbd, 0x87, 0x2b, 0x8b, 0xdf, 0x79, - 0x96, 0x29, 0x20, 0x8e, 0x34, 0x4a, 0x45, 0x96, 0x33, 0x8d, 0xa8, 0xb0, - 0x47, 0x26, 0x4f, 0x8b, 0xad, 0xb5, 0xa7, 0x2d, 0x15, 0x58, 0x92, 0x7b, - 0x4b, 0x53, 0xa9, 0x5e, 0x51, 0x39, 0x9c, 0xbd, 0x7e, 0x8f, 0x7f, 0x9f, - 0xb7, 0x38, 0xcd, 0x7e, 0xff, 0x7d, 0x73, 0x1f, 0xab, 0x3a, 0x61, 0xaa, - 0xde, 0x73, 0x28, 0xb2, 0x6f, 0x1e, 0xc9, 0x5e, 0x59, 0x71, 0x6b, 0xe8, - 0x6d, 0x63, 0xf3, 0x9e, 0xdf, 0x52, 0x86, 0x60, 0x1c, 0xbd, 0xc7, 0xeb, - 0xaf, 0x82, 0x83, 0xaa, 0x68, 0xa6, 0x71, 0x7a, 0xe8, 0xd3, 0xd4, 0xc8, - 0xe7, 0x9a, 0xcc, 0x3c, 0xc2, 0xdf, 0x0c, 0x42, 0xe8, 0xae, 0xc7, 0xd8, - 0x1f, 0x66, 0x0a, 0x57, 0x09, 0x14, 0x02, 0x74, 0x9a, 0x7a, 0x07, 0xb3, - 0x19, 0x87, 0x8d, 0xa9, 0x45, 0x25, 0x26, 0x48, 0xb3, 0x20, 0x3c, 0xf7, - 0x5a, 0x1c, 0xae, 0xc7, 0x06, 0x9e, 0x1a, 0x0a, 0x23, 0xf3, 0x39, 0x25, - 0x2c, 0x91, 0x7c, 0x5e, 0x87, 0xe7, 0x55, 0xc4, 0x69, 0xf3, 0x3e, 0xeb, - 0xc5, 0x44, 0xa8, 0xe3, 0xec, 0xc1, 0xfe, 0x70, 0xbf, 0xdd, 0xbb, 0xf0, - 0x22, 0xe1, 0x19, 0xa1, 0x6d, 0x7a, 0x9a, 0xa3, 0x36, 0x90, 0xbc, 0x1a, - 0xa7, 0x37, 0xf8, 0xcf, 0xdc, 0x9e, 0x23, 0x17, 0x42, 0xd5, 0xa0, 0xd3, - 0x36, 0xb0, 0xb1, 0xf5, 0x1a, 0x95, 0xbc, 0xe8, 0x0f, 0xb4, 0x58, 0x76, - 0x40, 0x74, 0xd0, 0x21, 0xaf, 0xae, 0xc6, 0xb4, 0x84, 0xd7, 0xfc, 0x70, - 0x6a, 0x8f, 0x41, 0x57, 0x2b, 0x8e, 0xbc, 0x6b, 0x21, 0x65, 0xcc, 0xa0, - 0x8e, 0xb9, 0x0b, 0x46, 0xef, 0xb3, 0x56, 0xec, 0x8a, 0xd6, 0x4d, 0xdd, - 0x97, 0xbd, 0xdd, 0x65, 0xbf, 0x26, 0xab, 0xba, 0x0d, 0xd1, 0x22, 0x7e, - 0xb6, 0x8a, 0xb4, 0x92, 0xc9, 0xa6, 0x48, 0xd4, 0x64, 0x17, 0xc6, 0xb5, - 0xb9, 0xce, 0x45, 0x6d, 0xf4, 0xd9, 0x3d, 0xa0, 0xb3, 0x86, 0x67, 0x19, - 0xad, 0xd8, 0x32, 0x2b, 0xf7, 0xab, 0x90, 0xee, 0x91, 0x8f, 0x73, 0xe4, - 0xc0, 0x29, 0xde, 0x45, 0x8a, 0xfb, 0xca, 0x74, 0x3b, 0x50, 0xf1, 0x34, - 0x40, 0x36, 0x25, 0x8a, 0xe0, 0xf9, 0x7f, 0x55, 0xc5, 0x59, 0x89, 0xbb, - 0x43, 0x03, 0xa3, 0xdd, 0x8c, 0x83, 0x03, 0xc6, 0xef, 0x60, 0x02, 0xc5, - 0xd8, 0x29, 0x3f, 0x2f, 0x56, 0xba, 0x8b, 0x97, 0x0a, 0xc4, 0xf3, 0x07, - 0x3f, 0xca, 0x0f, 0xdf, 0xb9, 0x5d, 0x59, 0x42, 0x36, 0x02, 0xf7, 0x0f, - 0x03, 0xc8, 0xf2, 0xb7, 0xd8, 0x64, 0xcd, 0x1e, 0xe4, 0xe1, 0xa0, 0xbd, - 0x0f, 0x70, 0xfb, 0xcf, 0x77, 0x77, 0xef, 0x9d, 0xdd, 0xc1, 0x61, 0xab, - 0x3c, 0xdb, 0xe4, 0x35, 0x11, 0xab, 0xde, 0x40, 0x7d, 0x51, 0xba, 0xb1, - 0x7d, 0x13, 0xf1, 0x58, 0x03, 0xca, 0xae, 0x12, 0x4a, 0xa3, 0xb6, 0xed, - 0xd7, 0x18, 0x1c, 0xb6, 0xd8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, - 0x75, 0x89, 0x70, 0x02, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, - 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x91, - 0x62, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x41, - 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x37, 0xee, 0x5a, 0x85, 0xe1, - 0xcb, 0xdd, 0xc8, 0xce, 0x07, 0x77, 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, - 0x30, 0x3a, 0xcd, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, - 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, - 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, - 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xfa, 0x4b, 0x92, 0xea, 0x4b, 0xef, 0xde, 0x03, 0xd5, 0xe2, 0xee, 0xe5, - 0x67, 0xd4, 0x99, 0x63, 0x37, 0x68, 0x91, 0xbc, 0x4f, 0xbc, 0x41, 0xe9, - 0x01, 0xc5, 0x4d, 0x59, 0x2a, 0x9b, 0x42, 0x60, 0x07, 0x7e, 0xc2, 0xbc, - 0x62, 0xcc, 0xbc, 0xa7, 0xf1, 0xe4, 0x20, 0x5f, 0xe3, 0xe8, 0x9f, 0x16, - 0x7a, 0x77, 0xd2, 0xb7, 0xad, 0x98, 0xc3, 0xb4, 0x99, 0xdb, 0x36, 0x1a, - 0xe4, 0xf0, 0xfc, 0xe1, 0xc8, 0x2f, 0x8c, 0xcf, 0x6f, 0x97, 0x48, 0x09, - 0x4a, 0xae, 0xc7, 0xf9, 0xfb, 0xb7, 0x5f, 0x64, 0x6a, 0x79, 0xa1, 0x27, - 0xeb, 0x59, 0x7d, 0x0a, 0xd3, 0x56, 0x27, 0x1d, 0x56, 0xd3, 0x62, 0x1e, - 0x7f, 0xb5, 0x0f, 0x50, 0x9c, 0x4d, 0x1d, 0xd5, 0x53, 0xcb, 0x08, 0x07, - 0x56, 0x93, 0x9e, 0x4f, 0xb2, 0xd0, 0x12, 0xc7, 0x50, 0xcf, 0x99, 0xac, - 0x24, 0xdb, 0x94, 0xab, 0x08, 0x89, 0x60, 0x2f, 0x6c, 0xd0, 0xc2, 0x2e, - 0x6d, 0x08, 0xe0, 0xf9, 0xfc, 0x7e, 0x5b, 0x54, 0x92, 0xaa, 0x01, 0xfd, - 0xf6, 0x49, 0xb1, 0xfc, 0xd4, 0x51, 0x83, 0x73, 0xaf, 0xac, 0x38, 0x78, - 0x8e, 0x9b, 0x42, 0x4e, 0x83, 0xbb, 0x9d, 0xd7, 0x5c, 0xdb, 0x73, 0xd3, - 0x3d, 0x2c, 0xe2, 0x4c, 0x57, 0xa4, 0xfa, 0xdf, 0x53, 0x44, 0x29, 0x71, - 0x22, 0xb6, 0x89, 0x84, 0x80, 0xca, 0xcb, 0x7c, 0x5f, 0x15, 0x19, 0x4b, - 0x06, 0x28, 0x5d, 0x4a, 0x9b, 0xc8, 0x59, 0xa7, 0x9e, 0xa2, 0xba, 0x32, - 0x5d, 0xf2, 0xcb, 0xa9, 0xc6, 0xba, 0x09, 0xee, 0xd2, 0x00, 0x32, 0x53, - 0x8b, 0x39, 0xff, 0xc4, 0x63, 0xac, 0xbc, 0x1c, 0x15, 0xb8, 0x79, 0xc2, - 0xe3, 0xda, 0x8d, 0xb2, 0x95, 0x8d, 0x3c, 0x10, 0xec, 0x93, 0x03, 0xc1, - 0x07, 0x84, 0x47, 0xf3, 0xeb, 0xe3, 0x10, 0x33, 0xa1, 0x2e, 0xc6, 0x48, - 0x44, 0x2c, 0x38, 0x36, 0xe1, 0x68, 0x3c, 0xe8, 0x0d, 0x5c, 0x8a, 0xdc, - 0x1f, 0xe8, 0x3b, 0xb2, 0x0f, 0xea, 0x27, 0x18, 0x7a, 0x7f, 0x82, 0x6a, - 0x96, 0xfa, 0x63, 0xd3, 0x5c, 0xbf, 0xf6, 0x1d, 0x9e, 0xf2, 0xd9, 0x83, - 0x3b, 0xf0, 0x1b, 0x29, 0x49, 0x8d, 0xb3, 0xdc, 0x60, 0x47, 0x9d, 0x2b, - 0xac, 0xd6, 0x6e, 0x59, 0xb3, 0x09, 0x0d, 0xa7, 0xfb, 0x0e, 0x43, 0x56, - 0xa3, 0x80, 0x2c, 0x9f, 0xc1, 0xe8, 0xd2, 0xef, 0x05, 0xc5, 0x25, 0x4c, - 0x5b, 0x67, 0x1a, 0x54, 0x0b, 0x55, 0x83, 0x3d, 0xfb, 0x38, 0x0e, 0xd2, - 0xc0, 0x1a, 0xcd, 0x9f, 0x81, 0x3e, 0x6d, 0x7f, 0xe4, 0x3f, 0x34, 0x0c, - 0xdc, 0x99, 0x5a, 0x77, 0xd4, 0xe4, 0xff, 0x4a, 0x7b, 0x8a, 0x95, 0xe4, - 0x46, 0x3d, 0x7b, 0xc4, 0x0e, 0xdd, 0xc7, 0x2d, 0xf4, 0xfa, 0x5e, 0x50, - 0xae, 0x9c, 0xca, 0x64, 0x97, 0xad, 0x03, 0x30, 0x3e, 0x05, 0xc4, 0x33, - 0x1e, 0x2c, 0x03, 0x2b, 0x06, 0x2c, 0x79, 0x13, 0xae, 0x1b, 0x65, 0xf1, - 0x1f, 0xb9, 0xe4, 0x8a, 0x06, 0x96, 0xea, 0xc4, 0x6e, 0x17, 0x19, 0x03, - 0x54, 0xe8, 0x39, 0xe7, 0xeb, 0x7b, 0xbc, 0x25, 0xd6, 0x55, 0x6c, 0x76, - 0x5f, 0xf7, 0xd2, 0x0e, 0x54, 0x46, 0x9f, 0x5d, 0xa4, 0x3d, 0xac, 0xa1, - 0x19, 0x7b, 0x7c, 0x5a, 0x44, 0x54, 0x65, 0x5d, 0x43, 0x26, 0x5f, 0x47, - 0x63, 0x2b, 0x00, 0xe3, 0xb4, 0xe9, 0x70, 0x8c, 0x31, 0x50, 0x7c, 0x37, - 0x01, 0x43, 0x6c, 0x29, 0xc3, 0xae, 0x59, 0xb7, 0x0b, 0xb9, 0x9a, 0x72, - 0x69, 0xe0, 0xd1, 0xb0, 0x47, 0x53, 0xf0, 0xb8, 0x8b, 0xc8, 0x80, 0x3c, - 0x58, 0xfa, 0x34, 0xf2, 0x44, 0x27, 0xb7, 0xfc, 0x44, 0x73, 0xfb, 0xe5, - 0xe1, 0x8b, 0xdb, 0x2b, 0xc5, 0x73, 0x97, 0x25, 0xb3, 0xef, 0x16, 0xfd, - 0xba, 0x08, 0x3d, 0x15, 0x2a, 0x03, 0xb5, 0x4d, 0x2a, 0x8c, 0xf5, 0x53, - 0x11, 0x97, 0x3c, 0x35, 0x66, 0x1d, 0x59, 0xc8, 0xc9, 0x79, 0x48, 0x6d, - 0x19, 0x4f, 0xa7, 0x07, 0x25, 0x4d, 0xb2, 0xfc, 0x1e, 0xbc, 0x9a, 0x0c, - 0x6e, 0x46, 0x2b, 0x58, 0x45, 0xbe, 0xe7, 0x8e, 0x09, 0xa5, 0xa0, 0xd3, - 0x5a, 0xf5, 0x6e, 0x92, 0x7b, 0x5b, 0x21, 0x07, 0xab, 0xf3, 0x57, 0xd6, - 0x93, 0x4b, 0x56, 0x3b, 0x9c, 0x3c, 0x4b, 0x85, 0xb0, 0x62, 0x18, 0x3e, - 0x7c, 0xc5, 0x25, 0xe2, 0xf2, 0xfc, 0xa3, 0xca, 0x88, 0xd6, 0xb2, 0x01, - 0x11, 0xcd, 0x93, 0x9a, 0x76, 0x84, 0xc2, 0x2d, 0x07, 0xd3, 0xbb, 0xac, - 0x99, 0xde, 0x29, 0x00, 0xf7, 0x3d, 0x06, 0xea, 0xdc, 0x88, 0xfd, 0xc6, - 0x6e, 0xf5, 0x55, 0x64, 0x73, 0x4e, 0x3b, 0xa9, 0x24, 0x44, 0x63, 0x1c, - 0x50, 0x29, 0x66, 0xc4, 0x74, 0x70, 0xcb, 0xd8, 0x57, 0x0c, 0x60, 0x50, - 0x6d, 0x64, 0x64, 0xd1, 0x53, 0xef, 0x62, 0xef, 0x61, 0xf4, 0xe2, 0xfe, - 0x4c, 0xaa, 0x9f, 0xe9, 0x81, 0x01, 0xe1, 0x97, 0xaa, 0xc0, 0x06, 0xbf, - 0x40, 0x19, 0x64, 0x24, 0x6e, 0x80, 0x73, 0x00, 0x5c, 0x86, 0x3e, 0xc2, - 0xcf, 0x8c, 0x09, 0xc0, 0xfa, 0x4a, 0xb3, 0x3a, 0x0d, 0x81, 0x1d, 0x49, - 0x58, 0x09, 0xe8, 0x31, 0x0e, 0xd7, 0x60, 0x8d, 0x9d, 0xfe, 0x9f, 0x35, - 0xf7, 0x8d, 0xa1, 0x12, 0x04, 0xb2, 0x47, 0xac, 0x31, 0x92, 0x03, 0x0a, - 0x10, 0x50, 0xb7, 0x86, 0x3d, 0xcd, 0x15, 0x8f, 0x25, 0x93, 0x24, 0x7a, - 0x5f, 0xa0, 0x3c, 0x41, 0xaa, 0xb2, 0x96, 0xce, 0xd3, 0x0c, 0xe9, 0x55, - 0x66, 0x37, 0x5c, 0xf3, 0x02, 0x3c, 0xa1, 0x09, 0xa4, 0x9e, 0x90, 0xc9, - 0x82, 0xab, 0xd4, 0x04, 0x2e, 0x8b, 0xb4, 0x8d, 0x5b, 0xcc, 0x19, 0x5a, - 0xfe, 0x86, 0x9c, 0x6c, 0x56, 0x09, 0x86, 0x36, 0xef, 0xe8, 0x1f, 0x3a, - 0xbc, 0xda, 0x4c, 0x68, 0xac, 0xa2, 0x1b, 0xd1, 0x23, 0x75, 0x28, 0xed, - 0x9f, 0x84, 0x2e, 0x40, 0x57, 0x5f, 0x0a, 0x85, 0xe4, 0x77, 0x59, 0x53, - 0x12, 0x32, 0xd6, 0x3c, 0x1b, 0xaf, 0x95, 0xa1, 0x1c, 0x14, 0x1a, 0x42, - 0x7d, 0xc7, 0x7b, 0x21, 0xd1, 0x4e, 0xb9, 0x29, 0x85, 0xef, 0xa2, 0x61, - 0x1c, 0xe5, 0x16, 0x44, 0xbe, 0xfb, 0xa3, 0x21, 0x4f, 0x94, 0x70, 0xff, - 0x5c, 0xc2, 0x1d, 0x0b, 0x39, 0x36, 0x84, 0x0e, 0x61, 0xe2, 0x1c, 0x63, - 0x74, 0xe0, 0x30, 0x01, 0xbe, 0x39, 0x0f, 0x6f, 0xe6, 0x29, 0xad, 0xd8, - 0x8c, 0xdd, 0x8b, 0x24, 0x38, 0x6f, 0x67, 0x8a, 0x2d, 0x82, 0x1e, 0x8e, - 0x45, 0xcb, 0xec, 0x2d, 0xe3, 0xb4, 0x03, 0x8e, 0x46, 0x2e, 0x01, 0xb0, - 0xca, 0x4f, 0xe0, 0x2c, 0x52, 0xd3, 0x4c, 0xdd, 0xd6, 0x62, 0xf3, 0x38, - 0x3f, 0x3c, 0xc1, 0x58, 0xaa, 0x87, 0x3d, 0x4f, 0xb2, 0xb1, 0x54, 0x65, - 0xdc, 0x1c, 0xc8, 0x16, 0x88, 0x15, 0x53, 0xb0, 0x4e, 0x77, 0xae, 0xe0, - 0x34, 0x18, 0x36, 0x34, 0x31, 0x74, 0x4c, 0x79, 0x0f, 0x2b, 0x1a, 0x11, - 0x06, 0x06, 0xaa, 0x60, 0x31, 0x6e, 0x65, 0x9e, 0x1b, 0xb0, 0x61, 0xd6, - 0x90, 0xd1, 0x1d, 0x4c, 0x36, 0xfe, 0xec, 0x26, 0xcc, 0xba, 0xce, 0xd7, - 0xe7, 0x0c, 0x53, 0x90, 0xe8, 0xce, 0xce, 0xed, 0x58, 0x37, 0x37, 0x3f, - 0x40, 0x39, 0xeb, 0x8c, 0xfb, 0x7d, 0x93, 0xa2, 0x26, 0x4e, 0xbf, 0x49, - 0xe7, 0x95, 0xc0, 0x12, 0x6a, 0xec, 0xfb, 0xbe, 0x00, 0x62, 0xb9, 0xc9, - 0x0d, 0x5a, 0x37, 0xf9, 0xae, 0x84, 0x95, 0x89, 0x20, 0x47, 0x48, 0xf6, - 0xf8, 0x73, 0x92, 0x5f, 0xe1, 0x4a, 0xb4, 0x9e, 0xd8, 0x75, 0xf3, 0x38, - 0x48, 0xe1, 0x29, 0x95, 0x0d, 0x74, 0x6b, 0x98, 0x96, 0x6e, 0xc9, 0x3f, - 0xfc, 0x44, 0x91, 0x4d, 0xf4, 0x4c, 0xb7, 0x38, 0xd7, 0xec, 0xbf, 0xf6, - 0x78, 0x05, 0x7d, 0x1b, 0xe5, 0x68, 0x8a, 0xbc, 0x6a, 0x6a, 0x29, 0xb6, - 0xc6, 0x9a, 0x8d, 0x7a, 0x0e, 0x00, 0x80, 0x73, 0xf5, 0x88, 0x5d, 0x2a, - 0xa2, 0x60, 0x98, 0x1e, 0xf5, 0x06, 0x3b, 0xef, 0xa9, 0x46, 0x6b, 0x89, - 0x24, 0xb0, 0xf4, 0x34, 0x42, 0x15, 0x87, 0xd3, 0xc9, 0x36, 0xe0, 0x52, - 0x5f, 0x57, 0x8e, 0x65, 0x5c, 0x7f, 0x7c, 0xf2, 0x66, 0xd8, 0xd1, 0xbf, - 0x13, 0x95, 0x65, 0xb0, 0x7a, 0xa0, 0xbb, 0xee, 0xc9, 0x20, 0xff, 0x26, - 0xda, 0xa0, 0x61, 0x65, 0xd5, 0x3c, 0xdf, 0xb5, 0xf0, 0xd2, 0x02, 0x4f, - 0x97, 0x65, 0x48, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, - 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x8a, 0x11, 0x01, 0x23, - 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, - 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x92, 0x1a, 0x33, 0x13, 0x41, 0xb7, - 0x59, 0x5c, 0x4b, 0x89, 0xf6, 0xba, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, - 0xf6, 0xba, 0xb1, 0x0a, 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, - 0xc7, 0x2e, 0xdb, 0x0f, 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x64, 0x14, - 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, - 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, - 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, - 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, - 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x12, 0x83, 0x28, 0x8c, 0xcd, - 0x78, 0x8c, 0x1b, 0x02, 0xa2, 0x38, 0xa7, 0x25, 0xc1, 0x25, 0x59, 0xcd, - 0x36, 0xb2, 0x21, 0xa1, 0x91, 0xd0, 0xc3, 0x54, 0x89, 0x64, 0xa8, 0x3d, - 0x07, 0xcb, 0x8f, 0xf7, 0xa6, 0x55, 0xc2, 0x96, 0xf6, 0x35, 0xc1, 0x67, - 0xdf, 0x2f, 0x1f, 0xda, 0xa8, 0xf8, 0x8c, 0xc9, 0xa7, 0x5e, 0x7f, 0x1f, - 0xa8, 0xd3, 0x38, 0x57, 0xa2, 0xf4, 0x57, 0x32, 0x17, 0xe3, 0x06, 0xe3, - 0xb6, 0x56, 0x60, 0x6e, 0xbe, 0x12, 0x60, 0x00, 0xfd, 0xa8, 0x4c, 0x3f, - 0x2b, 0x54, 0x9c, 0xfb, 0x87, 0x8b, 0xfa, 0x9e, 0xb8, 0xb2, 0x80, 0x36, - 0xf1, 0x5b, 0xcd, 0x9d, 0x74, 0xa1, 0x7b, 0xbf, 0xf6, 0x4c, 0x64, 0x58, - 0x67, 0x8b, 0x68, 0x05, 0x15, 0x7e, 0x4b, 0x54, 0xe9, 0x84, 0x59, 0x70, - 0x42, 0x80, 0x67, 0x6c, 0x45, 0x62, 0x12, 0x03, 0x27, 0x2b, 0x32, 0xdc, - 0x78, 0x85, 0x3d, 0x74, 0x28, 0x89, 0x5c, 0x33, 0x15, 0x79, 0x63, 0x1f, - 0xd7, 0x26, 0xbf, 0x5d, 0xf6, 0xb1, 0xb7, 0x9e, 0x37, 0x86, 0xd8, 0xf6, - 0xf9, 0xc3, 0x66, 0x90, 0x50, 0x5a, 0x0e, 0xeb, 0xcc, 0xe0, 0xf2, 0x19, - 0xbb, 0xd7, 0x6a, 0xe4, 0xea, 0x87, 0xf9, 0x17, 0x20, 0x88, 0xf6, 0xc0, - 0xc7, 0xb7, 0x55, 0x25, 0xef, 0x15, 0xec, 0xc5, 0x80, 0x52, 0x9a, 0x92, - 0xdb, 0x32, 0xf3, 0xc2, 0xa2, 0x55, 0xd6, 0xd9, 0x5b, 0xe6, 0xb1, 0x95, - 0x18, 0x2b, 0xf8, 0x94, 0x21, 0x56, 0x29, 0x30, 0xf3, 0x61, 0x39, 0x22, - 0x03, 0x86, 0xce, 0x81, 0x6d, 0x9e, 0xdb, 0x5b, 0x49, 0xdb, 0x2c, 0x1d, - 0x0d, 0x45, 0xa9, 0xb3, 0x1c, 0x1a, 0x43, 0x36, 0x1d, 0xd2, 0x76, 0x28, - 0x27, 0xe0, 0xd3, 0x19, 0x56, 0xd3, 0x52, 0xb2, 0xa0, 0x9c, 0xda, 0xb7, - 0xac, 0x4d, 0xb1, 0x98, 0x22, 0xa5, 0x86, 0x5d, 0x79, 0x6a, 0x69, 0x06, - 0xd7, 0x07, 0xe7, 0x44, 0x55, 0x6c, 0xc7, 0xd0, 0x8a, 0x2b, 0xa1, 0x45, - 0xc6, 0xbf, 0xf3, 0x21, 0x2e, 0x41, 0x5c, 0x84, 0xa2, 0x77, 0x46, 0x65, - 0x80, 0x75, 0xba, 0x49, 0xd6, 0xd7, 0x73, 0xeb, 0x35, 0x2c, 0x46, 0x58, - 0xc4, 0x1d, 0x2f, 0x6b, 0xe6, 0x6c, 0xa7, 0x5f, 0x95, 0x0c, 0xbc, 0x60, - 0x00, 0x3d, 0xa9, 0x0a, 0xd6, 0x0a, 0x66, 0x59, 0xc0, 0x9b, 0x49, 0x5b, - 0x4c, 0x73, 0xf5, 0x9e, 0x6d, 0x38, 0xdd, 0x0f, 0x25, 0xe4, 0x35, 0x84, - 0x34, 0x25, 0xfe, 0x71, 0x35, 0x78, 0xa7, 0x5b, 0xc1, 0x7a, 0xab, 0xd7, - 0xeb, 0x2f, 0x54, 0x93, 0x94, 0x49, 0x8a, 0x1e, 0x04, 0xe6, 0xfc, 0xd7, - 0xe3, 0xa2, 0x41, 0x25, 0x5a, 0xa5, 0x46, 0x59, 0x85, 0xfb, 0x21, 0xc7, - 0x02, 0x48, 0x79, 0xd4, 0xef, 0xc4, 0x03, 0xc2, 0x0a, 0x4b, 0x42, 0x1c, - 0x73, 0x35, 0xcd, 0x21, 0x8b, 0xd5, 0xfc, 0xa3, 0xdc, 0xbb, 0x4b, 0xa3, - 0x45, 0x04, 0x73, 0xa1, 0xdb, 0x3a, 0x97, 0x0e, 0xc7, 0x1c, 0xe2, 0x67, - 0x04, 0xd4, 0x49, 0x68, 0x0e, 0x05, 0xcb, 0x52, 0xd4, 0x37, 0x75, 0xd8, - 0x2a, 0x17, 0xd3, 0x7a, 0x93, 0x96, 0x46, 0xfb, 0x07, 0x6d, 0x3b, 0x92, - 0x60, 0xf4, 0x35, 0x94, 0x3b, 0xbd, 0x2e, 0xf6, 0x0b, 0x18, 0xd5, 0x0d, - 0x1b, 0xe1, 0xd3, 0x14, 0xc1, 0x84, 0xd7, 0x67, 0xd7, 0x96, 0x2d, 0xa9, - 0xab, 0x59, 0x70, 0x43, 0x7b, 0xea, 0x25, 0xa3, 0x05, 0x1c, 0x45, 0xf6, - 0x34, 0x51, 0x8e, 0xaf, 0x46, 0x33, 0x90, 0x68, 0x28, 0x4f, 0x38, 0x5b, - 0xbb, 0x69, 0xee, 0xbb, 0x0a, 0x4c, 0x76, 0x1c, 0x3d, 0xfd, 0xea, 0x1f, - 0x77, 0x9e, 0xd4, 0xa1, 0xeb, 0x74, 0x16, 0x60, 0x20, 0xe9, 0x44, 0xc1, - 0x90, 0x2c, 0x7b, 0x77, 0x6f, 0x70, 0xe3, 0x62, 0x0f, 0xc3, 0x20, 0xf6, - 0xce, 0xc3, 0xa6, 0x0e, 0x9c, 0x6d, 0xa3, 0xa0, 0x21, 0x1c, 0x28, 0x7f, - 0x44, 0xd7, 0xa9, 0x87, 0x62, 0x91, 0x4d, 0x2a, 0x93, 0xe2, 0xc7, 0x94, - 0x0c, 0x75, 0x1d, 0xf6, 0xc7, 0xf8, 0x36, 0x09, 0xa8, 0x23, 0xa3, 0x80, - 0x52, 0x2d, 0xe7, 0x0b, 0x44, 0x5d, 0x4b, 0xf5, 0xdc, 0x57, 0xa3, 0x02, - 0x40, 0x89, 0xdc, 0x40, 0xf7, 0x5c, 0xad, 0xea, 0x5c, 0x1a, 0x59, 0xfc, - 0xb8, 0xaf, 0xcb, 0x71, 0xe0, 0x08, 0xdc, 0x80, 0x08, 0x8a, 0x32, 0x85, - 0x46, 0xa9, 0x9a, 0x17, 0x6b, 0x25, 0x9c, 0xfe, 0x7d, 0x90, 0x22, 0x6e, - 0x7b, 0x01, 0x24, 0x17, 0xf6, 0xa7, 0x70, 0x93, 0x03, 0x60, 0xc2, 0x0d, - 0x7b, 0x3b, 0xe8, 0x5b, 0x02, 0xb0, 0x6d, 0x00, 0x62, 0x97, 0x1b, 0x84, - 0x86, 0x27, 0x72, 0x2d, 0x90, 0xee, 0xdc, 0xb6, 0xb8, 0xa5, 0x58, 0x73, - 0x29, 0x9b, 0x06, 0x99, 0xda, 0x4f, 0x12, 0x0c, 0x74, 0x0a, 0xc1, 0x1b, - 0x34, 0x20, 0xfa, 0x6d, 0x01, 0xd2, 0x1b, 0xf2, 0x0f, 0xe3, 0xfe, 0x34, - 0x2d, 0x44, 0x4f, 0xa3, 0x6a, 0xab, 0xaa, 0x7e, 0x1c, 0x35, 0xef, 0xfe, - 0xa0, 0xc1, 0x8a, 0xeb, 0x77, 0x80, 0xd6, 0x57, 0x20, 0x2e, 0x2b, 0xeb, - 0x67, 0xa0, 0x82, 0x86, 0xc8, 0x0e, 0x70, 0x76, 0x74, 0x52, 0x3e, 0x67, - 0x96, 0xf0, 0x48, 0x3f, 0x9b, 0xdc, 0x5f, 0x36, 0xd9, 0xae, 0x3a, 0xcb, - 0x57, 0x5d, 0xe0, 0x7c, 0x03, 0xa9, 0xe8, 0x88, 0x13, 0x6a, 0x70, 0x94, - 0x4b, 0xf5, 0x92, 0x8f, 0xc0, 0x34, 0x49, 0x3f, 0xf7, 0xe1, 0x59, 0xc4, - 0xf2, 0xae, 0x7a, 0x88, 0x58, 0x39, 0x74, 0x39, 0x6d, 0xaf, 0x7a, 0xec, - 0xaf, 0x44, 0x0e, 0x11, 0x7d, 0xa8, 0x3c, 0x50, 0x5b, 0x64, 0x8d, 0x8a, - 0x21, 0x59, 0xc6, 0x8c, 0x6c, 0xce, 0x05, 0xad, 0x1c, 0x2f, 0x5e, 0x4a, - 0xa3, 0x2a, 0x46, 0x3a, 0xaa, 0x12, 0x7e, 0xcc, 0x82, 0xb6, 0x62, 0xba, - 0xe6, 0x1a, 0x52, 0xc6, 0xe3, 0x96, 0x71, 0xf6, 0x81, 0x21, 0x46, 0xd0, - 0x3f, 0x5d, 0xa1, 0x37, 0x8b, 0xf5, 0xc7, 0x8c, 0x28, 0xf0, 0x2e, 0xe8, - 0x44, 0x25, 0x48, 0x27, 0x8e, 0x2f, 0x65, 0x83, 0xed, 0xf5, 0xb6, 0x9f, - 0x02, 0xa7, 0x1b, 0x1e, 0x90, 0x01, 0x55, 0x88, 0xe5, 0xdf, 0x0e, 0x7e, - 0x16, 0x66, 0xa1, 0xc6, 0x07, 0xf6, 0xb5, 0x84, 0x8d, 0x60, 0x6b, 0xe2, - 0xad, 0xbd, 0x18, 0x39, 0xe5, 0xd2, 0xd9, 0xe0, 0xab, 0xc2, 0xac, 0x2f, - 0x36, 0x24, 0x03, 0x69, 0x4c, 0xf9, 0xf3, 0x67, 0x8f, 0xf6, 0x8b, 0xde, - 0xf9, 0x7c, 0x14, 0xfa, 0x97, 0xc3, 0xe5, 0xc1, 0x7d, 0xcf, 0x16, 0x24, - 0x26, 0xda, 0xde, 0x5c, 0x70, 0x96, 0x90, 0xd9, 0x06, 0x2f, 0xf9, 0x61, - 0xa3, 0x47, 0x19, 0x50, 0x5e, 0xe2, 0xb6, 0x74, 0x5e, 0x55, 0xe6, 0x89, - 0xaa, 0xde, 0x19, 0x27, 0x26, 0x47, 0x95, 0x7b, 0xf0, 0x09, 0x21, 0xa9, - 0xf3, 0xf2, 0xf0, 0xbc, 0x1a, 0xa2, 0x25, 0x77, 0x3f, 0x8a, 0x57, 0x20, - 0xfc, 0x48, 0x45, 0xd8, 0x8b, 0xcb, 0x33, 0x04, 0x10, 0x1d, 0xc6, 0x4b, - 0x4c, 0xe4, 0x92, 0x1f, 0xef, 0x27, 0x5e, 0xd5, 0xac, 0xab, 0xcc, 0x69, - 0xbe, 0xd6, 0x35, 0x0e, 0x0d, 0x96, 0x99, 0x3b, 0x67, 0x8d, 0x33, 0xa0, - 0xe3, 0x16, 0xcc, 0x4a, 0x29, 0x80, 0xc8, 0x47, 0xd1, 0x0c, 0xb1, 0xa0, - 0xc1, 0xbe, 0xcc, 0x16, 0xab, 0xf7, 0xee, 0x8a, 0x77, 0xef, 0xca, 0x08, - 0x82, 0x0a, 0x9e, 0x11, 0xcf, 0x3c, 0xbb, 0x1b, 0x44, 0x96, 0xd1, 0x5e, - 0x65, 0xf9, 0xe7, 0xc7, 0xa1, 0x94, 0x42, 0xa9, 0x0e, 0x36, 0x9a, 0x5b, - 0x7f, 0xf0, 0x91, 0x95, 0xeb, 0xd1, 0xb6, 0x1d, 0x18, 0x44, 0x93, 0xa4, - 0xc1, 0x31, 0x97, 0x07, 0x09, 0x9b, 0x50, 0xae, 0xf3, 0x74, 0x7f, 0xbe, - 0x0d, 0xc2, 0xc3, 0x11, 0x8f, 0xa1, 0xea, 0x1f, 0x4e, 0x84, 0x94, 0x18, - 0x7e, 0x7c, 0xbd, 0xe6, 0xc9, 0x78, 0x0e, 0x39, 0x1e, 0x1a, 0x71, 0xc4, - 0xbc, 0x5c, 0x99, 0x76, 0xf7, 0x26, 0x66, 0x9c, 0x8f, 0xd4, 0xad, 0xa9, - 0x6e, 0x96, 0xb9, 0x54, 0x5b, 0xae, 0xa2, 0x0d, 0x94, 0xa8, 0x5a, 0x34, - 0xc3, 0xdb, 0x52, 0x59, 0x3f, 0xdd, 0x53, 0x72, 0xfc, 0xf6, 0x1d, 0x3c, - 0xe0, 0x1f, 0x4a, 0xee, 0xf5, 0x74, 0xa5, 0x95, 0x7a, 0x5d, 0x75, 0xbd, - 0x27, 0x4a, 0x49, 0x18, 0xcf, 0xf0, 0xe5, 0x32, 0x4f, 0x1b, 0xa0, 0xeb, - 0x00, 0x19, 0x21, 0xbd, 0xf7, 0xf5, 0x4b, 0x47, 0x1d, 0x3b, 0x8b, 0xe6, - 0xca, 0xdc, 0xb6, 0x52, 0x41, 0xa7, 0xab, 0x68, 0xb3, 0xfb, 0x8f, 0x40, - 0xc3, 0x59, 0xd9, 0x2d, 0x13, 0x3a, 0x99, 0x93, 0x9f, 0xa6, 0x90, 0xdd, - 0x65, 0x17, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x00, 0x00, 0x00, 0x1d, 0x04, - 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x6a, 0x00, 0x0f, 0x2a, 0x0e, 0xaa, - 0x0f, 0x6a, 0x0f, 0xb3, 0x0e, 0xea, 0x0e, 0x6a, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x0c, 0x09, 0x34, 0x34, 0x08, - 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, - 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, - 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, - 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, - 0x05, 0x00, 0x05, 0x00, 0x69, 0x63, 0x68, 0x61, 0x74, 0x06, 0x3f, 0x0c, - 0x08, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0xfc, - 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, - 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, 0x05, 0x00, 0x69, 0x63, 0x68, 0x61, - 0x74, 0x05, 0x3f, 0x0c, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, - 0x08, 0x17, 0x01, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, - 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, - 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, - 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, - 0x69, 0x63, 0x68, 0x61, 0x74, 0x04, 0x3f, 0x0c, 0x08, 0x34, 0x34, 0x08, - 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0x9b, 0x66, 0x83, 0xaf, 0x24, - 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, - 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, - 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, - 0x01, 0x00, 0x01, 0x00, 0x69, 0x63, 0x68, 0x61, 0x74, 0x03, 0x48, 0x0c, - 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x29, 0x01, 0x64, - 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, - 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x63, 0x6f, 0x6d, 0x2e, - 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x02, 0x4c, - 0x0c, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x33, 0x09, - 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, - 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, - 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, - 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x6c, 0x6f, 0x63, - 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xfb, 0x00, - 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x01, 0x05, 0x0a, 0x00, 0x00, 0x00, - 0x02, 0x0f, 0xf7, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x03, 0x03, 0x00, 0x09, - 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xcf, 0x00, 0x0f, 0xe8, 0x0f, 0xcf, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0x7e, 0x0b, 0xaa, 0xec, 0xd2, - 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, 0x20, - 0x84, 0xa7, 0x17, 0x02, 0x17, 0x03, 0x34, 0x09, 0x7e, 0x0b, 0xaa, 0xec, - 0xd2, 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, - 0x20, 0x84, 0xa7, 0x17, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xcf, 0x00, - 0x0f, 0xe8, 0x0f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0xda, - 0xde, 0x08, 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, - 0xba, 0xe3, 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x02, 0x17, 0x03, 0x34, 0x09, - 0xda, 0xde, 0x08, 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, - 0xf4, 0xba, 0xe3, 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x0a, 0x00, 0x00, 0x00, - 0x02, 0x0f, 0xcf, 0x00, 0x0f, 0xe8, 0x0f, 0xcf, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, - 0x03, 0x34, 0x01, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, - 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, - 0x17, 0x03, 0x34, 0x09, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, - 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, - 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xf2, 0x0f, 0xe8, - 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xed, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x09, - 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, - 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0x6b, 0x00, - 0x0f, 0xe8, 0x0f, 0xcf, 0x0f, 0xb6, 0x0f, 0x9d, 0x0f, 0x84, 0x0f, 0x6b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, - 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, - 0x40, 0x1d, 0x5c, 0x06, 0x18, 0x03, 0x34, 0x01, 0xfc, 0x9b, 0xff, 0x1a, - 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, - 0xdb, 0x40, 0x1d, 0x5c, 0x05, 0x18, 0x03, 0x34, 0x01, 0x9b, 0x66, 0x83, - 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, - 0x6a, 0xbc, 0x33, 0xef, 0x01, 0x04, 0x18, 0x03, 0x34, 0x01, 0x9b, 0x66, - 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, - 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0x03, 0x18, 0x03, 0x34, 0x01, 0x64, - 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, - 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, 0x17, 0x03, 0x34, 0x09, - 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, - 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x0a, 0x00, 0x00, 0x00, - 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, - 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x08, 0x01, 0x06, - 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x08, 0x01, 0x04, 0x04, 0x03, - 0x08, 0x01, 0x03, 0x04, 0x03, 0x08, 0x01, 0x02, 0x03, 0x03, 0x08, 0x09, - 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, - 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, - 0x01, 0x04, 0x04, 0x03, 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, - 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, - 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x09, 0x01, - 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, 0x09, 0x01, 0x03, 0x04, - 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, - 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, - 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, - 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, - 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, - 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, - 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x08, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x08, - 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, 0x03, 0x08, 0x01, 0x02, - 0x03, 0x03, 0x08, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, - 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x08, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, - 0x05, 0x04, 0x03, 0x08, 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, - 0x03, 0x08, 0x01, 0x02, 0x03, 0x03, 0x08, 0x09, 0x0a, 0x00, 0x00, 0x00, - 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, - 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, - 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, - 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, - 0x0d, 0x00, 0x00, 0x00, 0x05, 0x05, 0x88, 0x00, 0x05, 0x88, 0x07, 0xca, - 0x0a, 0x10, 0x0b, 0x9e, 0x0d, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x55, 0x07, 0x16, 0x00, 0x07, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, - 0x34, 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, - 0xaa, 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x0b, 0x66, - 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, 0x95, 0x22, 0xa7, 0xe3, - 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, - 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, - 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, 0x7c, 0xa5, 0xb2, 0x07, - 0xf2, 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, 0xc7, 0x85, 0xd2, 0x16, - 0x2f, 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, 0xbd, 0x3d, 0xd9, 0xc4, - 0x98, 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, 0x20, 0x7b, 0x97, 0xca, - 0xe6, 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, 0xc9, 0x46, 0x27, 0xd4, - 0x4f, 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, 0x3c, 0x4e, 0x8e, 0x37, - 0x6e, 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, 0x17, 0xdb, 0xd1, 0x96, - 0xb9, 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, 0xbf, 0x42, 0x46, 0xfc, - 0x1c, 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, 0x4c, 0x84, 0xde, 0x41, - 0x9f, 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, 0x9c, 0x59, 0xd6, 0xcf, - 0xcd, 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, 0x3b, 0x02, 0xcc, 0x1a, - 0xed, 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, 0x39, 0xa5, 0x82, 0x12, - 0x04, 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, 0xc0, 0x8d, 0xdb, 0xff, - 0x46, 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, 0x5e, 0xc1, 0xa3, 0xca, - 0xd4, 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, 0x22, 0xbf, 0xf6, 0x5a, - 0xe6, 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, 0xba, 0x8b, 0xd2, 0x39, - 0x49, 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, 0xdc, 0x0d, 0x73, 0x1b, - 0xe6, 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, 0x4b, 0x79, 0x8c, 0x23, - 0x8d, 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, 0x3f, 0x09, 0xec, 0xf3, - 0xa8, 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, 0x37, 0xc0, 0x2a, 0x7d, - 0x25, 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, 0x14, 0xd0, 0xa8, 0x1e, - 0x2a, 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, 0xa3, 0xb2, 0xee, 0x83, - 0x36, 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, 0x64, 0xb4, 0x07, 0x7c, - 0x3d, 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, 0x91, 0xf4, 0x32, 0xa8, - 0xf1, 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, 0x78, 0xca, 0xa4, 0x0c, - 0x84, 0x3f, 0x01, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, 0x5e, 0x17, - 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x41, 0xb7, 0x59, - 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x83, 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, - 0x45, 0x30, 0xb3, 0x67, 0xc8, 0x32, 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, - 0xf4, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, - 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x99, 0xb4, 0x79, - 0xc1, 0x37, 0xc1, 0xe1, 0x5c, 0x49, 0xa0, 0xe1, 0xf3, 0x17, 0xb8, 0x9c, - 0x69, 0xe6, 0xba, 0xdc, 0xe7, 0x78, 0xb2, 0x5d, 0xd6, 0x95, 0xbe, 0xb2, - 0xda, 0x91, 0xd3, 0x9b, 0xf2, 0xd4, 0xe3, 0x95, 0x3c, 0x53, 0x8d, 0x0e, - 0x68, 0xe9, 0x02, 0xb3, 0xed, 0xeb, 0x95, 0xdd, 0x11, 0xb2, 0x64, 0x69, - 0x8a, 0xfe, 0x03, 0x05, 0xd5, 0x04, 0x9b, 0xac, 0x8a, 0xb6, 0x98, 0x29, - 0x56, 0x2e, 0xd3, 0xea, 0x4e, 0x84, 0xee, 0x23, 0x44, 0x03, 0x12, 0x9d, - 0x9c, 0x9c, 0x9f, 0x11, 0x62, 0xf0, 0x86, 0x36, 0x52, 0x15, 0x0f, 0x27, - 0x93, 0xdb, 0xde, 0x13, 0xc9, 0x94, 0x93, 0xe4, 0xa4, 0x6f, 0x58, 0x9d, - 0x58, 0x9f, 0x15, 0xba, 0x5f, 0x4c, 0xf3, 0x9a, 0x90, 0xc0, 0xcb, 0x60, - 0xce, 0x9b, 0x56, 0x0c, 0xfe, 0x5b, 0xd2, 0x4e, 0x0e, 0x82, 0xe6, 0x4c, - 0x62, 0x57, 0x08, 0x6e, 0x5d, 0x54, 0x7b, 0x28, 0xbb, 0x88, 0xdc, 0xec, - 0xaa, 0xd1, 0x6e, 0xd3, 0x94, 0x20, 0x3e, 0x35, 0x81, 0x52, 0xf6, 0xe9, - 0xee, 0x42, 0x89, 0xe9, 0xea, 0x61, 0x2c, 0xd8, 0xdc, 0xe3, 0x82, 0xf7, - 0xf0, 0xc0, 0xf6, 0xf9, 0xb7, 0xef, 0x49, 0xc7, 0x8d, 0x6c, 0x8a, 0x6d, - 0x6e, 0xbc, 0x2d, 0xc0, 0xb1, 0xec, 0x0c, 0xdd, 0xe5, 0xbe, 0x65, 0x3f, - 0x69, 0x81, 0xcf, 0xe8, 0xd8, 0xf3, 0x57, 0x8e, 0xba, 0x73, 0x7f, 0xb0, - 0x4e, 0x65, 0xa2, 0xa5, 0xa5, 0xbb, 0x7b, 0xae, 0xaa, 0x88, 0x06, 0x4f, - 0x2c, 0x43, 0xb9, 0x4c, 0x17, 0xa1, 0x24, 0xfb, 0xe1, 0x90, 0x50, 0xdb, - 0xcc, 0xd9, 0xe5, 0x7b, 0x09, 0xaf, 0x5c, 0x5a, 0x4f, 0xb2, 0x2b, 0x30, - 0x53, 0x0f, 0xd3, 0xe2, 0xbd, 0xcd, 0xf7, 0xa3, 0x19, 0xdc, 0xba, 0xee, - 0xd1, 0x49, 0xbc, 0xa6, 0xde, 0x1b, 0xe6, 0xd3, 0xaf, 0xdd, 0x61, 0xf6, - 0xfd, 0xef, 0xb7, 0xda, 0x9d, 0x93, 0x45, 0x0a, 0xa2, 0xa8, 0x1a, 0xe5, - 0x16, 0xb1, 0xaf, 0x20, 0x00, 0x86, 0x6b, 0x66, 0x42, 0x97, 0x4e, 0x3a, - 0xea, 0x0d, 0x33, 0xb2, 0x93, 0x87, 0x9c, 0xd1, 0x6a, 0x20, 0xbc, 0xc9, - 0x7d, 0x46, 0xb9, 0x0a, 0x26, 0x9a, 0x09, 0x81, 0xc8, 0x6d, 0x9b, 0x63, - 0xa5, 0x1f, 0x63, 0x72, 0x6c, 0xa8, 0x65, 0x65, 0xa2, 0x8a, 0x81, 0x4d, - 0x54, 0xd4, 0xa3, 0xc4, 0x86, 0x48, 0x31, 0x5c, 0x4e, 0x15, 0xf3, 0x48, - 0x30, 0xbc, 0x17, 0xac, 0x0b, 0x85, 0x8f, 0x44, 0x62, 0xf4, 0x57, 0xc7, - 0xbd, 0x18, 0xcf, 0xf5, 0xd8, 0xa9, 0x2d, 0xf5, 0x57, 0xaf, 0x42, 0x09, - 0xf7, 0x5b, 0x25, 0x56, 0xa1, 0x04, 0x0c, 0xf7, 0xa7, 0xc9, 0x2d, 0xd7, - 0x84, 0x78, 0x86, 0x82, 0x2d, 0xd3, 0xaa, 0xd2, 0xbf, 0x77, 0xc0, 0x34, - 0x7b, 0xdb, 0x7e, 0x4d, 0xde, 0x63, 0x8f, 0xcc, 0xb6, 0x6d, 0x01, 0x80, - 0x68, 0x51, 0x3e, 0x8f, 0x2a, 0x7c, 0x0e, 0xaa, 0xc2, 0xbf, 0x77, 0x12, - 0x06, 0x88, 0xdf, 0x3f, 0x6c, 0x7d, 0x69, 0x05, 0x57, 0x71, 0xeb, 0xe7, - 0xf3, 0xcb, 0x32, 0x4d, 0x33, 0x54, 0x8a, 0x2a, 0x1b, 0xb5, 0x6e, 0xb6, - 0xa4, 0x64, 0xcd, 0x34, 0x5c, 0xa9, 0x3d, 0x92, 0xc8, 0x38, 0xbb, 0x84, - 0xed, 0xde, 0xe4, 0xa2, 0xe1, 0x68, 0x2f, 0xcb, 0x4b, 0x3c, 0x76, 0xb2, - 0x3b, 0x84, 0x5f, 0x6b, 0x46, 0x72, 0x2f, 0x7f, 0xf0, 0x6f, 0x6b, 0x7b, - 0xd3, 0xc5, 0x4b, 0x20, 0x2b, 0xae, 0x48, 0x7e, 0xcb, 0x22, 0x38, 0x44, - 0x1f, 0x43, 0x1c, 0x55, 0x85, 0xe0, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, - 0x6b, 0x75, 0x84, 0x43, 0x02, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, - 0x66, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x41, - 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x77, 0xac, 0x86, 0x8b, 0xf9, - 0xb8, 0xa0, 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, 0xe2, 0x63, 0x81, 0xf6, - 0x85, 0xbc, 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, - 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, - 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf6, - 0xbc, 0x81, 0x5b, 0x23, 0x66, 0x44, 0x13, 0x27, 0xcf, 0x98, 0xc2, 0xc0, - 0x31, 0x38, 0x98, 0xec, 0x01, 0x84, 0xbb, 0x38, 0xb1, 0x79, 0xd7, 0x91, - 0x66, 0x5a, 0x56, 0x22, 0x62, 0x6f, 0xb8, 0xf0, 0x68, 0x00, 0xe7, 0x1a, - 0x7a, 0x93, 0xfc, 0xa8, 0xd4, 0xd9, 0xaf, 0x21, 0x17, 0x71, 0xf3, 0x0c, - 0xd6, 0x22, 0x2f, 0xb0, 0xb7, 0xc3, 0x1e, 0x07, 0xe7, 0x53, 0x34, 0xc9, - 0x17, 0x9d, 0xe8, 0xd3, 0x07, 0x78, 0xe7, 0x74, 0xcd, 0xf0, 0xdd, 0x88, - 0x0d, 0x30, 0x9b, 0x3c, 0x78, 0xfb, 0x43, 0xb7, 0x4f, 0x79, 0xd1, 0x83, - 0xcd, 0x56, 0x60, 0xe7, 0x7e, 0x8d, 0xba, 0x61, 0x9d, 0x4f, 0xf2, 0x71, - 0x9b, 0xbd, 0x11, 0xfc, 0x82, 0x8f, 0xc2, 0x9b, 0x32, 0xb7, 0x4d, 0x5d, - 0x93, 0x87, 0x11, 0x7d, 0xbf, 0x3a, 0x06, 0x11, 0x15, 0xf5, 0x97, 0xf4, - 0x03, 0x24, 0x6a, 0xfb, 0x5e, 0x27, 0x2b, 0xb5, 0xac, 0x20, 0x84, 0xe8, - 0x8d, 0x67, 0xa9, 0xf5, 0x41, 0x8a, 0xbd, 0xea, 0x51, 0x91, 0x30, 0xd7, - 0xf2, 0x81, 0x12, 0xbc, 0x24, 0x61, 0x25, 0x58, 0x9e, 0x4a, 0x4c, 0x89, - 0xa4, 0x19, 0xf1, 0x12, 0xe2, 0x33, 0xf1, 0x37, 0x1f, 0x0f, 0xa0, 0x42, - 0xa1, 0x0e, 0xa2, 0xc4, 0x06, 0xb0, 0xba, 0x61, 0xef, 0xc5, 0x6b, 0x46, - 0x33, 0x62, 0x50, 0xe0, 0xe4, 0x2e, 0x74, 0x20, 0xf4, 0x54, 0xbb, 0xed, - 0xa0, 0x73, 0x51, 0xa5, 0xc6, 0x55, 0x90, 0x61, 0xe9, 0x9c, 0x76, 0x72, - 0x21, 0xa9, 0x19, 0x1a, 0xbd, 0xcf, 0x61, 0x29, 0x8a, 0xef, 0xdd, 0xe0, - 0xc6, 0x0a, 0xf0, 0xd8, 0x50, 0xb9, 0xe9, 0x92, 0x7d, 0xf3, 0xce, 0x7e, - 0x9e, 0xcf, 0x32, 0x92, 0xc7, 0x49, 0x59, 0x23, 0xb5, 0x4e, 0xf2, 0x71, - 0xf0, 0xda, 0xb3, 0x80, 0xe3, 0xb6, 0x7a, 0xe4, 0x14, 0x80, 0x25, 0x3e, - 0xd0, 0x89, 0x13, 0xf4, 0x70, 0x96, 0xee, 0xbe, 0xef, 0x31, 0x61, 0xa1, - 0x8d, 0xf7, 0x9a, 0x5c, 0x92, 0x0a, 0x9b, 0x1f, 0x8c, 0x5e, 0x3d, 0x37, - 0x24, 0xc2, 0x8d, 0x21, 0xe9, 0x47, 0x2e, 0x03, 0xee, 0x32, 0xbf, 0x46, - 0xc7, 0x2c, 0x6e, 0x7a, 0x81, 0x9e, 0x14, 0xb8, 0xbe, 0xdb, 0x22, 0x4f, - 0xf1, 0x8d, 0x47, 0x41, 0x84, 0xc9, 0xeb, 0x4f, 0xe9, 0xf4, 0xad, 0xc4, - 0xbe, 0xf8, 0x28, 0xcb, 0xe6, 0x16, 0xa8, 0x6b, 0xaf, 0xd5, 0x0a, 0x6d, - 0x06, 0x59, 0x4f, 0x7d, 0x53, 0xa6, 0x4e, 0x90, 0xa0, 0x23, 0x1b, 0x92, - 0xf0, 0xe8, 0xef, 0xed, 0x0d, 0xa7, 0x64, 0x01, 0x83, 0x4a, 0x3b, 0x2d, - 0x18, 0x90, 0x1d, 0x19, 0x1d, 0xa2, 0x98, 0xe9, 0xb5, 0xe4, 0x4a, 0x73, - 0xcf, 0xdf, 0x0c, 0x09, 0xd5, 0xf4, 0xd3, 0xd9, 0x12, 0x7c, 0xbb, 0x81, - 0x51, 0x26, 0x2a, 0xcb, 0xa7, 0xc9, 0x6a, 0xe9, 0xfb, 0x1d, 0xca, 0x43, - 0xf1, 0xbe, 0xfb, 0xc3, 0x6f, 0xb6, 0xa1, 0x0c, 0x42, 0x32, 0x18, 0x24, - 0x63, 0xf9, 0xa0, 0x7e, 0x71, 0x8c, 0xa5, 0x16, 0x16, 0x5a, 0x5e, 0x15, - 0x5d, 0x6d, 0x4b, 0x74, 0x5b, 0xde, 0x21, 0xd5, 0xe0, 0x11, 0xa6, 0x91, - 0xc3, 0xb2, 0xd7, 0x38, 0x70, 0xa2, 0x18, 0x29, 0x1b, 0xdc, 0x83, 0x3e, - 0x37, 0x45, 0xc4, 0x1b, 0x61, 0x98, 0x06, 0x12, 0x3e, 0xc0, 0xda, 0x1a, - 0xc9, 0x18, 0x9c, 0x50, 0x0e, 0xc5, 0xe1, 0xa7, 0x4d, 0x05, 0xc6, 0x99, - 0x31, 0xab, 0x17, 0x30, 0xb9, 0xb0, 0x01, 0x1f, 0x93, 0xd9, 0x76, 0xd4, - 0x67, 0x0b, 0xea, 0x7b, 0x2b, 0x0b, 0x42, 0x97, 0x40, 0x07, 0x94, 0x08, - 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x83, 0x0b, 0x05, 0x16, - 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x3c, 0x29, 0x13, 0x41, 0xb7, 0x59, - 0x5c, 0x53, 0x32, 0x4a, 0x6b, 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, - 0x6b, 0x65, 0x6d, 0xb0, 0x14, 0x83, 0xdf, 0x17, 0xb6, 0x73, 0x59, 0x09, - 0xd6, 0x8a, 0xed, 0x02, 0x13, 0x5a, 0x8b, 0xd4, 0x99, 0xda, 0x39, 0xa3, - 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, - 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, - 0x59, 0x31, 0xba, 0xaa, 0x89, 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, - 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0xdc, 0x97, 0xef, 0xa5, 0xc0, 0xbc, 0x15, 0x38, 0x95, 0x35, 0x74, - 0x61, 0x34, 0x68, 0xb9, 0x5c, 0xef, 0x21, 0xad, 0xeb, 0xc9, 0x50, 0x73, - 0xed, 0x31, 0x38, 0x33, 0x44, 0x03, 0x44, 0x16, 0xaf, 0xa2, 0xba, 0x34, - 0x58, 0x3f, 0x49, 0xaf, 0x93, 0xf8, 0xe4, 0x6e, 0x6f, 0x7f, 0x23, 0x05, - 0x46, 0x75, 0x49, 0xdf, 0x84, 0xad, 0x64, 0x83, 0x11, 0x43, 0xd9, 0x80, - 0x11, 0x93, 0x6d, 0xcf, 0xb4, 0x72, 0x42, 0xc2, 0x5a, 0x78, 0x57, 0x37, - 0x2d, 0x9e, 0x9a, 0x3e, 0x30, 0x9b, 0x72, 0x7b, 0xfa, 0x1d, 0x9e, 0x2d, - 0x53, 0x16, 0x85, 0x91, 0x3c, 0xe9, 0xf1, 0x39, 0x60, 0x1d, 0x9e, 0xc6, - 0xee, 0xb1, 0xdc, 0xb1, 0x0d, 0xb8, 0x23, 0x68, 0xbf, 0xe5, 0x08, 0xc4, - 0xac, 0x31, 0x4e, 0x2d, 0x0f, 0x1f, 0xe1, 0xb3, 0xfe, 0xd2, 0x31, 0x4a, - 0x52, 0x3e, 0x03, 0xe1, 0x1a, 0x66, 0x58, 0x8b, 0x56, 0x99, 0x55, 0x7f, - 0x6f, 0x5a, 0xa9, 0x8f, 0xcf, 0xb3, 0x03, 0x96, 0x79, 0xb0, 0x6c, 0x67, - 0x60, 0x35, 0xce, 0x8d, 0xc6, 0x1c, 0x70, 0x05, 0xa4, 0x5e, 0x4f, 0x83, - 0x4f, 0x1a, 0x98, 0x88, 0xdd, 0x5a, 0x5d, 0xb3, 0x9b, 0xf6, 0xb2, 0xa3, - 0x2e, 0x1c, 0x41, 0x81, 0x97, 0xef, 0x16, 0xb3, 0x8e, 0xbe, 0x09, 0x08, - 0x3d, 0x47, 0xaa, 0x2b, 0x90, 0x61, 0xc7, 0x67, 0xcb, 0x0d, 0xa5, 0x7a, - 0x58, 0x4d, 0xa7, 0x9f, 0xd4, 0x21, 0xf2, 0x47, 0x65, 0x3b, 0x9e, 0x3b, - 0xa4, 0xb4, 0x15, 0x05, 0x10, 0xee, 0x90, 0xe5, 0xd9, 0x2e, 0xa0, 0xfe, - 0x85, 0x9c, 0xad, 0x37, 0x71, 0x51, 0xba, 0x0e, 0x91, 0x48, 0x3e, 0x54, - 0xa0, 0x10, 0x1b, 0xc7, 0xff, 0x4b, 0xd2, 0x24, 0xf8, 0x37, 0xd9, 0xc3, - 0x17, 0x12, 0x05, 0x28, 0xbe, 0xeb, 0xf5, 0xa3, 0x5a, 0x93, 0x7b, 0x9e, - 0x59, 0xb2, 0x63, 0xbc, 0x71, 0x61, 0x6a, 0x5a, 0x6c, 0xbd, 0xae, 0xeb, - 0xff, 0x2a, 0x53, 0xf3, 0x44, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, - 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x84, 0x07, - 0x06, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x86, 0x46, 0x17, 0x13, 0x41, - 0xb7, 0x59, 0x5c, 0x54, 0xdd, 0xc7, 0x58, 0x41, 0xb7, 0x59, 0x5c, 0x54, - 0xdd, 0xc7, 0x58, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, - 0x1e, 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, - 0x0e, 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, - 0x36, 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x1c, 0x32, 0x04, 0xe7, 0x79, - 0xe1, 0xe0, 0x05, 0x0b, 0xa0, 0xe7, 0xb9, 0xe1, 0x92, 0xbb, 0xa8, 0xae, - 0xca, 0xff, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x99, 0x02, 0x2d, 0xc5, 0xee, 0x94, 0x76, 0x6c, 0x0a, - 0xe2, 0xa1, 0xb1, 0x7a, 0x6d, 0x0c, 0xbf, 0x9d, 0xa2, 0x60, 0xdc, 0xb9, - 0xf4, 0xf9, 0x4e, 0x6f, 0x61, 0x37, 0x18, 0x86, 0xbf, 0xef, 0xe9, 0x55, - 0x9e, 0x44, 0x75, 0x32, 0x4c, 0x20, 0x82, 0xb5, 0x3d, 0x42, 0x72, 0x35, - 0x69, 0xba, 0x22, 0x95, 0x0c, 0xec, 0x46, 0xe8, 0x5b, 0x62, 0xe2, 0x07, - 0xd4, 0x80, 0x99, 0xc1, 0x83, 0x12, 0x3f, 0xcc, 0xd4, 0xf6, 0xcd, 0xc2, - 0xb2, 0xcd, 0x4d, 0x94, 0x4c, 0xab, 0x05, 0x48, 0x0c, 0x09, 0xe1, 0x82, - 0x1a, 0x6c, 0x0a, 0xf5, 0x16, 0x06, 0x57, 0x23, 0x9e, 0x18, 0xe8, 0xd9, - 0xbb, 0x4a, 0x8a, 0xcd, 0x69, 0xed, 0xc3, 0xae, 0x71, 0xe8, 0x8f, 0xeb, - 0xb5, 0x76, 0x50, 0xca, 0xb5, 0x69, 0x05, 0xdc, 0x93, 0x5b, 0x49, 0xed, - 0xa3, 0xf8, 0x25, 0xfe, 0x6a, 0x83, 0x6f, 0x16, 0x1e, 0xef, 0x5b, 0xfd, - 0x24, 0x7f, 0x9f, 0x66, 0xf1, 0x65, 0x8c, 0x38, 0x43, 0xd1, 0xbc, 0x13, - 0x14, 0x45, 0x75, 0x66, 0x3b, 0xd7, 0xe1, 0x7a, 0xde, 0xb1, 0xf6, 0x27, - 0xd6, 0x3e, 0xf6, 0x44, 0x7d, 0xf3, 0x3e, 0xd2, 0x95, 0x49, 0xe5, 0x31, - 0x6f, 0x38, 0x95, 0xd0, 0x78, 0xc8, 0xca, 0x68, 0xaf, 0xec, 0xab, 0x1e, - 0xcf, 0x0c, 0xff, 0x3e, 0xc4, 0x12, 0x3e, 0x48, 0xb4, 0x7e, 0x70, 0xc6, - 0xa0, 0x9b, 0xf8, 0x80, 0x30, 0x75, 0x25, 0x1a, 0xf1, 0xdf, 0x3a, 0x37, - 0xa1, 0xac, 0x43, 0x5b, 0xa0, 0xae, 0x9b, 0x91, 0xb3, 0x4a, 0xfa, 0x5f, - 0x4b, 0xf1, 0xba, 0xcd, 0x41, 0x92, 0x38, 0x6a, 0x8d, 0x69, 0x9e, 0xd3, - 0x09, 0xaa, 0x4c, 0xb2, 0x60, 0xcf, 0xff, 0x37, 0xed, 0xa0, 0x39, 0x36, - 0x03, 0x1a, 0x6a, 0xb7, 0xed, 0xce, 0xc8, 0x4e, 0x46, 0xb1, 0x82, 0xfb, - 0xe1, 0x46, 0x2d, 0x12, 0xf4, 0x8a, 0x6c, 0x38, 0x5c, 0x6b, 0xaa, 0x05, - 0xf1, 0xc0, 0xf2, 0x14, 0x8d, 0x3e, 0xdc, 0xec, 0x04, 0x0c, 0x94, 0xe3, - 0xbf, 0x3b, 0x7b, 0x3f, 0xa2, 0x88, 0x98, 0xe6, 0x0c, 0x5f, 0x23, 0x6d, - 0x0b, 0x6f, 0x8e, 0xe9, 0xce, 0xc0, 0xe2, 0x3e, 0xc7, 0xcd, 0xa0, 0x7b, - 0xda, 0xf1, 0x26, 0xfd, 0x3d, 0xc6, 0xe7, 0xe8, 0xed, 0x9d, 0xeb, 0x74, - 0xc5, 0x14, 0x5c, 0xee, 0xcd, 0x4d, 0xc4, 0x4e, 0x1b, 0x2d, 0x09, 0xf4, - 0x7b, 0xdb, 0xf6, 0x96, 0x17, 0x17, 0xd1, 0x16, 0xd5, 0xea, 0xaf, 0x4f, - 0x7b, 0xc2, 0x1e, 0x0f, 0xe1, 0x2c, 0xd8, 0x26, 0xe1, 0xcc, 0x66, 0x64, - 0xd1, 0x3f, 0xd9, 0x16, 0x99, 0x0c, 0xb1, 0x11, 0xc2, 0x13, 0xe5, 0xab, - 0x99, 0x2a, 0x6f, 0x09, 0x37, 0xc5, 0x7c, 0x8e, 0xb8, 0x04, 0x73, 0x3b, - 0x0b, 0x58, 0x87, 0x10, 0x33, 0x1f, 0x5d, 0xea, 0xe9, 0xcd, 0x4e, 0x5b, - 0x33, 0x88, 0xc2, 0x9c, 0x01, 0x1a, 0xe6, 0x92, 0x57, 0xf9, 0xa8, 0x7d, - 0x03, 0x76, 0x79, 0x4e, 0x1e, 0x25, 0xe8, 0xae, 0x61, 0x70, 0x70, 0x6c, - 0x65, 0x64, 0x6b, 0x75, 0x84, 0x55, 0x07, 0x16, 0x00, 0x07, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, - 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, - 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x0b, 0x66, 0x7c, - 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, 0x95, 0x22, 0xa7, 0xe3, 0x08, - 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, - 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, - 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, - 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, 0x7c, 0xa5, 0xb2, 0x07, 0xf2, - 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, 0xc7, 0x85, 0xd2, 0x16, 0x2f, - 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, 0xbd, 0x3d, 0xd9, 0xc4, 0x98, - 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, 0x20, 0x7b, 0x97, 0xca, 0xe6, - 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, 0xc9, 0x46, 0x27, 0xd4, 0x4f, - 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, 0x3c, 0x4e, 0x8e, 0x37, 0x6e, - 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, 0x17, 0xdb, 0xd1, 0x96, 0xb9, - 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, 0xbf, 0x42, 0x46, 0xfc, 0x1c, - 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, 0x4c, 0x84, 0xde, 0x41, 0x9f, - 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, 0x9c, 0x59, 0xd6, 0xcf, 0xcd, - 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, 0x3b, 0x02, 0xcc, 0x1a, 0xed, - 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, 0x39, 0xa5, 0x82, 0x12, 0x04, - 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, 0xc0, 0x8d, 0xdb, 0xff, 0x46, - 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, 0x5e, 0xc1, 0xa3, 0xca, 0xd4, - 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, 0x22, 0xbf, 0xf6, 0x5a, 0xe6, - 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, 0xba, 0x8b, 0xd2, 0x39, 0x49, - 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, 0xdc, 0x0d, 0x73, 0x1b, 0xe6, - 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, 0x4b, 0x79, 0x8c, 0x23, 0x8d, - 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, 0x3f, 0x09, 0xec, 0xf3, 0xa8, - 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, 0x37, 0xc0, 0x2a, 0x7d, 0x25, - 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, 0x14, 0xd0, 0xa8, 0x1e, 0x2a, - 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, 0xa3, 0xb2, 0xee, 0x83, 0x36, - 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, 0x64, 0xb4, 0x07, 0x7c, 0x3d, - 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, 0x91, 0xf4, 0x32, 0xa8, 0xf1, - 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, 0x78, 0xca, 0xa4, 0x0c, 0xf8, - 0x40, 0x9f, 0x86, 0xd9, 0x16, 0x56, 0x67, 0x74, 0xd4, 0x33, 0x9e, 0xb7, - 0xef, 0xa6, 0xdf, 0x32, 0xb2, 0x24, 0x20, 0xe7, 0xe9, 0x80, 0xdf, 0x7b, - 0xa3, 0x49, 0x04, 0xd7, 0x3f, 0x9f, 0xbe, 0xa6, 0x2d, 0xd0, 0xec, 0xed, - 0x04, 0x76, 0xc9, 0x38, 0x0b, 0x2c, 0x02, 0xcc, 0xd0, 0x98, 0x02, 0x73, - 0x96, 0x6b, 0x8b, 0xcb, 0x2b, 0x57, 0x2d, 0xab, 0x0d, 0x5e, 0x97, 0xb8, - 0xd9, 0x81, 0xa6, 0x09, 0x7c, 0x6a, 0x6a, 0xbe, 0xed, 0x44, 0xe1, 0x87, - 0x2a, 0xbd, 0xad, 0x61, 0xfa, 0xdc, 0x76, 0xaa, 0xa5, 0xfd, 0x40, 0xee, - 0x9f, 0xf1, 0xc6, 0x74, 0xe9, 0xba, 0xc1, 0xaf, 0xf1, 0x5d, 0x16, 0x06, - 0x27, 0x60, 0x2b, 0x96, 0x9d, 0x0d, 0xc1, 0x7c, 0xc3, 0x7b, 0xfd, 0x33, - 0xc2, 0xa6, 0x7c, 0xbc, 0xc3, 0x1c, 0xef, 0x9d, 0xf4, 0xe2, 0x8c, 0x2d, - 0xe3, 0x01, 0xc1, 0x95, 0x24, 0x66, 0x15, 0x1a, 0xa1, 0xa0, 0x61, 0x28, - 0x8f, 0x44, 0x77, 0x80, 0xfc, 0x11, 0xce, 0xad, 0xe1, 0xf1, 0xe9, 0x80, - 0x55, 0x6d, 0x77, 0x5d, 0xf7, 0x2a, 0xf8, 0x15, 0x42, 0xdd, 0xf6, 0x62, - 0xac, 0x68, 0x8f, 0xaa, 0x85, 0xd8, 0xfa, 0xc6, 0x21, 0xe9, 0xa8, 0xa2, - 0x1e, 0xe3, 0xd4, 0x32, 0x3e, 0xee, 0xec, 0x96, 0x54, 0xe1, 0xb1, 0x8f, - 0x64, 0x59, 0xc6, 0x49, 0x01, 0x3c, 0xc0, 0x17, 0xa9, 0xf5, 0xf2, 0x6f, - 0x8a, 0xec, 0x9b, 0x66, 0xa7, 0x1d, 0x98, 0xff, 0x61, 0x70, 0x70, 0x6c, - 0x65, 0x64, 0x6b, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x04, 0x3a, 0x00, - 0x07, 0x4c, 0x0d, 0x3f, 0x0e, 0xa9, 0x04, 0x3a, 0x05, 0x5c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x1f, 0x11, 0x16, 0x00, 0x07, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x34, 0x00, 0x83, 0x22, 0x15, 0x11, 0x41, 0xb7, 0x59, 0x5c, 0xf4, - 0x84, 0x43, 0x4e, 0x41, 0xb7, 0x59, 0x5c, 0xf4, 0x84, 0x43, 0x4e, 0xda, - 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, - 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xa9, 0x4a, 0x8f, 0xe5, 0xcc, - 0xb1, 0x9b, 0xa6, 0x1c, 0x4c, 0x08, 0x73, 0xd3, 0x91, 0xe9, 0x87, 0x98, - 0x2f, 0xbb, 0xd3, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x72, 0xbd, 0xda, 0xaa, 0x55, 0x31, 0xcc, 0x9a, 0xfc, - 0x33, 0x30, 0x52, 0x07, 0x40, 0x54, 0xcb, 0x27, 0x4e, 0xb7, 0x9f, 0x96, - 0xb8, 0xcb, 0xdc, 0x88, 0x3c, 0x09, 0xd1, 0x96, 0xe2, 0x79, 0x54, 0x21, - 0x46, 0xca, 0x50, 0xa2, 0x46, 0xda, 0x44, 0x2e, 0x3b, 0x4b, 0x18, 0xb7, - 0x5a, 0x17, 0xe6, 0x4f, 0x06, 0xde, 0xec, 0x05, 0x9c, 0xec, 0x8e, 0xb5, - 0xd1, 0xb3, 0xe3, 0x0a, 0x3f, 0x44, 0x9c, 0xa5, 0x30, 0x0a, 0x83, 0x66, - 0x82, 0x89, 0xcf, 0x1b, 0xb8, 0xb8, 0xb2, 0x18, 0x54, 0xcf, 0x4d, 0x85, - 0x93, 0x97, 0x75, 0x54, 0x06, 0x23, 0x05, 0xe8, 0xff, 0x42, 0x33, 0x7f, - 0xdf, 0x26, 0xa0, 0x1e, 0xd3, 0xe2, 0x7b, 0xb7, 0xe2, 0x70, 0x88, 0x82, - 0xba, 0x3e, 0x38, 0xaa, 0x95, 0xee, 0xf7, 0x4f, 0x81, 0xbe, 0xf4, 0xfe, - 0x8f, 0x42, 0xb8, 0x94, 0x25, 0xe3, 0x3a, 0x4b, 0xe1, 0x15, 0xe2, 0xe1, - 0xe6, 0x8b, 0xda, 0x49, 0x9a, 0xb1, 0x47, 0xa4, 0x9c, 0xac, 0x35, 0xb8, - 0xa2, 0xb3, 0xc2, 0x5f, 0x2b, 0x87, 0x11, 0xd7, 0x57, 0x47, 0x05, 0x89, - 0x05, 0x86, 0xfa, 0x97, 0xa7, 0x97, 0x46, 0xcf, 0xaa, 0xa8, 0x94, 0x2c, - 0xde, 0xa3, 0xde, 0xb1, 0x92, 0x20, 0xbd, 0x7d, 0x90, 0xd2, 0xa7, 0x21, - 0x26, 0x6f, 0x2b, 0x6e, 0xd3, 0xd9, 0x1a, 0xea, 0x57, 0x04, 0x94, 0x1c, - 0x73, 0x0e, 0x74, 0x65, 0x73, 0x74, 0x61, 0x6b, 0xe1, 0x06, 0x12, 0x17, - 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x34, 0x34, 0x00, 0x81, 0xc0, 0x6a, 0x17, 0x13, 0x41, 0xb7, - 0x59, 0x5c, 0xfe, 0x44, 0x71, 0x3f, 0x41, 0xb7, 0x59, 0x5c, 0xfe, 0x44, - 0x71, 0x3f, 0x7f, 0xda, 0x6a, 0xa0, 0x63, 0xf3, 0xfc, 0x5a, 0x86, 0x5c, - 0xa8, 0xf7, 0xa6, 0x9b, 0x5d, 0x69, 0x07, 0x3b, 0x91, 0x55, 0x72, 0x29, - 0x9c, 0x30, 0x4b, 0x50, 0xee, 0xe7, 0xb0, 0xc7, 0x1b, 0x05, 0x97, 0x70, - 0xac, 0x8e, 0x43, 0x5d, 0x69, 0x39, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, - 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0xbe, 0xad, 0xda, 0xa8, 0x8a, - 0x50, 0x50, 0xa2, 0x05, 0x34, 0x4f, 0x7d, 0x48, 0x22, 0x81, 0x07, 0x45, - 0x81, 0x36, 0x06, 0x10, 0x48, 0xd5, 0xe0, 0xb8, 0x50, 0xbd, 0x5c, 0xe8, - 0x5d, 0x51, 0x93, 0x3c, 0xfa, 0xeb, 0x83, 0x4d, 0x00, 0xa1, 0x9d, 0x8a, - 0x39, 0x91, 0xac, 0x08, 0x70, 0x37, 0x9a, 0x2d, 0x33, 0xdf, 0xfa, 0x44, - 0xed, 0x61, 0x62, 0x10, 0x2c, 0x22, 0x27, 0x44, 0xa8, 0x19, 0xc3, 0x4f, - 0xd4, 0xb6, 0x7a, 0x6c, 0xf3, 0xb2, 0x4f, 0xf4, 0x06, 0x16, 0x5e, 0xc6, - 0x08, 0x61, 0xd5, 0x6b, 0xaf, 0x9d, 0x1e, 0x1f, 0x9c, 0xed, 0x30, 0xda, - 0x7a, 0xf1, 0xa3, 0x24, 0x26, 0xf5, 0xc9, 0xd6, 0xea, 0xdc, 0x1b, 0x4b, - 0xf6, 0x62, 0x78, 0xa6, 0x64, 0x6c, 0xd4, 0xbf, 0x30, 0x29, 0x36, 0x18, - 0x7c, 0x55, 0x1e, 0x12, 0xbe, 0x30, 0xc9, 0x51, 0x4c, 0x18, 0x83, 0x39, - 0x8d, 0xa2, 0xbc, 0x8a, 0x6f, 0x96, 0x1b, 0x69, 0xbf, 0x99, 0x29, 0x58, - 0x7b, 0xd2, 0x9d, 0x50, 0x32, 0x91, 0x31, 0xd2, 0x25, 0xcc, 0x19, 0xab, - 0x51, 0x6a, 0xc8, 0x5b, 0xd9, 0xf3, 0x64, 0x36, 0xf8, 0xbc, 0x73, 0x23, - 0x07, 0x04, 0x93, 0xd9, 0xbc, 0xd4, 0xb8, 0x7b, 0xd3, 0x58, 0x68, 0x2c, - 0x2b, 0x67, 0xae, 0x57, 0x39, 0x6b, 0xb0, 0xf5, 0x62, 0xe5, 0xec, 0xbe, - 0x42, 0x97, 0x9f, 0xec, 0x9c, 0x43, 0x7c, 0xba, 0xab, 0xad, 0xed, 0xd9, - 0xa0, 0xbc, 0xf4, 0x98, 0x03, 0xca, 0xbe, 0xd8, 0xa3, 0x79, 0x4c, 0xdb, - 0x3d, 0x22, 0x15, 0x71, 0xc9, 0x37, 0x92, 0x9b, 0x05, 0x54, 0x72, 0xe2, - 0x41, 0xd7, 0xd8, 0xb2, 0x4f, 0xcf, 0x56, 0xf3, 0x46, 0x4c, 0x39, 0x5d, - 0x49, 0xdf, 0xae, 0x52, 0xb2, 0x8f, 0xf0, 0x9a, 0xae, 0xe0, 0x00, 0xf4, - 0xd0, 0xd0, 0xa3, 0x8d, 0xf4, 0xba, 0x57, 0xe5, 0x0d, 0xa2, 0x0e, 0xcc, - 0xa3, 0xb9, 0xd0, 0x78, 0x24, 0x3e, 0xdb, 0xdb, 0x4b, 0xc8, 0x60, 0xbb, - 0x71, 0xb8, 0xc6, 0xfe, 0xb0, 0x67, 0x5b, 0x86, 0x09, 0x6c, 0xd0, 0x3e, - 0x6e, 0x0a, 0x82, 0x93, 0xcf, 0xdb, 0x9a, 0x72, 0x5c, 0x41, 0x8f, 0xa5, - 0xfd, 0x44, 0x17, 0xe0, 0x5f, 0x85, 0x9c, 0xb5, 0x71, 0xe4, 0x67, 0x94, - 0x88, 0xdf, 0xfe, 0xad, 0x4e, 0x5e, 0x67, 0x41, 0x49, 0xc3, 0xda, 0x1a, - 0x25, 0xcc, 0x8c, 0xaf, 0xb5, 0xf9, 0xb6, 0x37, 0x2f, 0xe9, 0x73, 0x1d, - 0x71, 0xaf, 0x2a, 0x7d, 0x95, 0xef, 0x8a, 0xe0, 0x0f, 0x0a, 0x73, 0x95, - 0x88, 0x33, 0xe2, 0xe0, 0x88, 0x2b, 0x44, 0x60, 0x51, 0x27, 0xfa, 0x90, - 0xfc, 0x5a, 0x35, 0x54, 0x19, 0x9c, 0xb4, 0x60, 0x2b, 0xd8, 0x4c, 0xf9, - 0x2d, 0xba, 0x88, 0x12, 0xa6, 0xfc, 0x0c, 0x22, 0xfd, 0x27, 0x9e, 0x98, - 0x02, 0xf8, 0x06, 0x70, 0x51, 0x66, 0xa0, 0x1e, 0xb1, 0x6e, 0xe1, 0x90, - 0x86, 0x55, 0xa2, 0x84, 0x92, 0xd6, 0xe4, 0x59, 0x00, 0x00, 0x00, 0x1c, - 0x8b, 0x70, 0x08, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x96, 0x40, 0x17, - 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xe2, 0xe0, 0xc1, 0x41, 0xb7, 0x59, - 0x5c, 0x7e, 0xe2, 0xe0, 0xc1, 0x51, 0x96, 0x74, 0xbb, 0x0c, 0xef, 0x0c, - 0xf3, 0x24, 0x61, 0xd2, 0x2c, 0xba, 0x9a, 0xa9, 0xc8, 0x0e, 0x22, 0xff, - 0x0b, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, - 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x4e, 0xcb, 0x84, - 0x35, 0xce, 0xed, 0x00, 0x0f, 0x0d, 0x8f, 0xce, 0xe6, 0x43, 0xc4, 0x14, - 0x6f, 0x42, 0xd5, 0x97, 0xdf, 0xa6, 0x31, 0x52, 0xa2, 0xb2, 0xc4, 0x38, - 0xf2, 0x2e, 0xb2, 0x5e, 0x73, 0x6d, 0xeb, 0x60, 0xa9, 0x70, 0x32, 0xad, - 0x98, 0x3a, 0x23, 0x00, 0x86, 0x4c, 0x75, 0x26, 0x22, 0x28, 0x8f, 0x1a, - 0x96, 0x60, 0x8a, 0x61, 0xa2, 0xc5, 0x0b, 0x5a, 0xf6, 0x7b, 0x3a, 0xb0, - 0x42, 0x02, 0x3a, 0x5f, 0x4c, 0x14, 0xdd, 0x52, 0x6a, 0xff, 0x08, 0x5f, - 0x7e, 0xef, 0x9a, 0x98, 0x0e, 0x06, 0x38, 0x24, 0x6d, 0x4c, 0xa6, 0x29, - 0xeb, 0x44, 0xa8, 0x35, 0x7d, 0x0f, 0x2f, 0x8c, 0x83, 0x5b, 0xc4, 0x43, - 0x5f, 0x9c, 0x33, 0x7f, 0xc0, 0x97, 0x17, 0xed, 0xcb, 0x95, 0xed, 0xa4, - 0xe4, 0x29, 0xdd, 0x62, 0xff, 0x3a, 0x07, 0x91, 0x92, 0xa9, 0xc2, 0x19, - 0xc3, 0xaa, 0xa3, 0xcb, 0xcc, 0x64, 0xf2, 0x00, 0xb8, 0xc9, 0x17, 0x3d, - 0x00, 0x24, 0xb2, 0xaf, 0x0e, 0x6c, 0xd5, 0x64, 0x84, 0x7d, 0x60, 0x19, - 0xad, 0xa6, 0x79, 0x05, 0x88, 0xf7, 0x72, 0x5a, 0xa4, 0x6b, 0x51, 0x77, - 0xb2, 0x28, 0x93, 0xcb, 0xbe, 0x74, 0x70, 0x10, 0x09, 0x00, 0x5f, 0x2d, - 0xe5, 0xf8, 0x9d, 0x90, 0x00, 0x2b, 0xa3, 0xbb, 0x32, 0x6c, 0x2d, 0x9e, - 0x72, 0x25, 0x18, 0x92, 0xec, 0xbf, 0x97, 0x49, 0xc7, 0x4c, 0xee, 0x90, - 0x5d, 0x6d, 0xdc, 0xa4, 0x4f, 0x4c, 0x88, 0x6c, 0x81, 0x9f, 0xcf, 0xd1, - 0x89, 0x29, 0x3d, 0x61, 0x38, 0x33, 0x89, 0x4a, 0x81, 0xd2, 0x0c, 0xc8, - 0xdc, 0x09, 0xb2, 0x6a, 0xa7, 0x16, 0x42, 0x9f, 0xa3, 0x9d, 0x85, 0x02, - 0xb4, 0xb8, 0xd4, 0xae, 0x63, 0xef, 0x50, 0x78, 0x43, 0x3b, 0x20, 0x7c, - 0x87, 0xac, 0xcb, 0x0b, 0x96, 0x1c, 0x8e, 0x1f, 0xc4, 0x84, 0x20, 0xe1, - 0x3c, 0xe3, 0x0a, 0x28, 0xfb, 0x4b, 0xa3, 0x19, 0x7c, 0xc7, 0x37, 0xf0, - 0x29, 0x47, 0x9d, 0xaf, 0xf4, 0xf1, 0xf6, 0x3c, 0x32, 0xae, 0x5b, 0x37, - 0xc5, 0x77, 0x90, 0xf5, 0x59, 0x8b, 0x85, 0x95, 0xee, 0xdf, 0xa7, 0x2e, - 0x4b, 0x5b, 0xf3, 0x0c, 0xe3, 0xc5, 0xe6, 0x6a, 0x85, 0xfb, 0xe2, 0x4a, - 0x5a, 0xb8, 0x06, 0xcc, 0x22, 0x3d, 0x21, 0x76, 0x04, 0xca, 0x5f, 0x61, - 0x18, 0x4f, 0x35, 0x11, 0x20, 0xe9, 0xc1, 0x72, 0x3d, 0x45, 0x58, 0x60, - 0x8b, 0x8e, 0x3d, 0x3d, 0x21, 0xf8, 0xb3, 0xa3, 0x02, 0x57, 0x06, 0xbd, - 0xff, 0xe0, 0x65, 0x35, 0x3a, 0xba, 0xe8, 0xa8, 0x96, 0x6f, 0x6c, 0x67, - 0xeb, 0xd6, 0xf4, 0xdc, 0xf6, 0x26, 0x52, 0xcd, 0xed, 0xc1, 0x73, 0x12, - 0xdb, 0x86, 0xef, 0x36, 0x87, 0x22, 0xc4, 0xfd, 0xaf, 0xc7, 0x35, 0x90, - 0x38, 0xe5, 0xb2, 0x4a, 0x8a, 0xca, 0xcc, 0x1a, 0xd5, 0x82, 0x10, 0xba, - 0xe7, 0x60, 0xb2, 0x0d, 0x6b, 0xb5, 0xbd, 0x9e, 0x6e, 0xd0, 0xe0, 0x36, - 0xd8, 0x0a, 0x09, 0x24, 0x87, 0xcd, 0xc2, 0x94, 0x10, 0x14, 0xc4, 0x15, - 0xc2, 0xf7, 0x37, 0x22, 0x78, 0x6c, 0x88, 0x75, 0x3a, 0x08, 0xdc, 0x81, - 0x58, 0xe6, 0x3a, 0x4b, 0x7a, 0x6b, 0xe8, 0x27, 0x5d, 0x5d, 0xea, 0x6d, - 0x1a, 0xbb, 0x50, 0x8b, 0xa5, 0x7c, 0x1d, 0xd2, 0xd8, 0x86, 0xf3, 0xa7, - 0xd7, 0xd7, 0x82, 0x61, 0x14, 0x7a, 0x4e, 0x32, 0xf3, 0x74, 0x38, 0x09, - 0x9b, 0xeb, 0x7c, 0x55, 0x53, 0x9e, 0x39, 0xec, 0xe1, 0xf0, 0xae, 0x7d, - 0xbe, 0x9a, 0x1d, 0x87, 0xab, 0x97, 0xc2, 0xa6, 0x05, 0xb7, 0xc2, 0x86, - 0x2d, 0xc8, 0x1e, 0x02, 0x0a, 0xa8, 0xaa, 0x4f, 0xb5, 0x70, 0x92, 0x97, - 0x75, 0x7a, 0x3c, 0xe0, 0xd3, 0x2c, 0x87, 0xf6, 0x53, 0x4f, 0x98, 0x69, - 0x2f, 0xb3, 0xa6, 0xeb, 0xb6, 0xfd, 0xf5, 0x07, 0x6d, 0x8c, 0x9d, 0xf7, - 0x70, 0x60, 0xe9, 0x34, 0x66, 0x9b, 0x54, 0x37, 0x20, 0xe2, 0x03, 0xb5, - 0x81, 0xff, 0xa1, 0x52, 0x72, 0x27, 0xae, 0x71, 0xe3, 0x4a, 0xf8, 0xda, - 0xa9, 0x8d, 0xb6, 0x2c, 0x88, 0xa2, 0xa4, 0xf3, 0x01, 0xdc, 0x16, 0x28, - 0xe2, 0xb3, 0x6d, 0x94, 0xa8, 0x17, 0xc7, 0x19, 0x35, 0x57, 0x75, 0x31, - 0x7b, 0x1e, 0x92, 0x44, 0xa3, 0xf4, 0xed, 0x84, 0x9c, 0x3e, 0xae, 0x71, - 0xfe, 0x12, 0x40, 0x76, 0x85, 0xa4, 0x98, 0x0b, 0x07, 0x48, 0x91, 0x22, - 0xff, 0x80, 0x07, 0x51, 0x5a, 0x67, 0x19, 0xa8, 0xf5, 0x11, 0x1b, 0x3a, - 0x2e, 0xae, 0x27, 0x6e, 0x26, 0x0e, 0xb0, 0x3c, 0x3b, 0xaf, 0xc0, 0x31, - 0xf6, 0x76, 0x95, 0x89, 0x66, 0xe5, 0x6d, 0x92, 0x12, 0xc8, 0x96, 0xc6, - 0x42, 0x33, 0x66, 0xb1, 0x3c, 0x9b, 0x45, 0xc8, 0xa2, 0x50, 0x37, 0xeb, - 0x7e, 0xf6, 0x67, 0x9e, 0xda, 0x28, 0x1b, 0x8f, 0x6d, 0xd4, 0x47, 0x71, - 0x6a, 0xa6, 0xd9, 0x0c, 0x3c, 0x49, 0xa8, 0xa5, 0x2a, 0x60, 0x88, 0xd0, - 0x44, 0x8f, 0xb0, 0xb8, 0x28, 0x8b, 0x84, 0xce, 0xdd, 0x05, 0x02, 0x22, - 0xab, 0x7c, 0x7a, 0xfe, 0x5a, 0x6c, 0x60, 0x7e, 0x63, 0x17, 0xc6, 0x8b, - 0xaa, 0x28, 0xf4, 0xa1, 0x59, 0x17, 0x93, 0x8e, 0xfc, 0x20, 0x7a, 0xd2, - 0x6d, 0x60, 0x53, 0x2f, 0xd3, 0x97, 0xaa, 0xc4, 0xc3, 0x1b, 0x81, 0x43, - 0xdd, 0x0b, 0xc2, 0x18, 0x31, 0x05, 0xb3, 0xce, 0xea, 0x46, 0x4a, 0x90, - 0xdb, 0x9f, 0x1e, 0x5b, 0xfd, 0x17, 0x6f, 0x84, 0x0d, 0x05, 0x4b, 0x4b, - 0xcb, 0x63, 0x6c, 0x15, 0x47, 0xcf, 0x8b, 0x77, 0x5d, 0xb7, 0x3a, 0x0e, - 0xe1, 0xc5, 0xd6, 0x4b, 0x8a, 0x81, 0x04, 0x18, 0x4f, 0x2e, 0x25, 0x1d, - 0x3b, 0x45, 0x00, 0xc0, 0xd9, 0x44, 0x23, 0xf0, 0x99, 0xf1, 0xe8, 0xc6, - 0xdc, 0x96, 0x38, 0xde, 0xa9, 0x85, 0x4a, 0x5c, 0x7b, 0x5d, 0xaf, 0x35, - 0xc8, 0x6d, 0xbe, 0x89, 0xd2, 0x2a, 0x5c, 0xec, 0xab, 0xe3, 0x8e, 0x69, - 0x19, 0x54, 0xb0, 0x61, 0xad, 0xfd, 0x0b, 0x68, 0x07, 0x2f, 0xe6, 0x13, - 0xa6, 0x83, 0xc1, 0x23, 0x45, 0x54, 0x9e, 0x19, 0xe0, 0xeb, 0x1b, 0x04, - 0xd4, 0xd9, 0x86, 0x6d, 0x38, 0xe4, 0x5b, 0x63, 0xbb, 0xb5, 0xb6, 0xd5, - 0xc5, 0x6e, 0xb1, 0xa5, 0xaf, 0x16, 0x6e, 0x8e, 0xbe, 0xb2, 0xc4, 0x2a, - 0xa8, 0x2d, 0x41, 0x5e, 0xd4, 0xc9, 0x28, 0x67, 0x65, 0x65, 0x98, 0x4c, - 0x0c, 0xd8, 0x40, 0x79, 0x59, 0x42, 0x77, 0xf3, 0x06, 0x81, 0x06, 0x43, - 0xfb, 0x97, 0xbf, 0x28, 0x41, 0xdc, 0xb5, 0x54, 0xb8, 0xdf, 0x9d, 0xc1, - 0x9d, 0xba, 0x4f, 0x11, 0x2a, 0x4e, 0xca, 0xf9, 0xc4, 0xcb, 0xfc, 0xeb, - 0xc1, 0x2a, 0x87, 0x75, 0x5c, 0x6f, 0xcb, 0x75, 0x36, 0xc2, 0x5e, 0xce, - 0x7a, 0x59, 0x6e, 0x7c, 0x6f, 0xe8, 0x3c, 0xa6, 0x7b, 0xe7, 0x36, 0x4d, - 0xfa, 0xad, 0xac, 0xbd, 0x61, 0xa3, 0x36, 0x53, 0xc4, 0x3d, 0xc5, 0xf5, - 0x46, 0x3a, 0x97, 0x5b, 0x66, 0x0a, 0x84, 0xa2, 0x31, 0xf0, 0xdc, 0xc3, - 0x30, 0xdc, 0x52, 0x93, 0x73, 0xab, 0x2b, 0x7e, 0x61, 0xb1, 0x35, 0xa2, - 0xff, 0x8a, 0x31, 0xf8, 0xfe, 0x0f, 0x22, 0x27, 0xba, 0xe2, 0x9e, 0xd3, - 0xfe, 0x7c, 0x2e, 0xe0, 0x94, 0x45, 0xc5, 0x2b, 0xd6, 0xaa, 0xb5, 0x74, - 0xd0, 0x5a, 0x5b, 0x61, 0x24, 0x69, 0x42, 0x8d, 0x5f, 0xe4, 0x3c, 0xe2, - 0xad, 0x15, 0x2b, 0x87, 0xbe, 0xec, 0xf0, 0x2e, 0x61, 0xb6, 0xc4, 0xe1, - 0xc6, 0x57, 0x9a, 0x5d, 0xc7, 0x35, 0x31, 0x6f, 0xb0, 0x14, 0xcc, 0x59, - 0xfc, 0x8a, 0x88, 0x08, 0xcb, 0x20, 0xdd, 0xc3, 0xc7, 0xa4, 0xdc, 0x9c, - 0x1f, 0x1b, 0x89, 0x28, 0x55, 0xab, 0x36, 0x9c, 0xae, 0x64, 0xb2, 0x7e, - 0x7f, 0x92, 0xb5, 0x79, 0x44, 0x0b, 0x2e, 0x0c, 0x3c, 0xc5, 0xd8, 0xd2, - 0x12, 0x15, 0xb9, 0x5e, 0x76, 0x40, 0xc5, 0xf5, 0x6f, 0x33, 0x41, 0xdf, - 0x83, 0x99, 0x91, 0x9b, 0xc1, 0x72, 0xf6, 0xbe, 0x87, 0xeb, 0x25, 0x82, - 0x49, 0x61, 0x44, 0xc1, 0x0f, 0x79, 0xd3, 0xae, 0x4d, 0x8d, 0xa0, 0xa5, - 0x40, 0x5f, 0xf2, 0x65, 0x94, 0xc3, 0x66, 0x18, 0xa1, 0x3c, 0x3b, 0x50, - 0x4b, 0xc9, 0xc0, 0x55, 0xb6, 0xf6, 0x69, 0xc2, 0x08, 0x10, 0x5f, 0xd7, - 0x7a, 0x62, 0xfb, 0x30, 0xf2, 0xdd, 0x25, 0x45, 0xfb, 0x8c, 0xaa, 0x56, - 0x89, 0xa5, 0xc8, 0x4a, 0xfc, 0x34, 0x57, 0x5a, 0x1c, 0x7b, 0x5b, 0xbd, - 0x7d, 0xfe, 0x43, 0xcb, 0xec, 0x3a, 0xdf, 0x59, 0x46, 0xd4, 0x01, 0xe3, - 0xee, 0xdf, 0x7e, 0xab, 0xc4, 0x55, 0x03, 0xdb, 0x7a, 0x3c, 0x56, 0x84, - 0xec, 0x39, 0x7c, 0xab, 0xd6, 0x64, 0x3b, 0x6e, 0xda, 0xa5, 0x1a, 0x48, - 0x13, 0x31, 0x3f, 0xe2, 0xaf, 0xee, 0x15, 0x74, 0xa6, 0x9d, 0x26, 0x6b, - 0xb4, 0x7d, 0x4d, 0xb2, 0x3e, 0xbe, 0x80, 0xdd, 0x81, 0xad, 0x81, 0x3a, - 0xa8, 0x27, 0x25, 0x13, 0xfc, 0x0e, 0xe6, 0x87, 0xdb, 0xf5, 0x08, 0x50, - 0x7a, 0x2c, 0x06, 0x66, 0x87, 0x07, 0xae, 0x14, 0xa8, 0xe2, 0x49, 0x6b, - 0x5f, 0x03, 0x89, 0x07, 0x8e, 0x1a, 0xa1, 0x5e, 0xa3, 0x9f, 0x1f, 0x1f, - 0xb1, 0x22, 0x14, 0x38, 0x9a, 0xc7, 0x4a, 0x7f, 0xd9, 0xb7, 0xd9, 0xbd, - 0xb5, 0x33, 0xa7, 0x97, 0xbb, 0x24, 0x5c, 0xb0, 0xee, 0x1a, 0xe3, 0x2d, - 0xf1, 0x0d, 0x33, 0x6e, 0x77, 0x02, 0x38, 0x35, 0x7d, 0x0f, 0x4a, 0xfb, - 0x12, 0x10, 0xee, 0x1e, 0xf8, 0x33, 0xa8, 0x19, 0xdb, 0xf1, 0xb3, 0x31, - 0x4b, 0x7b, 0xee, 0x3d, 0x0c, 0x71, 0x3a, 0x7c, 0xb7, 0xbc, 0x5e, 0x44, - 0x97, 0x99, 0xb8, 0x56, 0xee, 0x8a, 0xac, 0x72, 0x12, 0x38, 0xac, 0xe9, - 0x8d, 0x35, 0x05, 0x0a, 0x47, 0x27, 0xea, 0xd9, 0xbe, 0x21, 0xaa, 0xd5, - 0xb3, 0x57, 0x44, 0x15, 0xf9, 0xe7, 0x0d, 0x0d, 0x63, 0xc5, 0xa8, 0xe6, - 0x74, 0x9d, 0x52, 0xf4, 0xdd, 0x04, 0x1b, 0xea, 0x82, 0xe9, 0x5d, 0xca, - 0x43, 0xa5, 0x60, 0x6b, 0x16, 0xee, 0x1b, 0xe0, 0xc2, 0x28, 0x75, 0xad, - 0xb5, 0x87, 0xf2, 0xd2, 0x53, 0x32, 0x00, 0xa7, 0xe6, 0x15, 0xd0, 0x93, - 0x0d, 0x1f, 0x67, 0x56, 0xea, 0xaf, 0x98, 0xe4, 0x87, 0x04, 0x71, 0xfe, - 0xf9, 0x2e, 0xd0, 0x2d, 0x1f, 0x70, 0xa9, 0xee, 0x53, 0xec, 0xdb, 0xc7, - 0x3b, 0x3e, 0x42, 0x7e, 0xf3, 0x07, 0xdd, 0x6e, 0x3f, 0xca, 0x69, 0xcc, - 0xe3, 0x9b, 0x9b, 0xd6, 0xfd, 0xd2, 0x44, 0x27, 0xd5, 0xd0, 0x64, 0x2f, - 0xe8, 0x72, 0x26, 0x3c, 0xaf, 0x49, 0xcb, 0xb6, 0x69, 0xae, 0x95, 0xc1, - 0x24, 0x33, 0xc3, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x82, - 0x67, 0x09, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x2e, 0x17, 0x13, - 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xe7, 0x05, 0xea, 0x41, 0xb7, 0x59, 0x5c, - 0x7e, 0xe7, 0x05, 0xea, 0x05, 0xc5, 0x64, 0xf0, 0xff, 0xc1, 0x0a, 0xf4, - 0x42, 0x83, 0x33, 0x33, 0x5d, 0x04, 0x75, 0x9c, 0x85, 0x9a, 0x74, 0x0a, - 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, - 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x8e, 0xb4, 0xf5, - 0x90, 0xc1, 0x32, 0x90, 0x6a, 0xe5, 0x04, 0x8f, 0xcf, 0xc2, 0xed, 0xf7, - 0x79, 0x17, 0xfc, 0x2e, 0x73, 0xd6, 0xaa, 0xea, 0xfe, 0xb5, 0x0d, 0x3f, - 0x72, 0xf1, 0x5a, 0x24, 0x01, 0xcd, 0xda, 0x13, 0xc1, 0x2b, 0x8f, 0xa9, - 0x10, 0xf2, 0x28, 0xa0, 0x07, 0xbd, 0xc8, 0x20, 0x8c, 0x85, 0x74, 0x3c, - 0xcb, 0x87, 0xbd, 0x9f, 0x3f, 0xf0, 0xd8, 0x56, 0x35, 0x47, 0x97, 0x13, - 0xc9, 0x22, 0x59, 0x2b, 0x71, 0x3f, 0x46, 0x44, 0xf1, 0x3d, 0x3f, 0xc8, - 0x44, 0x43, 0x4d, 0x5c, 0x56, 0x92, 0x3a, 0x3b, 0x00, 0xb0, 0xc1, 0x42, - 0x91, 0xf8, 0xa5, 0x17, 0x42, 0xa8, 0x6a, 0x4d, 0x1e, 0xfd, 0x6f, 0x05, - 0xfb, 0x89, 0x38, 0x46, 0x67, 0x9f, 0x6d, 0xe5, 0x3b, 0xd5, 0xb1, 0xcc, - 0x8b, 0xa9, 0x67, 0x6f, 0x67, 0x1b, 0x5d, 0x7c, 0xe0, 0x0f, 0xd4, 0xdf, - 0x6e, 0xd1, 0x4a, 0xbb, 0x53, 0x57, 0x47, 0xe8, 0x0c, 0xe7, 0x64, 0x54, - 0x4f, 0x57, 0xb6, 0x8e, 0xce, 0xb3, 0x88, 0x70, 0x36, 0x06, 0x0f, 0xdc, - 0xa8, 0x1d, 0xda, 0x06, 0x2b, 0x03, 0xbb, 0xa4, 0x9d, 0x70, 0xb2, 0x04, - 0xa3, 0xfd, 0x9d, 0x8b, 0x6f, 0x89, 0x74, 0x3a, 0xff, 0xf5, 0x2f, 0x30, - 0x34, 0xb1, 0x6b, 0x21, 0xe3, 0xe9, 0x3a, 0xe0, 0x87, 0x17, 0xf5, 0xb4, - 0x81, 0xf2, 0x8f, 0x5e, 0x86, 0xf1, 0x69, 0x5e, 0x99, 0x20, 0x4c, 0x13, - 0xf6, 0x45, 0x46, 0x54, 0x8a, 0x96, 0xfb, 0x83, 0xee, 0xd3, 0x18, 0xd3, - 0x75, 0xa0, 0x6f, 0x32, 0x71, 0xde, 0x4c, 0x92, 0x22, 0x06, 0xca, 0xd0, - 0x9e, 0x1b, 0x32, 0xb5, 0xc9, 0x6c, 0x7e, 0x5f, 0xd1, 0x34, 0xfa, 0xb6, - 0x70, 0x8c, 0x7d, 0xcd, 0x68, 0x86, 0xd0, 0xb6, 0x97, 0x6d, 0x78, 0x96, - 0x48, 0x96, 0xe5, 0x28, 0x28, 0x87, 0xe1, 0xa6, 0xcc, 0x7f, 0x9c, 0x44, - 0x2e, 0xa4, 0x86, 0xef, 0xa9, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, - 0x75, 0x82, 0x54, 0x0d, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x08, - 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xe0, 0x01, 0x3f, 0x41, 0xb7, - 0x59, 0x5c, 0x83, 0xe0, 0x01, 0x3f, 0x59, 0x27, 0x33, 0x2f, 0x22, 0x90, - 0x8f, 0xdf, 0x8f, 0x07, 0xfa, 0xa9, 0xeb, 0x8d, 0x26, 0x20, 0xc7, 0xc6, - 0x2a, 0x20, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, - 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, - 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa1, 0x9c, - 0xa0, 0x45, 0x5c, 0x35, 0x23, 0x76, 0xa8, 0xd0, 0x2d, 0x3f, 0xa5, 0x6d, - 0x7a, 0x4d, 0xe6, 0xc5, 0x95, 0x1d, 0xea, 0xcf, 0xd5, 0x75, 0x93, 0x57, - 0x57, 0xc1, 0x28, 0xc0, 0xb2, 0x8f, 0x42, 0x7f, 0x45, 0xd2, 0x6c, 0xc3, - 0xec, 0xe7, 0x48, 0x15, 0xf5, 0xb1, 0x10, 0xf3, 0xbc, 0x0e, 0x78, 0xef, - 0x2f, 0x15, 0x65, 0x7d, 0xe4, 0x09, 0xb7, 0x34, 0x5b, 0x66, 0x24, 0x0c, - 0x93, 0x63, 0xd8, 0xdc, 0xfd, 0x47, 0x1c, 0xeb, 0x4a, 0xd3, 0x86, 0x57, - 0x49, 0xb7, 0x8e, 0x15, 0x47, 0xa1, 0x61, 0xd8, 0x0a, 0x07, 0xb0, 0x97, - 0x08, 0x48, 0x99, 0x2b, 0x88, 0xcf, 0xe5, 0xe8, 0xd3, 0xda, 0xc2, 0xae, - 0x50, 0xd6, 0xbb, 0x64, 0xbf, 0x7a, 0x1f, 0xc8, 0xbe, 0x29, 0x6e, 0x8d, - 0xf1, 0x18, 0x7c, 0xf7, 0x13, 0x78, 0xf6, 0x23, 0x35, 0x9b, 0xf8, 0xf3, - 0x42, 0x4a, 0x5d, 0xef, 0x7d, 0x20, 0x62, 0x2e, 0xa6, 0xb5, 0xce, 0x94, - 0x0a, 0xfd, 0x8b, 0xf9, 0x12, 0xea, 0x53, 0x13, 0x45, 0x9d, 0xdd, 0x66, - 0x7d, 0x42, 0xb2, 0x3f, 0x65, 0xc4, 0x0d, 0xf8, 0x6d, 0xda, 0x0e, 0xe6, - 0x45, 0x35, 0xd4, 0x90, 0xc3, 0x9b, 0x8b, 0xb4, 0x39, 0xf1, 0x4f, 0x70, - 0x4a, 0x7f, 0x51, 0x1d, 0x3d, 0x80, 0x95, 0x4b, 0xd2, 0xb0, 0xd7, 0xb7, - 0xfe, 0xa8, 0x40, 0x38, 0x95, 0x48, 0x27, 0xf8, 0x23, 0xb9, 0xb0, 0xfe, - 0x58, 0x3a, 0x8e, 0x1a, 0x53, 0xf3, 0xa4, 0x59, 0xf9, 0xba, 0x9d, 0x9d, - 0x24, 0x8b, 0xe6, 0x39, 0xc1, 0xaf, 0x86, 0xdc, 0xf7, 0x27, 0x0d, 0x0b, - 0x85, 0xc4, 0x9d, 0x25, 0xb8, 0x81, 0xd4, 0x5d, 0xc2, 0x6a, 0xe4, 0x96, - 0x42, 0x87, 0xaa, 0x67, 0x17, 0xe1, 0x23, 0xa1, 0x32, 0x62, 0xa2, 0x65, - 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x00, 0x00, 0x00, 0x1f, - 0x7d, 0x89, 0x47, 0x47, 0xf5, 0xb7, 0xed, 0xb4, 0x95, 0xd6, 0x75, 0x78, - 0xeb, 0x1d, 0x4e, 0xa4, 0x3c, 0x47, 0x73, 0x5e, 0x8d, 0xd2, 0xd4, 0x7c, - 0xc6, 0x32, 0x4b, 0x5d, 0xc7, 0x78, 0xa2, 0xc7, 0xbd, 0xca, 0x06, 0x92, - 0xf9, 0xba, 0x4d, 0x7d, 0xe3, 0xe0, 0xf8, 0x0a, 0xec, 0x73, 0x88, 0xb6, - 0xab, 0x6d, 0x37, 0x6d, 0x37, 0xd2, 0xa5, 0x3d, 0xa8, 0xd0, 0x47, 0x7b, - 0xa1, 0x58, 0xf7, 0x07, 0x73, 0x23, 0x49, 0xfb, 0xa0, 0x7e, 0xae, 0x30, - 0x88, 0x4c, 0x2b, 0x75, 0x91, 0xd7, 0xe3, 0x5d, 0x80, 0x06, 0x12, 0xcc, - 0xb4, 0xe9, 0xdc, 0xc6, 0x01, 0x48, 0x91, 0x2a, 0x38, 0x93, 0x26, 0xee, - 0x01, 0x8a, 0xad, 0xdb, 0x02, 0xdc, 0x54, 0x5a, 0x08, 0x18, 0xf8, 0xe1, - 0xc2, 0x63, 0x80, 0x13, 0xd4, 0x4c, 0x06, 0xf0, 0x1d, 0x60, 0x66, 0x75, - 0x25, 0x43, 0xb9, 0xa1, 0x2b, 0xc7, 0x54, 0x81, 0x91, 0x2d, 0x66, 0xb2, - 0x74, 0xe7, 0x90, 0x8e, 0xd4, 0x03, 0xca, 0xef, 0x9a, 0x13, 0xfe, 0x40, - 0xf8, 0x42, 0x77, 0x52, 0x5b, 0xae, 0x22, 0xd0, 0x6b, 0xb6, 0x77, 0x41, - 0xff, 0x96, 0x80, 0xbc, 0x8f, 0xfa, 0xa1, 0xb6, 0xe4, 0xf1, 0x93, 0x1d, - 0x91, 0x96, 0x7b, 0x84, 0xc7, 0x60, 0x7e, 0x80, 0x98, 0xcd, 0x7b, 0x12, - 0x11, 0x41, 0x90, 0x33, 0x96, 0xc0, 0xeb, 0x6b, 0x9f, 0xb4, 0x1a, 0x2c, - 0x46, 0x80, 0xf0, 0x56, 0xe2, 0x4b, 0x32, 0x3c, 0x6a, 0xa1, 0x94, 0xca, - 0x46, 0xb4, 0x06, 0x63, 0x85, 0xcf, 0x62, 0x20, 0x79, 0xf2, 0x03, 0x97, - 0xa0, 0xa0, 0x44, 0x7b, 0x8e, 0x39, 0x16, 0xca, 0xe0, 0xb2, 0x04, 0x79, - 0xf8, 0x55, 0xf7, 0xe6, 0x3c, 0x3f, 0x67, 0x2f, 0x2b, 0x75, 0x39, 0x55, - 0x12, 0xd5, 0x85, 0xd4, 0x22, 0x37, 0xb6, 0x8c, 0x40, 0x47, 0x51, 0x11, - 0x88, 0xa1, 0xfa, 0x8f, 0x2d, 0x43, 0x41, 0x0a, 0x58, 0xe3, 0x38, 0x94, - 0xa0, 0xe1, 0xda, 0x1e, 0x7b, 0x07, 0x74, 0xc5, 0xe4, 0xd1, 0xb7, 0x3f, - 0xed, 0x46, 0x1e, 0x35, 0x84, 0x7c, 0x58, 0x3d, 0xc3, 0x99, 0x9f, 0x3f, - 0x0e, 0x30, 0x4f, 0xd5, 0xf4, 0x5d, 0x09, 0xef, 0x01, 0xe3, 0xa3, 0xbc, - 0x17, 0x74, 0xa4, 0x28, 0x5f, 0xab, 0xe5, 0x71, 0x66, 0x34, 0x2e, 0x29, - 0x2a, 0x24, 0xbb, 0x6d, 0x41, 0x16, 0x76, 0x86, 0x15, 0x67, 0xb5, 0x07, - 0x60, 0x13, 0xd2, 0x11, 0xa6, 0x90, 0x22, 0xc4, 0x17, 0x76, 0x38, 0x3a, - 0xaf, 0x51, 0xee, 0x4c, 0x9b, 0xfa, 0x84, 0x25, 0xd9, 0x6d, 0xd3, 0x8d, - 0x3e, 0xb2, 0x95, 0xd7, 0x8a, 0x83, 0x19, 0xaf, 0x7a, 0x2f, 0x6b, 0x87, - 0x36, 0x9e, 0xa3, 0x48, 0xdd, 0x8e, 0xe0, 0xdc, 0x40, 0xf3, 0xb7, 0xb4, - 0x3f, 0x95, 0x70, 0x5b, 0x67, 0xf7, 0xa1, 0xe9, 0x91, 0x7a, 0x94, 0xd1, - 0x81, 0xcc, 0xeb, 0x55, 0xb7, 0xc6, 0xd9, 0x0d, 0x59, 0x4a, 0x9f, 0x37, - 0x06, 0x6a, 0xda, 0x4e, 0xd3, 0xef, 0x35, 0x18, 0xa3, 0x90, 0x19, 0x72, - 0x2e, 0xcd, 0x03, 0x61, 0xf7, 0xb2, 0x0f, 0x69, 0x50, 0x47, 0x2f, 0xb3, - 0x10, 0x4a, 0xb1, 0x5d, 0xe8, 0x5a, 0x36, 0x07, 0xd6, 0x95, 0x03, 0x17, - 0x50, 0x1f, 0xa2, 0x58, 0x01, 0x0d, 0xfc, 0x8d, 0xcc, 0xf2, 0x6c, 0x4d, - 0x2f, 0x58, 0x02, 0xb6, 0x5e, 0x7c, 0x6f, 0x47, 0x3e, 0x13, 0x62, 0x33, - 0xc3, 0x7f, 0x64, 0x88, 0x30, 0x45, 0x5a, 0x6a, 0x8f, 0x49, 0x9a, 0xd1, - 0x6e, 0xf4, 0x3a, 0x3a, 0x9b, 0x50, 0x50, 0x8b, 0x59, 0x36, 0xbc, 0x0c, - 0x2c, 0x73, 0xec, 0x21, 0x0c, 0x95, 0xca, 0x32, 0x28, 0x07, 0x85, 0x91, - 0x0a, 0x90, 0xfe, 0x5a, 0x9d, 0x11, 0x09, 0xa2, 0x38, 0x9b, 0x0f, 0x22, - 0xc1, 0x44, 0x09, 0xca, 0x50, 0xe0, 0x4e, 0x01, 0x24, 0xef, 0x8a, 0x58, - 0xa5, 0x56, 0x69, 0x9b, 0x2e, 0x72, 0xf5, 0xb2, 0xbe, 0xa3, 0xca, 0x84, - 0x36, 0x36, 0x84, 0xb0, 0x88, 0x88, 0x74, 0x60, 0xc3, 0xf2, 0x6b, 0x19, - 0x44, 0xb6, 0x8b, 0x02, 0x38, 0x7d, 0x6e, 0x26, 0x89, 0x37, 0xae, 0xc5, - 0x67, 0x9c, 0x4e, 0x5b, 0xeb, 0x68, 0xc1, 0x3a, 0xb9, 0x10, 0xad, 0x10, - 0x00, 0x1f, 0x6a, 0x9a, 0xfe, 0x6a, 0x7e, 0x03, 0xcc, 0x7d, 0x0d, 0x37, - 0xea, 0x91, 0xfa, 0xf4, 0xdb, 0x22, 0x9b, 0x91, 0x70, 0x07, 0x6d, 0xa8, - 0xd6, 0x95, 0x49, 0x66, 0xd6, 0xbc, 0xd1, 0x57, 0x6e, 0xa5, 0x1c, 0x96, - 0x16, 0xaf, 0x94, 0xa5, 0x00, 0x06, 0x38, 0x55, 0xe9, 0xdc, 0xb8, 0x38, - 0x66, 0x26, 0x2d, 0xac, 0x1a, 0xff, 0x95, 0x52, 0xa3, 0x97, 0x58, 0xd9, - 0xe9, 0x35, 0x54, 0x3d, 0x6a, 0xae, 0xe6, 0xcd, 0x00, 0xbe, 0x68, 0x83, - 0x05, 0x5a, 0x65, 0xb8, 0x8c, 0x94, 0x87, 0x6c, 0x27, 0x82, 0x7b, 0x4a, - 0x48, 0x1e, 0x6e, 0x42, 0xc1, 0xe5, 0xd8, 0x25, 0x9b, 0x8a, 0xe4, 0x2b, - 0x85, 0x6f, 0x40, 0x75, 0x65, 0x9e, 0xc5, 0x03, 0xd1, 0x14, 0x82, 0x91, - 0x15, 0x59, 0x66, 0x48, 0x13, 0xfe, 0xd3, 0x17, 0x1e, 0xff, 0xec, 0x58, - 0x43, 0xb5, 0xb9, 0xbf, 0xad, 0x33, 0xb2, 0x91, 0xe2, 0xb5, 0x3b, 0x57, - 0xd6, 0xb1, 0x55, 0x6c, 0xa2, 0xac, 0x7f, 0x5e, 0x9b, 0x28, 0xa7, 0x98, - 0x44, 0x46, 0x1d, 0x30, 0x16, 0x2f, 0xa5, 0x35, 0x85, 0x68, 0xaa, 0x92, - 0x0f, 0x51, 0xb3, 0x88, 0x42, 0xf3, 0x8d, 0xa0, 0x06, 0x8f, 0x91, 0xcf, - 0xf4, 0x8f, 0xbc, 0x95, 0xb1, 0x57, 0xa5, 0x61, 0xd9, 0x1e, 0x40, 0x29, - 0x79, 0x63, 0x84, 0xfd, 0xf5, 0x93, 0xd4, 0x5b, 0xb9, 0xdf, 0x5d, 0x56, - 0xc5, 0xfb, 0xcb, 0xee, 0x1f, 0x3b, 0x9c, 0x02, 0x0c, 0x7d, 0x7f, 0xbb, - 0x81, 0x8d, 0xbb, 0xa5, 0x83, 0x5c, 0x4f, 0xf1, 0x08, 0xf8, 0x18, 0x87, - 0xab, 0x74, 0x5c, 0xa7, 0x57, 0xa8, 0xcf, 0xf4, 0x2f, 0xcc, 0xd2, 0xcc, - 0x5b, 0x99, 0x00, 0xbc, 0xe5, 0x06, 0x42, 0x24, 0xc9, 0xf0, 0x23, 0x45, - 0x60, 0xf1, 0x34, 0xb0, 0x99, 0xb4, 0x24, 0x94, 0x71, 0x76, 0x16, 0x32, - 0x2d, 0xb5, 0x98, 0x38, 0x9e, 0x02, 0xe4, 0x1b, 0xc9, 0x3f, 0x20, 0xa3, - 0x94, 0xc2, 0x4c, 0xff, 0x81, 0x95, 0x05, 0xd5, 0x8c, 0x13, 0xd2, 0xb8, - 0x54, 0xf5, 0x55, 0xff, 0x4a, 0xfa, 0xd0, 0x93, 0xa7, 0x49, 0x5f, 0x43, - 0x6d, 0x23, 0x3e, 0x5f, 0x37, 0xb1, 0x05, 0xb1, 0xc7, 0x99, 0xb5, 0xab, - 0xbe, 0x04, 0x65, 0xef, 0xb0, 0x79, 0x62, 0x47, 0xbc, 0x7b, 0x57, 0x74, - 0xea, 0xac, 0x2d, 0x45, 0xfc, 0x65, 0x26, 0x3d, 0xf7, 0x91, 0x0e, 0xbd, - 0x78, 0x78, 0x72, 0x6b, 0x8a, 0xfe, 0x8d, 0x6e, 0x03, 0x6d, 0x0c, 0x3a, - 0x52, 0xb5, 0xc4, 0x9c, 0x7d, 0x82, 0xdd, 0x52, 0x75, 0xb7, 0xe3, 0xe3, - 0xff, 0xfc, 0x31, 0xa9, 0xc6, 0xd7, 0xa4, 0x1d, 0x05, 0xde, 0x8b, 0x82, - 0x1d, 0x7d, 0xd0, 0xb3, 0x25, 0xcc, 0x45, 0xce, 0x8e, 0x4c, 0x2b, 0xca, - 0x60, 0x15, 0x6c, 0xba, 0x5d, 0x6b, 0x41, 0x22, 0x62, 0x05, 0xef, 0x55, - 0x04, 0x84, 0x2e, 0x14, 0xe6, 0x5e, 0x23, 0x83, 0x82, 0x39, 0xbe, 0x79, - 0xd1, 0x29, 0xe3, 0xac, 0x54, 0x63, 0x03, 0xf9, 0xa0, 0xb7, 0xb7, 0xd4, - 0x37, 0xdc, 0x91, 0xfc, 0x1e, 0x96, 0xe9, 0xcc, 0x66, 0x6b, 0xa4, 0x67, - 0xb8, 0xc8, 0xed, 0x69, 0x4f, 0x08, 0xa2, 0xaf, 0x34, 0x3b, 0xcb, 0x70, - 0xf2, 0x8c, 0xae, 0xc9, 0x2e, 0x96, 0xe3, 0x47, 0x31, 0x36, 0x13, 0x62, - 0xc8, 0xcc, 0x18, 0x7f, 0x48, 0xea, 0x2e, 0xf4, 0x87, 0x09, 0xa2, 0x68, - 0x19, 0xf7, 0x30, 0x8b, 0x72, 0x65, 0xa6, 0x9f, 0xf3, 0x96, 0x22, 0x68, - 0x59, 0x72, 0x69, 0x2f, 0xdd, 0x88, 0x4c, 0x04, 0xd2, 0xb9, 0x71, 0x0c, - 0xd7, 0x2d, 0xd7, 0xef, 0xce, 0x33, 0x7f, 0x5a, 0xe7, 0x80, 0xba, 0x85, - 0xc0, 0xd3, 0x83, 0x27, 0xe9, 0x11, 0x40, 0x67, 0xb7, 0xf7, 0x8f, 0x8e, - 0x8f, 0x93, 0x7d, 0xfb, 0x04, 0x0f, 0x1e, 0x6d, 0xd7, 0xa9, 0xc6, 0x53, - 0x29, 0x58, 0x55, 0xe5, 0x2d, 0xe1, 0x05, 0xe3, 0x00, 0x3b, 0x6f, 0xb9, - 0xdd, 0x5f, 0x42, 0x47, 0x0a, 0x79, 0x43, 0xef, 0x84, 0x47, 0x6d, 0x37, - 0xba, 0x37, 0xb3, 0xef, 0xae, 0x0b, 0xc9, 0x45, 0x32, 0x1a, 0x9a, 0x94, - 0x3f, 0xb8, 0xc7, 0x72, 0xd8, 0x90, 0xb1, 0x61, 0x62, 0xe0, 0x0f, 0xd1, - 0xef, 0x94, 0x04, 0x2f, 0xff, 0xd6, 0x7e, 0x14, 0x81, 0xb8, 0x62, 0xcc, - 0x4e, 0x76, 0x0a, 0xc6, 0x1f, 0x58, 0x51, 0xa1, 0x14, 0xe8, 0xde, 0x2f, - 0xe6, 0x2e, 0xb2, 0xe2, 0xda, 0x24, 0x47, 0xe1, 0xcf, 0x26, 0x2a, 0xfc, - 0xb1, 0xbf, 0xae, 0x1a, 0xb0, 0x4d, 0x3d, 0x97, 0x4d, 0x18, 0xfb, 0x0d, - 0x00, 0x64, 0x40, 0x75, 0x6a, 0x78, 0x3a, 0x60, 0xda, 0x54, 0x06, 0x92, - 0xb6, 0xa9, 0x1c, 0x36, 0xeb, 0x26, 0x46, 0x10, 0x0d, 0x5d, 0x3e, 0x13, - 0xca, 0x7e, 0xb1, 0xbb, 0xa7, 0x37, 0x71, 0x7c, 0x09, 0xd4, 0x5d, 0xd4, - 0x59, 0xb0, 0x46, 0x37, 0x06, 0x2a, 0xdb, 0xd3, 0x0c, 0x26, 0x0a, 0x9d, - 0x18, 0x65, 0x8a, 0xb4, 0xf1, 0x1b, 0xfd, 0x50, 0x32, 0x6a, 0xa9, 0x2f, - 0x0c, 0x46, 0x1f, 0x9b, 0x50, 0x86, 0xf1, 0x91, 0xf0, 0xe0, 0xc2, 0x8d, - 0x84, 0x8e, 0xfe, 0x6d, 0x1e, 0x6e, 0xd4, 0x93, 0xf1, 0x56, 0x4b, 0x3b, - 0x20, 0x10, 0x1f, 0x6a, 0xc5, 0xf3, 0x8c, 0x2f, 0x88, 0x32, 0x28, 0xbe, - 0x05, 0x9a, 0x1b, 0x7d, 0x1b, 0xaa, 0x2d, 0xa5, 0xe4, 0x82, 0xd0, 0xf3, - 0x65, 0x5a, 0xd5, 0xa5, 0x3e, 0xdd, 0xee, 0x98, 0x03, 0xf4, 0x63, 0x6e, - 0xe5, 0x60, 0x35, 0x54, 0xf9, 0xf8, 0x5c, 0x8c, 0x02, 0x5f, 0xa5, 0xf3, - 0xb2, 0xf8, 0x47, 0xce, 0x74, 0xbc, 0xf5, 0xcc, 0x1e, 0x0f, 0x8b, 0x6f, - 0x1f, 0xd3, 0x11, 0x2d, 0x10, 0x40, 0x5d, 0xb2, 0x45, 0x6f, 0xd3, 0xc3, - 0x44, 0xc5, 0x74, 0xab, 0x29, 0x2f, 0x4c, 0x7e, 0xc8, 0x57, 0xcb, 0xaf, - 0x0b, 0x44, 0x12, 0xa2, 0x1d, 0x3b, 0x1c, 0xfa, 0xf5, 0xd3, 0xe6, 0x75, - 0x4e, 0xc7, 0x04, 0x99, 0xd8, 0x32, 0x14, 0x83, 0xda, 0x35, 0xf0, 0xfa, - 0x67, 0x15, 0x8d, 0xab, 0xa9, 0x30, 0x12, 0xd0, 0x4a, 0xb6, 0x09, 0x20, - 0x89, 0x19, 0xee, 0x60, 0x4b, 0x97, 0xd2, 0x38, 0x2a, 0x57, 0x36, 0x22, - 0xe9, 0x02, 0x2f, 0x2d, 0x30, 0x93, 0x88, 0x14, 0x99, 0xa3, 0x31, 0x93, - 0x2a, 0x33, 0x58, 0xae, 0xe6, 0xe6, 0xcc, 0x89, 0x02, 0x95, 0x52, 0xe3, - 0x60, 0xed, 0xd5, 0x9d, 0xac, 0x7f, 0x1f, 0x35, 0x54, 0xd6, 0x89, 0x8e, - 0xed, 0x13, 0x7f, 0xe6, 0xce, 0xba, 0xe7, 0x00, 0x30, 0x7f, 0x46, 0x25, - 0xdc, 0xb3, 0x22, 0xac, 0xef, 0x54, 0xef, 0x17, 0xf8, 0xdc, 0xc4, 0x12, - 0xdb, 0x40, 0xe8, 0x20, 0x7a, 0x1b, 0x5a, 0x6b, 0x37, 0x8d, 0x46, 0xfd, - 0x26, 0xa5, 0x1f, 0x24, 0xb3, 0xaa, 0xe4, 0xb6, 0x1c, 0x93, 0xd9, 0x77, - 0xc2, 0x66, 0xf7, 0x0a, 0xf8, 0xca, 0xa1, 0xfb, 0xa6, 0x78, 0x9c, 0xc3, - 0x7f, 0x40, 0x63, 0x9a, 0x98, 0x52, 0x23, 0xb2, 0x51, 0x0f, 0xab, 0xf2, - 0xa0, 0x41, 0x87, 0x79, 0x18, 0x2e, 0x50, 0x8a, 0x6a, 0x99, 0xc7, 0xef, - 0x0c, 0x33, 0xee, 0xf2, 0x76, 0x26, 0x40, 0x4b, 0xb7, 0x75, 0xb0, 0x8c, - 0x99, 0x8c, 0x96, 0x8a, 0xc3, 0xb6, 0xfd, 0xa2, 0x62, 0x49, 0x29, 0x8c, - 0xc4, 0xfe, 0xc8, 0xe9, 0x89, 0xeb, 0xc7, 0x59, 0x08, 0x99, 0xd3, 0x73, - 0xea, 0x64, 0x50, 0x9d, 0x09, 0x36, 0xe3, 0x85, 0xc4, 0xac, 0x3e, 0x87, - 0x11, 0x5d, 0xf4, 0x5b, 0x21, 0x91, 0xf6, 0x34, 0xfb, 0x08, 0x15, 0xd2, - 0xe1, 0xcb, 0x8c, 0x72, 0xca, 0x88, 0xd6, 0xb1, 0x65, 0xd4, 0xd7, 0x6e, - 0x10, 0x7b, 0x15, 0x0f, 0x41, 0xd7, 0x12, 0x49, 0xcc, 0x8d, 0x39, 0x13, - 0x9c, 0x22, 0x1d, 0x15, 0x43, 0xc1, 0x8a, 0x6f, 0xf3, 0x1d, 0x46, 0x74, - 0xb3, 0x1f, 0xa4, 0xbd, 0x17, 0x20, 0x69, 0x57, 0x53, 0x2c, 0x6a, 0xec, - 0x29, 0xac, 0x02, 0xb1, 0x47, 0x83, 0xf0, 0x2f, 0xc9, 0x20, 0xcc, 0x14, - 0xf0, 0xe4, 0x4f, 0x43, 0xe1, 0x98, 0x3d, 0xbd, 0x2c, 0x48, 0x7f, 0xd5, - 0xd6, 0x33, 0x98, 0xd2, 0x9d, 0xa8, 0xe0, 0xb1, 0x85, 0xe0, 0x14, 0x96, - 0xec, 0xde, 0x18, 0xc4, 0xe9, 0x8f, 0x67, 0x24, 0x48, 0x6c, 0xf9, 0xaf, - 0xfb, 0x89, 0xd1, 0x35, 0xc9, 0x0d, 0xe9, 0x22, 0x08, 0xef, 0x8b, 0x27, - 0x9d, 0x18, 0xa1, 0x19, 0x7d, 0x20, 0xd1, 0xc1, 0x1b, 0x99, 0x59, 0xea, - 0xba, 0xae, 0xe4, 0x09, 0xd4, 0xb6, 0x23, 0x08, 0x5f, 0x0c, 0x0b, 0x49, - 0x69, 0x8a, 0x36, 0x02, 0xf5, 0x32, 0x3e, 0xfb, 0xb4, 0xdb, 0x45, 0x9d, - 0x19, 0x9d, 0x4b, 0xcf, 0xee, 0xa7, 0xbc, 0x5a, 0x06, 0x4e, 0x43, 0x52, - 0xd3, 0xd2, 0x4a, 0x0e, 0x21, 0x08, 0xd6, 0xc0, 0x93, 0x7d, 0xe8, 0xff, - 0x04, 0xd4, 0xef, 0xe8, 0x0d, 0xd1, 0xe7, 0x74, 0xf2, 0x56, 0x66, 0x51, - 0x4c, 0x79, 0xf4, 0x12, 0x9f, 0xf4, 0xd2, 0x61, 0x12, 0x60, 0xc2, 0xfb, - 0x98, 0x5c, 0xed, 0x73, 0x13, 0x06, 0xa7, 0xce, 0x86, 0xea, 0x65, 0x26, - 0xc0, 0xfc, 0xe6, 0xc1, 0xdb, 0xe0, 0xcc, 0x13, 0xd3, 0x63, 0x5f, 0x2d, - 0xfb, 0x5a, 0x95, 0x9e, 0x27, 0x05, 0x3d, 0xd0, 0x1b, 0xaf, 0x29, 0x79, - 0x70, 0x69, 0x12, 0xc7, 0xe6, 0xc2, 0x57, 0x40, 0x31, 0xcb, 0x50, 0xd4, - 0xfe, 0xf3, 0xb1, 0x3e, 0x79, 0xdb, 0xcf, 0xdd, 0x9a, 0x86, 0x2a, 0x58, - 0xb3, 0x51, 0xe6, 0x74, 0x9f, 0x1e, 0xbd, 0xb1, 0x57, 0xd8, 0xa9, 0xe8, - 0xbf, 0x5e, 0x15, 0xcf, 0x2c, 0x4b, 0x00, 0x88, 0x8d, 0x10, 0x15, 0x25, - 0xeb, 0x36, 0xe6, 0x4b, 0x9c, 0xe5, 0x82, 0x26, 0x6e, 0x61, 0xb3, 0x69, - 0xf4, 0x4c, 0x21, 0x15, 0x64, 0x36, 0x0c, 0x8e, 0x77, 0xc1, 0x89, 0xd5, - 0xfd, 0xb0, 0x81, 0x7c, 0x90, 0x7d, 0xdf, 0xd3, 0xe5, 0xc9, 0xd8, 0x4f, - 0xc5, 0x85, 0x12, 0xb7, 0x02, 0x63, 0xb7, 0x24, 0x2c, 0xeb, 0xb5, 0x89, - 0x59, 0x44, 0x2b, 0xa3, 0x8e, 0xfd, 0x42, 0x48, 0x57, 0x57, 0x17, 0x71, - 0xec, 0xe0, 0x0e, 0x72, 0xfc, 0x6c, 0xa2, 0xa5, 0xfb, 0xd3, 0x17, 0xb7, - 0x1a, 0x19, 0xe4, 0x93, 0x22, 0x4d, 0xde, 0x22, 0x4f, 0xb8, 0x42, 0x3a, - 0x06, 0xa7, 0x35, 0x20, 0x57, 0xc4, 0xe6, 0x0c, 0x7f, 0xae, 0x59, 0xfe, - 0xe6, 0xe7, 0x17, 0x0c, 0xec, 0x33, 0x4d, 0x6e, 0x0a, 0xd8, 0x6e, 0xe2, - 0x27, 0x39, 0x3e, 0x32, 0x1b, 0xf8, 0x9d, 0xd5, 0xdb, 0x38, 0xee, 0xe6, - 0x58, 0xbf, 0xfa, 0x05, 0xc0, 0x7e, 0xf1, 0x70, 0x43, 0x8d, 0xc5, 0x5f, - 0xd1, 0xb8, 0x5f, 0xe2, 0xb4, 0xd7, 0x81, 0xd7, 0x04, 0x8d, 0x06, 0x99, - 0x7f, 0x0b, 0x87, 0xea, 0xe3, 0x9a, 0x51, 0xd4, 0xd4, 0x47, 0xeb, 0x29, - 0x98, 0x56, 0xa7, 0x2f, 0x07, 0xa3, 0x04, 0x88, 0xe9, 0x13, 0x4f, 0xac, - 0x0f, 0x29, 0xda, 0xc7, 0x53, 0x2c, 0x9d, 0x00, 0x7a, 0x9e, 0x7a, 0x74, - 0xac, 0xce, 0xf2, 0xfa, 0xe6, 0xd5, 0xa2, 0x0c, 0xab, 0x80, 0xa9, 0x9f, - 0x46, 0x39, 0xe6, 0x8c, 0xc8, 0xf3, 0x90, 0xca, 0x9e, 0xb6, 0xdd, 0x0c, - 0xf9, 0xe6, 0x8c, 0x83, 0x46, 0xb0, 0x12, 0xe3, 0x47, 0xba, 0x12, 0x7b, - 0xf5, 0xb7, 0xe6, 0x49, 0x8c, 0x78, 0x45, 0xc2, 0xa3, 0x7a, 0xdf, 0x47, - 0xa9, 0x80, 0x41, 0x03, 0x29, 0x7f, 0xeb, 0xa1, 0xa8, 0x4b, 0x4f, 0xa8, - 0x41, 0x57, 0xb9, 0xfe, 0x06, 0xa9, 0xce, 0xbc, 0x27, 0x81, 0xed, 0x1b, - 0xab, 0x19, 0x4a, 0xbf, 0x6b, 0xe0, 0xef, 0x58, 0xfb, 0xfa, 0xe3, 0xa1, - 0x85, 0x02, 0x0d, 0x57, 0x9b, 0x04, 0x2b, 0xc0, 0x8e, 0x21, 0x73, 0xdc, - 0x34, 0x21, 0x63, 0x1d, 0xaf, 0xd8, 0xe0, 0x42, 0xaa, 0x45, 0xe9, 0x3c, - 0x44, 0xc5, 0x22, 0x77, 0xc0, 0xe5, 0xa5, 0xf7, 0xa4, 0x83, 0x66, 0xad, - 0xc7, 0x4a, 0x32, 0xc6, 0x7e, 0xca, 0x8f, 0x35, 0xa7, 0x88, 0x64, 0x56, - 0x45, 0x25, 0xec, 0xfa, 0x85, 0x61, 0x34, 0x0d, 0x83, 0x92, 0x1e, 0xf0, - 0x58, 0x4c, 0x47, 0x93, 0xe5, 0x17, 0xaa, 0xe8, 0x22, 0x53, 0xa6, 0x9e, - 0x3d, 0xb1, 0x47, 0x25, 0x09, 0x93, 0x93, 0x9d, 0x08, 0x31, 0x5b, 0xdc, - 0x07, 0x1f, 0x82, 0xbc, 0x88, 0x31, 0xbd, 0xc3, 0xa6, 0x4d, 0x2a, 0xed, - 0xf9, 0xc2, 0x76, 0x1e, 0xa1, 0xfd, 0xca, 0x7e, 0xcd, 0x62, 0x83, 0x06, - 0xca, 0xf3, 0x13, 0xcd, 0x25, 0xa1, 0x45, 0x0c, 0x3a, 0xc3, 0xb1, 0x3b, - 0xf5, 0xa1, 0x12, 0x1e, 0x90, 0xff, 0xf6, 0x56, 0x06, 0x7b, 0x14, 0xb7, - 0x37, 0x5c, 0x7a, 0xe9, 0x7e, 0xca, 0x33, 0x05, 0xc0, 0x7c, 0xa7, 0xcd, - 0xb2, 0x11, 0x2a, 0x0c, 0xe7, 0x2b, 0x36, 0x11, 0x5f, 0xa6, 0xba, 0xc5, - 0x56, 0x6f, 0x7c, 0xb7, 0x8c, 0xee, 0x54, 0xa0, 0x8c, 0x59, 0x85, 0x22, - 0x98, 0xad, 0xbb, 0x93, 0x66, 0x23, 0xfa, 0x00, 0x81, 0x88, 0xb0, 0x0a, - 0x1d, 0xfb, 0x66, 0xa2, 0x14, 0x88, 0x2a, 0x4e, 0x41, 0xb4, 0x89, 0x91, - 0x6d, 0x73, 0x5a, 0x3c, 0x4f, 0xc9, 0xd3, 0xa3, 0x08, 0x10, 0xe0, 0xb2, - 0xc2, 0xda, 0xa1, 0x23, 0x91, 0x40, 0x92, 0x51, 0xa0, 0xf4, 0x92, 0x01, - 0xb1, 0xa7, 0xd1, 0x80, 0x1d, 0xf0, 0x30, 0x29, 0xed, 0x0b, 0xec, 0x80, - 0x02, 0x09, 0x4e, 0x8d, 0x3f, 0xdf, 0x7a, 0x53, 0xcf, 0xed, 0xad, 0x6c, - 0x1b, 0x9c, 0x6a, 0x25, 0xff, 0xc3, 0xd7, 0xe9, 0x99, 0xf8, 0xa6, 0x8d, - 0x3f, 0x4a, 0x17, 0xf1, 0xe4, 0x54, 0x2b, 0x55, 0x67, 0x4a, 0xd2, 0xee, - 0x29, 0x53, 0x44, 0x71, 0x87, 0x6c, 0x98, 0xef, 0x8f, 0x23, 0x06, 0xf5, - 0x56, 0x9d, 0x12, 0x1f, 0x9c, 0xe5, 0x22, 0x51, 0x6e, 0x5b, 0x41, 0x7e, - 0x89, 0x6f, 0x40, 0x4b, 0xd6, 0x81, 0xd1, 0x7f, 0x63, 0xd1, 0x3f, 0xa1, - 0x60, 0xe2, 0xe4, 0x01, 0x7b, 0x76, 0x86, 0xf5, 0x13, 0x4f, 0xa2, 0x50, - 0xaf, 0xc8, 0x74, 0xe3, 0x2f, 0x7a, 0xd0, 0x81, 0x3e, 0xcf, 0xfa, 0x31, - 0xeb, 0xc0, 0xc3, 0x07, 0xc7, 0xe8, 0xb2, 0x9a, 0x51, 0xb9, 0xf7, 0x98, - 0x55, 0x90, 0xce, 0xdd, 0x60, 0xac, 0xc9, 0x08, 0x5e, 0xe8, 0xae, 0xad, - 0x22, 0xed, 0x73, 0x29, 0xa1, 0x5f, 0x43, 0x27, 0x2f, 0xb9, 0x38, 0x78, - 0x9d, 0x32, 0x1f, 0xff, 0xe0, 0xf7, 0x77, 0x37, 0xdf, 0xd1, 0xcb, 0xf7, - 0x50, 0xcd, 0x4a, 0xe9, 0xdd, 0x21, 0x50, 0xa0, 0xf2, 0x7f, 0x73, 0x31, - 0xae, 0xfb, 0x6e, 0xb7, 0x99, 0x1a, 0x43, 0x16, 0x5a, 0x17, 0x3a, 0x77, - 0xf1, 0xc3, 0xa8, 0x33, 0xde, 0xc6, 0x5b, 0xe8, 0x59, 0x53, 0x19, 0xf9, - 0x7f, 0xc5, 0x20, 0x56, 0xfc, 0x99, 0x19, 0x38, 0x77, 0x92, 0xe4, 0x7c, - 0xf3, 0x96, 0xac, 0x22, 0x87, 0x16, 0x5d, 0x43, 0x43, 0x65, 0x4e, 0x46, - 0x45, 0x44, 0x2d, 0x3f, 0x7f, 0x9d, 0xf0, 0x0c, 0x0e, 0x5b, 0xf7, 0x5b, - 0x31, 0x71, 0xcd, 0x27, 0x5b, 0xa3, 0x4a, 0x7a, 0xef, 0x28, 0x1c, 0x9a, - 0x98, 0x26, 0x95, 0xda, 0x35, 0x8d, 0x0d, 0xce, 0x04, 0xa2, 0xed, 0x8a, - 0xbb, 0x46, 0xf7, 0xca, 0x2b, 0x92, 0xd7, 0x8d, 0xae, 0x1b, 0xf1, 0xe4, - 0x9d, 0x67, 0x5b, 0x03, 0x57, 0xd1, 0xf6, 0x1e, 0x8f, 0x03, 0x7d, 0x8d, - 0xb8, 0x4a, 0x74, 0x99, 0x0f, 0x76, 0x3d, 0xe7, 0xb3, 0x4f, 0xdb, 0x9f, - 0x5c, 0xa7, 0x1b, 0x23, 0xa7, 0x99, 0x48, 0x34, 0x65, 0x46, 0x32, 0x83, - 0xc8, 0xcb, 0xee, 0xb3, 0xab, 0xe8, 0x99, 0xc9, 0x8a, 0x50, 0x34, 0x15, - 0x13, 0x52, 0xda, 0x12, 0xbd, 0x20, 0x21, 0x41, 0x57, 0x2a, 0xa0, 0x2c, - 0xba, 0x6c, 0xa9, 0xed, 0xcb, 0x03, 0xc9, 0x10, 0x26, 0x9d, 0x31, 0x52, - 0xf2, 0x66, 0x88, 0x2e, 0x51, 0x80, 0x76, 0xc9, 0xce, 0xfb, 0x8a, 0x4a, - 0x10, 0x8c, 0x83, 0x34, 0xe9, 0x02, 0xfc, 0x4e, 0xfe, 0xaa, 0x6c, 0xd6, - 0xcc, 0x81, 0x5d, 0x45, 0xc8, 0xa6, 0xa0, 0x3a, 0xef, 0xa4, 0xc5, 0xf1, - 0xba, 0x32, 0x93, 0x12, 0x2b, 0x59, 0x68, 0x19, 0x21, 0xe8, 0xd2, 0x8f, - 0x1d, 0x38, 0xd3, 0x56, 0x54, 0x38, 0x1d, 0xbb, 0xa0, 0x69, 0xe4, 0x82, - 0xfc, 0x21, 0x55, 0xee, 0xf8, 0x84, 0x7b, 0xab, 0x5e, 0x83, 0x42, 0x7e, - 0x18, 0xab, 0x3b, 0x1b, 0xea, 0x0e, 0xa0, 0xbd, 0x74, 0x33, 0x6d, 0x8a, - 0xe6, 0x7f, 0xe9, 0x78, 0xcf, 0xc9, 0xfd, 0xb6, 0x95, 0x90, 0x0e, 0x76, - 0x1a, 0xce, 0xb5, 0x72, 0x3f, 0x48, 0xa2, 0xcc, 0x6b, 0xf6, 0x6e, 0x72, - 0xef, 0x0c, 0x5f, 0x1b, 0xb4, 0x61, 0x5d, 0xf2, 0xc3, 0x9f, 0x09, 0x5b, - 0x60, 0xd8, 0xfd, 0xb0, 0x12, 0xe3, 0xc3, 0xeb, 0x4a, 0x5b, 0x26, 0xf8, - 0x5c, 0xfe, 0xd8, 0x93, 0xf1, 0xc8, 0x38, 0x29, 0x2c, 0xfe, 0x76, 0xf8, - 0xf5, 0x7b, 0x1b, 0x48, 0x6e, 0x27, 0xc3, 0xc8, 0xba, 0x23, 0xa8, 0x23, - 0xa3, 0xae, 0x48, 0x24, 0x83, 0x13, 0x6c, 0xbb, 0xfe, 0x7c, 0x36, 0xf7, - 0x7e, 0xe6, 0x1b, 0xd8, 0x86, 0x39, 0xc1, 0x84, 0x89, 0x2d, 0x0e, 0x80, - 0x3f, 0xb9, 0x5f, 0x25, 0x05, 0x85, 0xfa, 0x34, 0x23, 0xb9, 0xfa, 0xa2, - 0x2b, 0xaa, 0x40, 0x6d, 0xd3, 0x9b, 0xc9, 0x6a, 0xf7, 0xe8, 0x60, 0x2b, - 0x38, 0xe2, 0x79, 0xc9, 0x37, 0x62, 0x7d, 0xe0, 0x7a, 0xb5, 0xc6, 0x1f, - 0x80, 0xb1, 0xba, 0x4a, 0xdc, 0x65, 0x99, 0x0d, 0xe4, 0xae, 0x7f, 0x79, - 0x27, 0x93, 0xe6, 0x89, 0xbf, 0xb6, 0xeb, 0x8b, 0x1d, 0xfc, 0xb2, 0x8f, - 0x41, 0x0d, 0x0d, 0xa6, 0x20, 0x8f, 0x14, 0xf7, 0x33, 0x0c, 0xbb, 0x79, - 0xa4, 0xf3, 0x03, 0x23, 0xe9, 0xa3, 0x0a, 0x8b, 0xc2, 0xa6, 0xe3, 0xd3, - 0xaf, 0x11, 0xd3, 0x00, 0xfe, 0x84, 0x36, 0x8e, 0x51, 0x62, 0x00, 0x8a, - 0xaf, 0x45, 0x34, 0xc7, 0x96, 0xc1, 0x48, 0x5f, 0xd7, 0xc4, 0xa1, 0x2e, - 0xf6, 0x86, 0x0e, 0x74, 0xfd, 0x0f, 0x2d, 0x70, 0x9a, 0x83, 0xa6, 0x47, - 0x91, 0x50, 0x9e, 0xf7, 0xbe, 0x00, 0xce, 0xe1, 0xe0, 0x93, 0x47, 0x0f, - 0x3c, 0x2b, 0x1b, 0x68, 0x34, 0x07, 0xc4, 0x28, 0x8f, 0x66, 0xb9, 0xb6, - 0xad, 0xfc, 0x53, 0x42, 0xbb, 0x21, 0x00, 0x35, 0xe7, 0x74, 0xd8, 0x36, - 0x66, 0x7c, 0x54, 0xc2, 0x59, 0xe4, 0x11, 0x52, 0x8f, 0xdb, 0xb5, 0x46, - 0xe6, 0xb3, 0x16, 0x6a, 0xf5, 0x79, 0x51, 0x11, 0x56, 0x13, 0xa9, 0xfe, - 0x39, 0xe7, 0xfe, 0x27, 0x86, 0x05, 0x2a, 0xde, 0x90, 0x43, 0xa3, 0x84, - 0x41, 0x78, 0x24, 0xfb, 0xe3, 0x4f, 0x42, 0xc1, 0x56, 0x65, 0x45, 0xab, - 0x8d, 0x69, 0x42, 0x6d, 0x44, 0x22, 0x19, 0x50, 0x43, 0x73, 0x52, 0x34, - 0xdd, 0xb9, 0xcf, 0x78, 0xe7, 0x81, 0xa7, 0x3a, 0x51, 0xe3, 0x9e, 0xc4, - 0x38, 0xa3, 0x03, 0x2c, 0xe6, 0x45, 0x67, 0x70, 0xc7, 0xc5, 0x4c, 0x50, - 0xf7, 0x68, 0x52, 0x7f, 0x08, 0x94, 0x78, 0xd7, 0xb8, 0x8c, 0xb2, 0x56, - 0x45, 0x90, 0x65, 0xd3, 0x55, 0x1c, 0x20, 0x9c, 0x3c, 0x54, 0x96, 0xf3, - 0x45, 0x42, 0x9b, 0x1b, 0x20, 0xab, 0xc7, 0x1e, 0x73, 0x85, 0x6d, 0x03, - 0x0e, 0xc7, 0x17, 0xc5, 0xf6, 0x02, 0x10, 0x3b, 0x54, 0x2c, 0x17, 0x5c, - 0x08, 0xa2, 0xd6, 0x2e, 0xcc, 0x18, 0x9b, 0x71, 0x60, 0xba, 0xdb, 0xae, - 0x18, 0x54, 0x57, 0xd0, 0x30, 0xda, 0xe9, 0x15, 0x5f, 0x90, 0x43, 0x52, - 0xd9, 0xf5, 0xb6, 0x4e, 0x5b, 0x83, 0x83, 0xaa, 0xc0, 0x16, 0xe2, 0xa9, - 0x5f, 0x31, 0x30, 0x79, 0x87, 0x9d, 0x0c, 0xd8, 0xf2, 0xdb, 0x4e, 0x3e, - 0xe6, 0xd9, 0xc9, 0x17, 0xb7, 0x11, 0x8d, 0x9c, 0x72, 0x17, 0x45, 0xde, - 0x2b, 0x6a, 0xc7, 0x60, 0x79, 0x3f, 0xbe, 0xf8, 0xdd, 0x47, 0x07, 0x66, - 0x24, 0xe3, 0xa6, 0x00, 0x91, 0xa2, 0x6f, 0x6d, 0xbf, 0x76, 0x0c, 0x18, - 0xe0, 0x87, 0xe1, 0xb8, 0x0e, 0x75, 0x18, 0xa2, 0x46, 0x62, 0x9a, 0x20, - 0x85, 0x5e, 0x8b, 0xb4, 0xfe, 0xd2, 0x24, 0x4b, 0x6b, 0x2c, 0x53, 0x3e, - 0xba, 0xb3, 0x28, 0x6b, 0x29, 0x81, 0x6a, 0x74, 0xc8, 0xb6, 0x92, 0x13, - 0x77, 0x2b, 0xe7, 0xad, 0x1f, 0x20, 0x41, 0x0c, 0xdd, 0xb4, 0xa7, 0xa2, - 0xb8, 0x88, 0x2e, 0xb3, 0x12, 0xec, 0xfb, 0x36, 0x7a, 0xea, 0x77, 0xb3, - 0x22, 0xb4, 0x52, 0xd0, 0x97, 0x41, 0xae, 0xc1, 0xb2, 0x04, 0xd0, 0x7f, - 0x88, 0x23, 0x66, 0x50, 0x21, 0xee, 0xb5, 0x89, 0xcd, 0xeb, 0xe4, 0x46, - 0xed, 0x7b, 0x89, 0x4a, 0xb9, 0xc2, 0xa6, 0x33, 0x13, 0xdd, 0xc3, 0x96, - 0x16, 0xd5, 0xe0, 0x70, 0xfb, 0x13, 0xb8, 0xa3, 0x64, 0x86, 0x18, 0x2e, - 0xb6, 0x0f, 0x86, 0x2c, 0x1f, 0xda, 0x82, 0xb0, 0x79, 0x9c, 0x73, 0xa9, - 0x7e, 0x7b, 0xe9, 0x49, 0x84, 0x08, 0x53, 0x14, 0x31, 0x77, 0xdc, 0xa1, - 0x65, 0xd5, 0xaa, 0xb2, 0x99, 0xa6, 0x85, 0x30, 0x45, 0x95, 0x06, 0x31, - 0xc3, 0xd2, 0xb2, 0x5e, 0xcd, 0x8d, 0x4a, 0x24, 0x66, 0xfb, 0x97, 0x02, - 0xf0, 0xca, 0x1c, 0x5c, 0x79, 0x28, 0xa1, 0x97, 0x47, 0xac, 0xba, 0x85, - 0x05, 0x79, 0x1c, 0x06, 0x2c, 0xdf, 0x1f, 0xcf, 0xca, 0xd4, 0xa8, 0x31, - 0xa6, 0x76, 0x8d, 0x3d, 0x3e, 0xd6, 0xba, 0xf9, 0xe6, 0xb1, 0xae, 0x49, - 0xca, 0x4c, 0x5b, 0xb3, 0x58, 0xee, 0x44, 0xec, 0xa9, 0x82, 0x73, 0xa3, - 0xe3, 0x1e, 0xd0, 0xc0, 0x28, 0x15, 0x6a, 0x7a, 0x1f, 0x5b, 0xc1, 0xc6, - 0x14, 0x17, 0x15, 0x2f, 0x15, 0xd5, 0xcb, 0xb0, 0x4a, 0x58, 0x56, 0x5a, - 0xa5, 0xac, 0x82, 0x89, 0x22, 0x2d, 0xe0, 0x0c, 0x89, 0xab, 0x05, 0x82, - 0x29, 0x73, 0x03, 0xc9, 0xcc, 0x03, 0x8e, 0x4e, 0x81, 0x75, 0x16, 0x2e, - 0x7f, 0xe4, 0x41, 0x3f, 0x6b, 0x49, 0xfa, 0xb4, 0x15, 0xd0, 0x71, 0xea, - 0x53, 0xf0, 0xa3, 0x40, 0x0e, 0x63, 0x8e, 0x31, 0x30, 0x02, 0x6d, 0x35, - 0x47, 0x65, 0x84, 0x72, 0x12, 0xd3, 0x78, 0x6e, 0x35, 0xba, 0x32, 0x41, - 0x62, 0x26, 0x61, 0x33, 0x39, 0x89, 0xc2, 0xc3, 0x58, 0x09, 0x2a, 0x32, - 0x44, 0xaf, 0xd8, 0xe9, 0x16, 0x41, 0x08, 0xbf, 0x6f, 0x20, 0x0d, 0x9f, - 0xc8, 0xdd, 0x5a, 0xdf, 0xc7, 0xec, 0xcc, 0x81, 0x57, 0x12, 0xa1, 0x9a, - 0x5e, 0xe2, 0x68, 0x2d, 0xa9, 0x6b, 0xd8, 0x7f, 0x36, 0x5f, 0xe1, 0x43, - 0xca, 0xbc, 0x7e, 0x8c, 0x74, 0x11, 0xd4, 0xf4, 0x20, 0xa5, 0xf8, 0x28, - 0x3b, 0x7d, 0x24, 0xe6, 0x3c, 0x46, 0xd8, 0x46, 0x4d, 0xea, 0x84, 0x16, - 0x7b, 0xf7, 0xb9, 0x9b, 0x7f, 0xf6, 0x1d, 0x53, 0x6f, 0x32, 0x02, 0x74, - 0xd3, 0x12, 0x62, 0x92, 0x0c, 0x53, 0xa2, 0xbf, 0x16, 0x4e, 0xde, 0x1d, - 0xe5, 0xe4, 0x9f, 0x75, 0xe4, 0xac, 0xa0, 0x71, 0x54, 0x45, 0x37, 0xfc, - 0x3b, 0x1a, 0x40, 0x99, 0x1e, 0x4a, 0x66, 0xe3, 0x1e, 0x47, 0x18, 0xe1, - 0xa6, 0x66, 0x26, 0x90, 0x31, 0xc6, 0x89, 0xb1, 0x0e, 0x98, 0x3d, 0x1e, - 0xb8, 0x47, 0x8a, 0xb5, 0xd1, 0x4c, 0xee, 0x25, 0x2c, 0x1f, 0x29, 0x30, - 0xd6, 0x57, 0x9a, 0xb7, 0x66, 0x6c, 0x92, 0x13, 0xa8, 0x49, 0xdd, 0x59, - 0xc4, 0xc3, 0xe0, 0x44, 0x2e, 0xeb, 0x4e, 0x2e, 0x39, 0x4f, 0x37, 0x63, - 0xf9, 0xbe, 0x7d, 0x39, 0x53, 0x0b, 0x8b, 0x6b, 0x40, 0x6a, 0x6f, 0x21, - 0x3a, 0xea, 0x15, 0xc9, 0xc3, 0x19, 0x58, 0x50, 0x27, 0x5f, 0xd0, 0x33, - 0x55, 0x68, 0xad, 0xe3, 0xf2, 0x84, 0x97, 0x0b, 0x7f, 0x39, 0xeb, 0xad, - 0x25, 0x6b, 0xa4, 0xbe, 0x77, 0x5d, 0xcc, 0x25, 0xda, 0x50, 0xbf, 0xbb, - 0xfc, 0x03, 0xd1, 0x54, 0xfb, 0x21, 0x5c, 0x7f, 0x35, 0x7f, 0x4b, 0x76, - 0x2e, 0x46, 0x5c, 0x6d, 0xc0, 0x40, 0xbc, 0x08, 0x54, 0xab, 0x27, 0xfd, - 0xaf, 0x2c, 0xff, 0x4e, 0x14, 0xe2, 0xa9, 0xa4, 0xba, 0xa0, 0x34, 0x47, - 0xbd, 0x7a, 0x81, 0x7c, 0xd1, 0xe4, 0xe3, 0xa3, 0x20, 0x33, 0xa3, 0x64, - 0x9a, 0x78, 0x0c, 0xc2, 0x3a, 0x55, 0xdb, 0x98, 0x35, 0x2d, 0x39, 0x04, - 0x2d, 0xf3, 0x22, 0xdf, 0x2e, 0x9c, 0x7c, 0x57, 0x53, 0xf3, 0x9d, 0xd3, - 0x1e, 0xcf, 0xf9, 0x15, 0xd4, 0x5b, 0x1f, 0xac, 0x56, 0x47, 0xb7, 0x36, - 0x4e, 0x5c, 0x88, 0x0c, 0x01, 0xf5, 0x7c, 0xc7, 0xe0, 0x20, 0xea, 0xcc, - 0xe7, 0x6e, 0x41, 0xab, 0xcc, 0xa6, 0x2b, 0x8a, 0x99, 0xe5, 0x01, 0x47, - 0xf5, 0xb7, 0xbf, 0x98, 0x73, 0x89, 0x44, 0xa9, 0xa1, 0x75, 0x6f, 0xfb, - 0x0b, 0x64, 0x55, 0xca, 0xb4, 0x75, 0xbf, 0xc3, 0x55, 0xce, 0x87, 0x50, - 0xce, 0x0b, 0xf7, 0x7c, 0x24, 0x19, 0xe4, 0xe9, 0x97, 0x29, 0x86, 0x5f, - 0x8a, 0x16, 0x97, 0xf7, 0x87, 0x5a, 0x41, 0x7b, 0x38, 0x13, 0x70, 0x62, - 0x0f, 0xf0, 0xad, 0xe9, 0xd7, 0xf9, 0x7f, 0x62, 0xda, 0x77, 0x2a, 0x60, - 0x8d, 0xd2, 0x85, 0x5c, 0x6b, 0xc4, 0x43, 0xa7, 0x30, 0x27, 0x2d, 0x18, - 0x79, 0x52, 0x94, 0x76, 0xd8, 0xea, 0xb2, 0xb7, 0x2d, 0x86, 0xbb, 0xef, - 0xf7, 0x54, 0x17, 0x1b, 0xec, 0x1d, 0x9a, 0x7f, 0xa9, 0xb7, 0x35, 0x15, - 0xb1, 0xdf, 0x61, 0xd9, 0x76, 0x7c, 0x2d, 0x4a, 0x59, 0xf5, 0xf6, 0x5e, - 0xde, 0xfe, 0x3a, 0x27, 0x8d, 0x33, 0xa9, 0x72, 0xfc, 0x7e, 0xa9, 0xf5, - 0xdd, 0x72, 0xe9, 0x2c, 0x0d, 0xd3, 0x89, 0x89, 0x54, 0xc0, 0x9e, 0xd2, - 0x61, 0x68, 0xc5, 0x7b, 0xd1, 0x91, 0xd0, 0x55, 0xaa, 0x69, 0xb5, 0x19, - 0x0f, 0x83, 0x37, 0xbb, 0x72, 0x90, 0xb9, 0x7f, 0x47, 0xd8, 0xc4, 0xf0, - 0x29, 0x9d, 0x96, 0xe8, 0x32, 0x70, 0x64, 0x85, 0xc4, 0xa0, 0xfb, 0x53, - 0x9a, 0x45, 0xe6, 0x94, 0xcb, 0x6d, 0x09, 0x8a, 0xe2, 0x9d, 0xf7, 0x35, - 0xa7, 0x43, 0xbb, 0x46, 0x9d, 0x18, 0x37, 0x58, 0x14, 0x5b, 0xc5, 0x1c, - 0x35, 0x57, 0xf5, 0x30, 0x60, 0x8d, 0x3b, 0xba, 0xab, 0x90, 0x3f, 0x22, - 0xa1, 0x2a, 0xff, 0xae, 0xa4, 0xe4, 0x95, 0xa9, 0x43, 0x89, 0x12, 0x2d, - 0xf0, 0xe0, 0x70, 0x25, 0x1c, 0x90, 0xd7, 0x70, 0x1b, 0xbe, 0x82, 0xad, - 0x26, 0x59, 0x01, 0x05, 0x2c, 0x8e, 0xf4, 0x74, 0x50, 0xa0, 0x83, 0xbe, - 0x76, 0x05, 0x41, 0x55, 0xf8, 0x12, 0x3e, 0x0c, 0x11, 0xf6, 0x59, 0x9c, - 0x23, 0xc3, 0x13, 0x41, 0xee, 0xd3, 0x0d, 0xa6, 0x00, 0x5c, 0x11, 0x12, - 0x00, 0x00, 0x00, 0x1b, 0x99, 0x90, 0xef, 0x9c, 0x6b, 0x48, 0x2f, 0x5d, - 0xe2, 0x75, 0x64, 0x30, 0x6e, 0x94, 0x88, 0xcd, 0xc7, 0xb1, 0x7d, 0xd2, - 0xc6, 0xc6, 0x44, 0xab, 0x2d, 0xff, 0x54, 0x7b, 0x29, 0x79, 0x07, 0xd6, - 0xd2, 0x68, 0x7c, 0x74, 0xcd, 0x27, 0x28, 0x1c, 0x58, 0x5c, 0xd9, 0x4e, - 0xbd, 0xee, 0xc0, 0x02, 0xe7, 0x71, 0x41, 0xc9, 0x31, 0x14, 0x6b, 0x68, - 0x2f, 0xb9, 0xfb, 0xf5, 0x49, 0x17, 0x23, 0x35, 0x8d, 0x3e, 0x7b, 0x5a, - 0x21, 0x21, 0x3a, 0x71, 0x00, 0x14, 0xb1, 0x84, 0x71, 0x13, 0x3d, 0xf2, - 0xb3, 0xad, 0x9c, 0xff, 0xe9, 0xd3, 0x19, 0x7c, 0x67, 0x5c, 0x7c, 0x5d, - 0x0b, 0xb9, 0x4e, 0xfc, 0x2a, 0x9d, 0x19, 0x37, 0x80, 0xe6, 0xbe, 0xef, - 0x5d, 0xb6, 0xf9, 0x90, 0x5d, 0xdf, 0x25, 0x93, 0x98, 0x04, 0x0a, 0x46, - 0xce, 0xd8, 0xe3, 0x92, 0xd1, 0x8e, 0x90, 0xf6, 0xce, 0xe8, 0x6f, 0x58, - 0x8c, 0xe0, 0x4c, 0x44, 0x61, 0x8d, 0x84, 0xe8, 0xc7, 0xc9, 0xa6, 0x80, - 0xdf, 0x96, 0x8d, 0x22, 0x2d, 0x86, 0x38, 0x19, 0x0f, 0x36, 0x1c, 0xbb, - 0x5c, 0xa1, 0xa1, 0xb3, 0xb0, 0xc6, 0xbf, 0xf1, 0x41, 0x9b, 0x3f, 0xf6, - 0x5c, 0x1f, 0x96, 0xc5, 0xce, 0x8f, 0x8a, 0xd5, 0xcc, 0xc5, 0xc4, 0x14, - 0xce, 0xe0, 0xea, 0x87, 0x7a, 0x30, 0xac, 0x17, 0xf6, 0xc8, 0x4a, 0x17, - 0xb2, 0x2d, 0xf8, 0x46, 0xf9, 0x5c, 0xad, 0x02, 0xc7, 0x4a, 0x19, 0x33, - 0xe1, 0x7e, 0x39, 0x06, 0xe7, 0x88, 0x1a, 0x3b, 0xc7, 0x4b, 0xb7, 0x0f, - 0x05, 0x34, 0x06, 0xae, 0x6d, 0x92, 0x5b, 0xea, 0x22, 0x17, 0x6c, 0xad, - 0x65, 0x86, 0x68, 0xba, 0x4e, 0x38, 0xf5, 0x3a, 0xeb, 0xe4, 0x81, 0x2a, - 0xff, 0x22, 0x33, 0x73, 0x85, 0xeb, 0x11, 0x78, 0x98, 0xcb, 0x4d, 0xc9, - 0xbf, 0x4f, 0x24, 0x8e, 0x6b, 0xf7, 0x44, 0x7b, 0xbf, 0xf2, 0xa9, 0x4e, - 0x08, 0xcd, 0xfc, 0xb7, 0xfc, 0xd9, 0xb8, 0x19, 0xf5, 0x80, 0xd1, 0xce, - 0x45, 0x06, 0x9b, 0xc8, 0x4c, 0xd8, 0xd1, 0x19, 0xd7, 0x9b, 0xc8, 0x67, - 0x11, 0x04, 0x86, 0x69, 0xae, 0x5d, 0xd5, 0xa2, 0xb3, 0xe5, 0x64, 0x50, - 0x2b, 0x9c, 0x18, 0xf5, 0xef, 0x65, 0x90, 0xdc, 0xb9, 0x7a, 0x67, 0x1d, - 0x62, 0xf3, 0x17, 0xbf, 0x1d, 0x67, 0xaf, 0xb3, 0x0c, 0xe4, 0xda, 0x27, - 0x06, 0xa3, 0x34, 0xe6, 0x8f, 0x43, 0xd1, 0x20, 0x17, 0x44, 0x44, 0x10, - 0x93, 0x91, 0x61, 0x43, 0xb7, 0x75, 0x9f, 0x1e, 0x91, 0x0b, 0xa0, 0x5e, - 0x49, 0x02, 0xba, 0x5d, 0xbc, 0xde, 0x6c, 0xb5, 0xbb, 0x26, 0x87, 0x68, - 0x03, 0x94, 0xe1, 0x05, 0xd1, 0xfc, 0xba, 0x48, 0xc7, 0x87, 0x86, 0xef, - 0xe9, 0x54, 0x0a, 0xaf, 0xd1, 0x7b, 0x0a, 0xd4, 0xf5, 0x07, 0xe6, 0x1f, - 0x60, 0xec, 0x82, 0x2c, 0xc5, 0x93, 0xc3, 0x60, 0xee, 0x78, 0x85, 0x28, - 0xa5, 0x08, 0x9f, 0x36, 0x47, 0x9c, 0xb2, 0x8e, 0x0a, 0x90, 0xf2, 0xa2, - 0xd0, 0x13, 0x3e, 0xfa, 0x40, 0x46, 0x6e, 0x97, 0x92, 0xea, 0x56, 0x60, - 0xe3, 0x95, 0xa1, 0x35, 0x3c, 0x26, 0xe2, 0x4d, 0x35, 0x92, 0x5e, 0xe4, - 0xbd, 0x4c, 0xea, 0x8e, 0xbf, 0x81, 0xd6, 0xe8, 0xa2, 0x37, 0x70, 0x3b, - 0x3c, 0xc4, 0x8d, 0x05, 0x16, 0x9a, 0x3a, 0x34, 0x47, 0x99, 0xd7, 0x49, - 0xc7, 0x9a, 0x34, 0x1c, 0x7f, 0xbf, 0xce, 0x56, 0x7e, 0x64, 0xaa, 0xba, - 0xc6, 0xfc, 0xe7, 0x3e, 0x62, 0x7f, 0xa6, 0x38, 0xdd, 0x3a, 0x95, 0x80, - 0xd4, 0xf8, 0x49, 0x58, 0xe7, 0x02, 0x4e, 0xa0, 0x08, 0x74, 0x71, 0x19, - 0x79, 0x75, 0x41, 0x95, 0x88, 0xc8, 0xe1, 0xe4, 0x9d, 0x19, 0x7c, 0x06, - 0x03, 0x0d, 0x27, 0x36, 0x5d, 0x2b, 0xbc, 0xa6, 0xb6, 0x22, 0x94, 0x12, - 0x17, 0xa2, 0xa2, 0x1e, 0x07, 0x60, 0x0e, 0x8d, 0x53, 0x60, 0x41, 0x7b, - 0x92, 0xfb, 0x13, 0x74, 0x1c, 0x6c, 0x1a, 0xd3, 0x7d, 0xda, 0xe1, 0x1c, - 0x16, 0xb9, 0xf9, 0xd2, 0x39, 0x36, 0xc0, 0xbb, 0x49, 0x00, 0xd4, 0x8d, - 0x7a, 0x59, 0x41, 0x9c, 0x2f, 0x09, 0x3b, 0x63, 0x1c, 0x82, 0x15, 0xe3, - 0x36, 0x62, 0x37, 0x07, 0x3b, 0x6e, 0x7c, 0x8d, 0x6c, 0x7b, 0x2b, 0xa0, - 0xa8, 0xd2, 0xe1, 0x24, 0x58, 0x3d, 0xb2, 0xf2, 0x3f, 0xf8, 0x86, 0x44, - 0x09, 0xe7, 0xab, 0x5f, 0x34, 0xa8, 0x37, 0xda, 0x2d, 0xd8, 0xae, 0x01, - 0x88, 0x0d, 0x43, 0x38, 0x35, 0x7d, 0xb5, 0xe7, 0x6e, 0x79, 0x0d, 0xe9, - 0xe9, 0x25, 0xf8, 0xdb, 0xfd, 0x3b, 0xd9, 0x73, 0x77, 0x55, 0x45, 0xc3, - 0x22, 0xf5, 0x43, 0x22, 0x4f, 0x47, 0xbf, 0x78, 0xfb, 0x34, 0xd1, 0xee, - 0xd0, 0xcc, 0x3a, 0xa5, 0xa4, 0xe5, 0x78, 0xe9, 0xd6, 0x55, 0xe0, 0x15, - 0x86, 0x4b, 0x58, 0x9d, 0x62, 0x2f, 0x29, 0x62, 0xd8, 0xdf, 0x96, 0x80, - 0x05, 0x1a, 0x9d, 0xc1, 0x0d, 0xb9, 0xd1, 0x44, 0x29, 0x6f, 0xe0, 0x86, - 0x25, 0xde, 0x7f, 0x78, 0x6f, 0xe0, 0x9c, 0xdf, 0x14, 0xdd, 0x89, 0x3e, - 0x44, 0xf4, 0xe0, 0x4c, 0x20, 0x58, 0xbb, 0x55, 0xf5, 0x4e, 0x96, 0xaa, - 0x82, 0x74, 0x2d, 0xbd, 0xc2, 0xad, 0x7f, 0xc3, 0xed, 0x8b, 0xd5, 0x98, - 0xf7, 0xad, 0x5a, 0xc4, 0x90, 0x14, 0xb2, 0xa8, 0xf4, 0x81, 0xc4, 0xaf, - 0x6c, 0x05, 0xfe, 0xee, 0x04, 0x3c, 0x51, 0xbd, 0x75, 0xd7, 0x32, 0xf5, - 0x7e, 0x45, 0x19, 0x39, 0x19, 0x28, 0x45, 0x9a, 0xc7, 0xcf, 0x82, 0x7d, - 0x56, 0xac, 0x68, 0xdb, 0xde, 0x89, 0x9d, 0x72, 0x1a, 0x46, 0xea, 0xb0, - 0xc3, 0xbc, 0x6f, 0x0d, 0x4b, 0x41, 0x3b, 0x38, 0xb3, 0xc7, 0xcb, 0x04, - 0xbe, 0xf3, 0x4c, 0x3b, 0x74, 0xa9, 0x2a, 0xe4, 0xe3, 0x2f, 0xc7, 0x8c, - 0x90, 0x30, 0x67, 0xcb, 0xb1, 0x1f, 0xbf, 0xc0, 0xad, 0x37, 0x74, 0x80, - 0xa9, 0x04, 0x7c, 0xc8, 0x57, 0x33, 0x83, 0x5b, 0x8c, 0xe6, 0xfc, 0xd5, - 0xa4, 0xf3, 0x9b, 0x6b, 0x2d, 0xdc, 0x64, 0x2b, 0x83, 0xe7, 0xdc, 0xb4, - 0x48, 0x8d, 0x11, 0x65, 0x22, 0xb5, 0xb5, 0x54, 0xec, 0x26, 0xdc, 0x1f, - 0x96, 0xbc, 0x68, 0x87, 0x67, 0xed, 0x1c, 0x41, 0xd3, 0xd8, 0x4f, 0xe2, - 0xc8, 0x43, 0xbb, 0x22, 0xd9, 0xa1, 0x39, 0xe1, 0x72, 0xdb, 0x75, 0x81, - 0x58, 0x74, 0x89, 0xb9, 0x58, 0x8b, 0x0f, 0x8a, 0xa0, 0x6a, 0x9e, 0x70, - 0x6b, 0x3b, 0x01, 0x2f, 0x2b, 0xf4, 0x00, 0xb8, 0x1c, 0xf9, 0x34, 0xa4, - 0x30, 0x80, 0x80, 0x4a, 0x0e, 0xcc, 0x52, 0x4e, 0xc7, 0xc1, 0x01, 0xfd, - 0x73, 0x22, 0x26, 0x33, 0x68, 0xfe, 0x01, 0x1d, 0xe1, 0xf0, 0x04, 0x66, - 0xfd, 0xcc, 0x77, 0xe5, 0xa1, 0x4b, 0xbe, 0x0e, 0xde, 0x95, 0x74, 0x72, - 0xbf, 0xbb, 0xa2, 0x5c, 0x08, 0x5d, 0x13, 0xcb, 0xcb, 0xd7, 0xa6, 0x34, - 0x61, 0x53, 0x0b, 0x3e, 0xb1, 0xe0, 0xb5, 0xd3, 0xaf, 0xe9, 0x07, 0x67, - 0x4c, 0x1a, 0x5b, 0x64, 0x68, 0xac, 0x94, 0x6f, 0xc4, 0xdb, 0x0f, 0x84, - 0x52, 0x88, 0x4b, 0x1e, 0xe5, 0xf1, 0x05, 0x70, 0x94, 0xee, 0xc1, 0x62, - 0xfd, 0x6f, 0x41, 0x2a, 0x1f, 0xda, 0xbe, 0x9f, 0xfb, 0x87, 0xf0, 0x96, - 0x8d, 0xa0, 0x60, 0x74, 0x7d, 0x53, 0x6e, 0x2e, 0x2d, 0x42, 0x49, 0x3d, - 0x9a, 0xae, 0xbc, 0x1b, 0x76, 0xa0, 0xc7, 0xaf, 0x4b, 0xb9, 0x18, 0x6f, - 0x4b, 0xe8, 0xbc, 0x56, 0x7b, 0x57, 0x60, 0xd1, 0xd3, 0x0c, 0x4d, 0xe0, - 0xe2, 0x3d, 0xcc, 0x82, 0x36, 0x78, 0xa2, 0x53, 0xe8, 0xe8, 0xf6, 0x13, - 0xa6, 0xc1, 0x1f, 0x0c, 0x9f, 0x5b, 0x0c, 0xf9, 0x89, 0x8e, 0xae, 0x70, - 0x51, 0xd0, 0x1f, 0x7b, 0xab, 0x69, 0xda, 0xb9, 0x56, 0x4d, 0x2d, 0x93, - 0x18, 0xa4, 0x40, 0x55, 0x95, 0xdf, 0x58, 0xca, 0xbd, 0x36, 0x89, 0x07, - 0x58, 0x11, 0xa6, 0x22, 0xf8, 0x83, 0x1c, 0x8e, 0xe7, 0xa9, 0xc7, 0xd3, - 0xdc, 0x5e, 0x54, 0x35, 0xd6, 0xf1, 0xe4, 0x41, 0x98, 0xa4, 0x16, 0x67, - 0x73, 0x56, 0xdd, 0x69, 0x6d, 0xaa, 0x3f, 0xb8, 0xad, 0xfa, 0xd7, 0xce, - 0xee, 0x65, 0xc5, 0x10, 0xe8, 0x39, 0x1d, 0xff, 0x57, 0x1a, 0x85, 0x43, - 0x77, 0x3f, 0xb1, 0xe1, 0x21, 0x81, 0xa6, 0x8e, 0xd8, 0x49, 0xec, 0xe8, - 0x44, 0x0c, 0x4c, 0x44, 0x8f, 0x8d, 0x78, 0x45, 0xcc, 0x81, 0xed, 0x17, - 0xd1, 0xac, 0x54, 0x3c, 0x58, 0xa4, 0x8e, 0x65, 0xd0, 0xd8, 0x94, 0xc9, - 0xd7, 0x8d, 0x46, 0x5d, 0xc1, 0x3c, 0xb6, 0xb9, 0x0d, 0x88, 0xdf, 0x2c, - 0xb8, 0x51, 0x6d, 0x30, 0x87, 0x76, 0x27, 0x0a, 0xd7, 0xfe, 0x0a, 0x2b, - 0x2d, 0xdc, 0xd1, 0xd2, 0xfd, 0x72, 0xcd, 0x0f, 0x1b, 0xb7, 0xb6, 0x0d, - 0xbd, 0xe0, 0x10, 0x60, 0xec, 0xfd, 0xe1, 0x18, 0x0d, 0x88, 0x48, 0x34, - 0xec, 0xf6, 0x7f, 0x4a, 0x24, 0xce, 0xa9, 0x8d, 0x45, 0x4e, 0xde, 0xcc, - 0x5e, 0xfc, 0x48, 0xf8, 0x7e, 0xa8, 0x0a, 0x9c, 0x5b, 0xad, 0x3c, 0x5e, - 0x5d, 0x3e, 0x33, 0x89, 0xec, 0x88, 0x58, 0xa9, 0xca, 0xa6, 0xe7, 0x59, - 0x5a, 0x8e, 0xfb, 0x21, 0x43, 0x8a, 0x45, 0x49, 0x0f, 0x91, 0xb8, 0xf8, - 0x60, 0x5b, 0x35, 0x44, 0xd7, 0x0d, 0x68, 0x9f, 0x47, 0x6f, 0xbf, 0x3d, - 0xa1, 0x6f, 0xd7, 0xfc, 0xef, 0xbd, 0x9b, 0x84, 0xce, 0x79, 0xbd, 0xf9, - 0x59, 0x4d, 0x46, 0x6e, 0xde, 0x49, 0xdd, 0xde, 0xb8, 0x27, 0x33, 0xf9, - 0xdb, 0x33, 0xdb, 0xea, 0x42, 0x30, 0xff, 0x96, 0x72, 0x5b, 0x55, 0xb6, - 0xa3, 0xa9, 0x15, 0xb3, 0xbd, 0x31, 0xb6, 0x7c, 0x4e, 0xc8, 0xec, 0x5a, - 0x2a, 0x53, 0xe9, 0xa8, 0x25, 0x26, 0x75, 0xeb, 0xce, 0xd5, 0x27, 0x6e, - 0x85, 0xe2, 0x01, 0x0b, 0xd6, 0x1b, 0x09, 0xe8, 0x0a, 0x11, 0xf3, 0x2d, - 0x94, 0xcf, 0xab, 0x03, 0xb9, 0x83, 0x8a, 0x6f, 0x3b, 0x05, 0x98, 0xb4, - 0x72, 0x3b, 0xba, 0x90, 0xbd, 0x23, 0x07, 0x8b, 0xf8, 0xd9, 0x26, 0x13, - 0x74, 0xe3, 0x1c, 0x85, 0xec, 0x8f, 0x43, 0x29, 0xa8, 0x17, 0x6d, 0xb7, - 0x00, 0xda, 0xd1, 0x34, 0x1d, 0x1c, 0xd2, 0xc3, 0xe6, 0xd7, 0x11, 0x51, - 0x79, 0x1b, 0x73, 0x00, 0x51, 0xd0, 0xe7, 0x92, 0xe1, 0x11, 0x5d, 0x9b, - 0x5c, 0x11, 0x88, 0x4c, 0xfa, 0x02, 0x82, 0x78, 0x86, 0xed, 0x65, 0x08, - 0x4f, 0x1c, 0xcb, 0x8c, 0x78, 0x59, 0x65, 0xea, 0x97, 0x8c, 0xe6, 0x52, - 0xe1, 0x3f, 0xdd, 0xbb, 0x20, 0xe6, 0x7c, 0xf9, 0xc7, 0xf8, 0xb9, 0xe6, - 0x74, 0xa0, 0xa5, 0xcb, 0xe9, 0x89, 0xb9, 0xff, 0x88, 0xa3, 0xb8, 0x7b, - 0x60, 0x8d, 0xb0, 0xca, 0x50, 0xe8, 0xc0, 0x80, 0xc1, 0x68, 0x27, 0xef, - 0x48, 0xe7, 0x00, 0x22, 0x52, 0xb4, 0x2e, 0x30, 0x97, 0x96, 0xde, 0xb3, - 0xd0, 0xa1, 0x8b, 0x6a, 0x31, 0x6a, 0xc4, 0x52, 0xef, 0xba, 0x74, 0x57, - 0xf1, 0xc6, 0x19, 0x37, 0x0b, 0x22, 0xa0, 0x23, 0xb9, 0xe0, 0x26, 0x0c, - 0x23, 0xa3, 0xb8, 0x4c, 0x71, 0x7b, 0x45, 0xa4, 0xe8, 0xfd, 0x94, 0xfc, - 0x96, 0x47, 0xba, 0x0f, 0xaa, 0x67, 0x90, 0xa3, 0x2d, 0x95, 0x70, 0xd2, - 0xa3, 0xfa, 0x7b, 0x49, 0x03, 0x45, 0x44, 0x45, 0x8a, 0x38, 0x2a, 0x04, - 0x1b, 0x9a, 0xa3, 0xbd, 0xc6, 0xa9, 0xcf, 0x4f, 0x88, 0x41, 0x98, 0x0c, - 0x2a, 0x5e, 0x22, 0x60, 0x01, 0xf3, 0x78, 0x98, 0xf4, 0x13, 0xc9, 0x27, - 0x80, 0x6e, 0xee, 0x4f, 0xa0, 0xf2, 0xbe, 0x8f, 0x83, 0x69, 0x52, 0xc4, - 0xf8, 0x82, 0x36, 0xd6, 0xe4, 0x91, 0xd9, 0x62, 0xa4, 0x09, 0xa1, 0xbd, - 0xff, 0xec, 0x96, 0x74, 0x0d, 0x6f, 0x17, 0xf9, 0xb7, 0xe3, 0xe4, 0x16, - 0x7f, 0x03, 0xd7, 0x27, 0x7f, 0xaa, 0x94, 0x27, 0x61, 0x3a, 0x3c, 0x0a, - 0x92, 0x82, 0x93, 0x6a, 0xed, 0x55, 0x12, 0xac, 0xe4, 0x89, 0xc2, 0x25, - 0x36, 0x50, 0x63, 0x68, 0x49, 0xb7, 0x5f, 0x44, 0x95, 0xe8, 0x41, 0x09, - 0x6f, 0xdf, 0x66, 0x0c, 0xde, 0x6f, 0xba, 0x7a, 0x0f, 0x9e, 0x87, 0x43, - 0x62, 0x99, 0x9b, 0x97, 0xe7, 0xb1, 0x46, 0x2d, 0xa2, 0x10, 0x57, 0x92, - 0x5a, 0xbe, 0xec, 0xc1, 0x24, 0x91, 0x94, 0x80, 0x1c, 0xea, 0x0f, 0xc7, - 0xfe, 0x02, 0x4d, 0x99, 0x88, 0x1b, 0xc1, 0xaa, 0xce, 0x4d, 0x6a, 0xc7, - 0xe0, 0x93, 0x4b, 0x35, 0x71, 0x49, 0x81, 0x6b, 0x98, 0x54, 0x17, 0x6d, - 0xf5, 0xbc, 0xc2, 0xc3, 0xb8, 0x5b, 0x00, 0xfd, 0xec, 0x50, 0x50, 0x6e, - 0xb6, 0xe7, 0xdc, 0x6c, 0x2b, 0x4b, 0x77, 0x73, 0xeb, 0xee, 0xc1, 0xc3, - 0xe1, 0xee, 0xc1, 0xc6, 0xc9, 0xce, 0xad, 0x6b, 0x8f, 0x40, 0x95, 0xb3, - 0x41, 0xb9, 0x86, 0xf8, 0x6a, 0x9a, 0x59, 0x7e, 0xc8, 0xb3, 0x26, 0xa0, - 0x55, 0x6e, 0x41, 0x90, 0xff, 0xf2, 0x69, 0x01, 0x70, 0x61, 0x81, 0x6a, - 0x61, 0x14, 0x78, 0x8c, 0x31, 0xbc, 0xc4, 0x51, 0x81, 0x4e, 0x12, 0x54, - 0xef, 0xd8, 0x85, 0x07, 0x92, 0xa4, 0x02, 0xae, 0x54, 0x80, 0x70, 0x94, - 0x26, 0x49, 0x8a, 0xa2, 0x3e, 0x63, 0x6f, 0x3a, 0xa5, 0xbe, 0x71, 0x02, - 0x22, 0x99, 0xf0, 0x98, 0xe8, 0x8f, 0xc5, 0x58, 0x1e, 0xcd, 0x2b, 0xe8, - 0xf5, 0xa0, 0x2c, 0xd0, 0x21, 0x87, 0x3a, 0x38, 0x28, 0x0d, 0x87, 0x1f, - 0x0f, 0x3e, 0xfb, 0xd6, 0xd3, 0x12, 0x86, 0x66, 0x25, 0x02, 0x6c, 0x08, - 0x54, 0x10, 0xfb, 0x29, 0x8f, 0x7f, 0xe5, 0x96, 0xa8, 0x56, 0xba, 0x72, - 0x71, 0x36, 0xdd, 0xc6, 0x81, 0xe2, 0x1f, 0x7a, 0xd4, 0x8d, 0xdc, 0xea, - 0xe6, 0xff, 0x2f, 0xb5, 0xea, 0x44, 0xea, 0x88, 0x69, 0x80, 0x2e, 0x49, - 0x4d, 0x84, 0x6f, 0xa1, 0x7a, 0xed, 0x05, 0x55, 0x73, 0x42, 0x56, 0xe4, - 0xa6, 0x9f, 0x65, 0x32, 0x46, 0x32, 0xb3, 0x97, 0x87, 0x74, 0x7a, 0xd3, - 0xdd, 0xcf, 0x9f, 0x01, 0x96, 0x37, 0xf2, 0xd1, 0xeb, 0x45, 0x4a, 0x23, - 0xb5, 0x33, 0x6c, 0xa5, 0x7b, 0x98, 0x65, 0xd2, 0xe1, 0x78, 0xf9, 0x44, - 0x03, 0x3b, 0x29, 0xa8, 0xf2, 0x45, 0xb2, 0x96, 0x3e, 0xac, 0x09, 0x24, - 0x76, 0x48, 0xb9, 0x75, 0x87, 0xba, 0x2c, 0x4e, 0x33, 0x67, 0xdf, 0xdc, - 0x70, 0x3b, 0xc3, 0x1f, 0xbb, 0xd9, 0x36, 0xf8, 0x19, 0x2e, 0xeb, 0x42, - 0xe5, 0x6b, 0xaa, 0x85, 0x3f, 0xeb, 0xac, 0x51, 0x78, 0xdb, 0x62, 0x9e, - 0x2a, 0x5f, 0x1e, 0xb2, 0x72, 0xa7, 0xdd, 0x25, 0xb0, 0x6b, 0xcb, 0xc5, - 0xb5, 0xe3, 0x88, 0x1c, 0xcd, 0xfa, 0xa8, 0x6e, 0x2a, 0x0e, 0xa0, 0x79, - 0x7a, 0x04, 0x1f, 0xed, 0x3d, 0xc2, 0x65, 0xaf, 0x0b, 0xaa, 0xb2, 0xec, - 0x73, 0x6e, 0x0f, 0xd4, 0x21, 0xd8, 0x29, 0x39, 0x10, 0x53, 0x2c, 0xf8, - 0x31, 0xaf, 0x5f, 0x4b, 0x81, 0xff, 0xb2, 0x6f, 0x96, 0x41, 0xcf, 0x25, - 0x0f, 0x03, 0x13, 0x05, 0x72, 0x7f, 0x75, 0x5c, 0x31, 0x09, 0x72, 0x90, - 0x65, 0x01, 0x43, 0x4b, 0xef, 0x55, 0x91, 0xd3, 0x75, 0x85, 0x44, 0x78, - 0xe9, 0x4c, 0xb0, 0x9b, 0x68, 0xdd, 0xf2, 0x2d, 0x4a, 0x96, 0x21, 0xb6, - 0x2c, 0x2f, 0x86, 0x76, 0x6f, 0xc5, 0x1f, 0x30, 0x6c, 0xc4, 0xf8, 0x12, - 0x8d, 0x0a, 0x1d, 0x76, 0xe7, 0x79, 0xac, 0x85, 0xd4, 0x2f, 0xfc, 0x2c, - 0x9b, 0x54, 0x2b, 0xdc, 0xf7, 0xad, 0x4a, 0x64, 0x03, 0x40, 0xb4, 0xaa, - 0x21, 0x5f, 0x47, 0x55, 0xf2, 0xfd, 0x9d, 0xe2, 0x14, 0x2e, 0x68, 0x84, - 0xef, 0x98, 0x8e, 0xcd, 0xe3, 0x04, 0x52, 0xd1, 0xc2, 0x6c, 0x3b, 0xc3, - 0x2c, 0x49, 0xc4, 0x53, 0x6c, 0xcb, 0x7e, 0xb5, 0x8a, 0xce, 0x18, 0x02, - 0x34, 0x3c, 0xcb, 0xa4, 0xd6, 0xd8, 0xc9, 0xea, 0xa0, 0x19, 0x08, 0x52, - 0x3a, 0x76, 0x49, 0xc5, 0x6c, 0xb3, 0xbf, 0x23, 0x4d, 0x17, 0x18, 0xa4, - 0x27, 0xea, 0x2c, 0x89, 0xc0, 0x77, 0xe5, 0x5c, 0xab, 0x78, 0xdc, 0x17, - 0x29, 0x7a, 0xde, 0x43, 0x4b, 0x40, 0x06, 0x5d, 0x57, 0xa4, 0xf4, 0xe9, - 0xf0, 0xc3, 0xfe, 0x75, 0x71, 0xb3, 0x57, 0x5d, 0x02, 0x84, 0x1e, 0x35, - 0x9c, 0x2b, 0x97, 0x4b, 0x73, 0x8b, 0xaf, 0x7c, 0x1f, 0xae, 0x2b, 0xb2, - 0x85, 0x3b, 0x00, 0xe6, 0xa6, 0x3f, 0x93, 0x8a, 0xfb, 0x47, 0x71, 0x47, - 0xcb, 0xfd, 0x34, 0xd9, 0xf0, 0xbd, 0x7d, 0x85, 0x02, 0x9b, 0x90, 0x88, - 0x7f, 0x6e, 0x97, 0xce, 0x1a, 0x9f, 0x61, 0x19, 0x59, 0x81, 0x05, 0xfb, - 0xb8, 0xbc, 0x3c, 0x19, 0x1c, 0x1a, 0x5b, 0x60, 0xe0, 0x24, 0xcc, 0x52, - 0xb7, 0x49, 0x9e, 0xb6, 0x08, 0xd5, 0x0e, 0x69, 0xfe, 0xc0, 0x92, 0x74, - 0x73, 0x72, 0x93, 0x32, 0xe7, 0xe6, 0xe9, 0x8f, 0xb2, 0xb4, 0x86, 0x47, - 0x67, 0x67, 0xff, 0xc5, 0x2f, 0x25, 0x54, 0x36, 0x50, 0xeb, 0xf4, 0x34, - 0x91, 0x83, 0xde, 0x05, 0xd7, 0xc6, 0xc8, 0xce, 0xf8, 0xe0, 0xbb, 0xc7, - 0x27, 0x24, 0x65, 0x60, 0x21, 0x47, 0x0d, 0x4e, 0x2c, 0x03, 0xad, 0x14, - 0x0b, 0xe3, 0x0f, 0xe3, 0x50, 0xef, 0x06, 0x63, 0x22, 0xb0, 0x51, 0xff, - 0x72, 0x6d, 0x03, 0xaf, 0x76, 0xf6, 0x0f, 0x06, 0xa1, 0x84, 0x53, 0xa2, - 0x79, 0xe1, 0x68, 0x1c, 0xe7, 0x57, 0x09, 0xf3, 0xff, 0x64, 0x6a, 0x33, - 0x81, 0x8a, 0x84, 0x80, 0xd0, 0x85, 0x84, 0x99, 0x75, 0xc6, 0x2e, 0xae, - 0xe0, 0x6d, 0x49, 0xaa, 0xbd, 0x0e, 0x8d, 0xb9, 0x88, 0xb7, 0x52, 0x55, - 0x00, 0xaf, 0xcb, 0x68, 0xb4, 0x53, 0x25, 0x8d, 0x58, 0xc3, 0xcf, 0x94, - 0x1f, 0x80, 0x8a, 0xda, 0x1f, 0x70, 0xe2, 0x19, 0x6d, 0xdd, 0x1d, 0xac, - 0xab, 0xf8, 0xef, 0x0f, 0x43, 0xe0, 0x91, 0xd7, 0x7c, 0xed, 0xb4, 0x8f, - 0x2f, 0x2a, 0xa6, 0x36, 0x18, 0x86, 0xd7, 0xcc, 0xd1, 0xde, 0xda, 0x0d, - 0x0c, 0xde, 0xae, 0x9f, 0xbc, 0x49, 0xf7, 0x07, 0x82, 0xbe, 0x6e, 0xd0, - 0x2b, 0xb1, 0xd4, 0xfa, 0x1a, 0xfe, 0xcc, 0x57, 0x97, 0x2f, 0x4d, 0x12, - 0xf0, 0xba, 0xa0, 0x3f, 0x7f, 0xb4, 0xfe, 0xb8, 0x0f, 0xb3, 0xc5, 0x03, - 0xdc, 0x77, 0x98, 0x95, 0xc6, 0x0b, 0x7b, 0x6f, 0xad, 0xae, 0x9d, 0xb4, - 0xf0, 0x0d, 0xa2, 0xa1, 0xa8, 0x83, 0x62, 0xc7, 0x31, 0x27, 0x9c, 0x52, - 0x36, 0x06, 0x13, 0x52, 0x0e, 0xd6, 0x30, 0x41, 0xc4, 0x38, 0x29, 0x1d, - 0x39, 0x7c, 0x23, 0x32, 0x45, 0xcc, 0x79, 0xca, 0xa5, 0x9a, 0x62, 0x6e, - 0x00, 0x02, 0xc9, 0xb9, 0xd3, 0x84, 0x02, 0x5d, 0xe3, 0x69, 0x5c, 0x8e, - 0xbe, 0x55, 0xf4, 0x96, 0xdf, 0xcb, 0x8b, 0x52, 0xa1, 0x4e, 0x9c, 0x38, - 0x56, 0xa1, 0xd7, 0x82, 0x4a, 0x6a, 0xd3, 0x19, 0xa6, 0x74, 0x80, 0x04, - 0x6d, 0xc5, 0x7e, 0xd6, 0xda, 0x91, 0x5e, 0x2c, 0x81, 0x3b, 0x0c, 0x6a, - 0xc6, 0xe8, 0x40, 0xb7, 0x9c, 0x2a, 0x4f, 0xb3, 0x87, 0x46, 0xc5, 0x4b, - 0x81, 0x87, 0xbe, 0x93, 0x5a, 0x9c, 0xc8, 0xdc, 0x97, 0x93, 0xff, 0x06, - 0x36, 0x8e, 0xa6, 0x24, 0x03, 0x10, 0x17, 0xf9, 0x20, 0xed, 0x75, 0xef, - 0xed, 0xcf, 0x28, 0x1b, 0x7b, 0x64, 0x00, 0x7c, 0x78, 0x10, 0x84, 0xa2, - 0x96, 0x4b, 0x04, 0x42, 0x57, 0x76, 0xaa, 0x2b, 0x7d, 0x7c, 0xc4, 0x85, - 0x83, 0xef, 0x04, 0xdd, 0x6a, 0x68, 0x5e, 0xe3, 0xba, 0xb4, 0x08, 0xe0, - 0x8a, 0xdc, 0x32, 0x53, 0x1a, 0x4b, 0x06, 0x06, 0x8c, 0x12, 0xb9, 0xf7, - 0xd2, 0xf6, 0x5d, 0x12, 0x7b, 0x1b, 0xb9, 0xcf, 0x0d, 0x8c, 0xfe, 0xb2, - 0x4b, 0xfb, 0xaf, 0x0c, 0xf6, 0x1a, 0x89, 0xe1, 0xdb, 0xa0, 0x92, 0x3b, - 0xb0, 0x15, 0xaf, 0x76, 0xe5, 0x22, 0x5f, 0x93, 0x0f, 0x08, 0x33, 0xa6, - 0xe0, 0x52, 0x00, 0x49, 0x7d, 0xf2, 0xd0, 0xdd, 0xe0, 0xb5, 0xbb, 0x07, - 0x78, 0x2f, 0xd3, 0x17, 0xe0, 0xce, 0xd1, 0x60, 0xef, 0x26, 0x27, 0x68, - 0x81, 0x7e, 0x23, 0xa2, 0xcf, 0x93, 0x12, 0xc6, 0x44, 0x1b, 0xaf, 0x47, - 0x8b, 0x26, 0x47, 0xba, 0x95, 0x7c, 0x2f, 0xc0, 0xff, 0xc6, 0xdc, 0xe8, - 0x1f, 0x2c, 0x35, 0xa1, 0x4b, 0xdc, 0x16, 0x1a, 0xbf, 0x78, 0x05, 0xbc, - 0xb2, 0x1d, 0x69, 0x75, 0x74, 0x6e, 0x32, 0x05, 0x4e, 0x20, 0x6e, 0x1f, - 0xaf, 0x11, 0xf2, 0x37, 0x41, 0x0a, 0x7b, 0xfd, 0x28, 0x9f, 0xa4, 0x47, - 0xfc, 0x25, 0xf5, 0x1c, 0xd5, 0x62, 0xde, 0x84, 0xcb, 0xf9, 0x52, 0xe2, - 0xdd, 0x26, 0x3f, 0x8e, 0x8c, 0xd4, 0xba, 0x54, 0x34, 0xbf, 0x9b, 0xff, - 0x9e, 0x05, 0x2f, 0x9c, 0x98, 0xce, 0xa6, 0x4e, 0x36, 0xde, 0x96, 0x81, - 0x30, 0x05, 0x75, 0x07, 0xdd, 0xa0, 0x74, 0x4f, 0x39, 0x60, 0xcb, 0x5e, - 0x26, 0x2e, 0xbb, 0x00, 0xaf, 0xf7, 0x3b, 0xd9, 0xb1, 0x70, 0x4f, 0xa4, - 0x31, 0x45, 0x06, 0x63, 0x61, 0x03, 0x45, 0x27, 0xe3, 0x66, 0xf7, 0x9f, - 0x15, 0x5b, 0x22, 0x45, 0xb7, 0x6d, 0xe8, 0xb2, 0x67, 0x35, 0x8e, 0x72, - 0x02, 0x76, 0xf4, 0xb4, 0x63, 0x4a, 0x7c, 0xd7, 0xd1, 0x00, 0x6c, 0x93, - 0xfc, 0x63, 0x53, 0x20, 0x40, 0x59, 0xbb, 0x2e, 0xad, 0x26, 0x9c, 0xff, - 0x63, 0xbf, 0xb8, 0x7c, 0x2c, 0x87, 0xb8, 0x5d, 0x07, 0xeb, 0x6d, 0x40, - 0x04, 0x8d, 0x48, 0xc2, 0x92, 0x67, 0x47, 0x16, 0x95, 0x9f, 0x31, 0x93, - 0x3e, 0x09, 0x92, 0x7f, 0xcf, 0xaf, 0x10, 0xec, 0x39, 0xff, 0xd7, 0xb7, - 0xee, 0x8f, 0x86, 0x4e, 0x02, 0x83, 0x04, 0x76, 0x9f, 0x32, 0xf5, 0xa6, - 0xc4, 0xeb, 0xc0, 0x7a, 0xa3, 0x9c, 0x77, 0xd0, 0xb8, 0x9e, 0xf7, 0xad, - 0x51, 0x69, 0xf0, 0x1b, 0xf6, 0x57, 0xde, 0x1e, 0x2b, 0x24, 0xa6, 0x15, - 0x20, 0xba, 0xde, 0xe5, 0xfb, 0x62, 0x60, 0x9c, 0x3e, 0x94, 0xa1, 0x6a, - 0x16, 0x02, 0xa2, 0xc0, 0xc7, 0xe9, 0x21, 0x33, 0x5b, 0xf2, 0x18, 0xbc, - 0x6b, 0x11, 0x13, 0x0a, 0xaa, 0x71, 0x4e, 0xd0, 0x6a, 0x17, 0x91, 0x65, - 0xfd, 0x5f, 0x5e, 0x93, 0xba, 0x9f, 0x70, 0xfa, 0x91, 0xc2, 0x74, 0xf2, - 0xbb, 0xe0, 0x47, 0xf5, 0x7c, 0x0a, 0x91, 0x3c, 0x08, 0x13, 0x74, 0x3f, - 0x63, 0xd6, 0x9c, 0xc6, 0xf6, 0x04, 0x7f, 0xd7, 0x5b, 0xa9, 0x8c, 0x74, - 0x0a, 0x57, 0x45, 0x32, 0x5e, 0x31, 0xf9, 0xa2, 0x68, 0xed, 0xc5, 0xba, - 0x08, 0xf5, 0x41, 0x83, 0x98, 0x65, 0x47, 0x9a, 0x86, 0x87, 0x75, 0x64, - 0xa6, 0xd2, 0x6c, 0xfe, 0x0b, 0xdd, 0x17, 0xb0, 0x4e, 0xbe, 0x09, 0xdb, - 0xe7, 0x2f, 0x5e, 0xd4, 0x2b, 0x2d, 0x2d, 0x26, 0x63, 0xd2, 0xeb, 0x64, - 0x79, 0xd2, 0x55, 0x4f, 0xf1, 0x45, 0x89, 0xc2, 0xf9, 0x38, 0x96, 0xab, - 0xba, 0x5a, 0xfb, 0x42, 0x06, 0xb9, 0xe6, 0x9d, 0x16, 0xaf, 0x79, 0x45, - 0xf7, 0xe7, 0xe6, 0x2e, 0xec, 0x1b, 0x69, 0xe6, 0xbf, 0x54, 0x88, 0x2c, - 0xea, 0xd2, 0x0c, 0xc6, 0x96, 0xfe, 0xc9, 0x5a, 0x5b, 0x16, 0xd8, 0x9a, - 0x13, 0x77, 0x43, 0x37, 0x88, 0xe8, 0x6a, 0x82, 0x06, 0xe4, 0x5d, 0x0a, - 0x50, 0xd9, 0xff, 0xd0, 0x62, 0xcd, 0x8c, 0xcf, 0x86, 0x47, 0xd4, 0xba, - 0x7b, 0xec, 0x4d, 0x78, 0xa5, 0xff, 0x67, 0x2f, 0xf8, 0x70, 0xf4, 0x42, - 0x4b, 0xce, 0xa3, 0xef, 0x25, 0x4c, 0x92, 0x3d, 0x7e, 0x10, 0xfb, 0x03, - 0x97, 0x0a, 0xfe, 0xf4, 0xd3, 0x73, 0x64, 0x00, 0xa1, 0x5e, 0x68, 0xdb, - 0x5f, 0x7a, 0xff, 0x2e, 0x9f, 0xe2, 0x75, 0xd4, 0xf9, 0xa4, 0x49, 0xf0, - 0xe9, 0x5b, 0xe2, 0x37, 0x3b, 0x0c, 0xa9, 0x0c, 0x77, 0x3b, 0x7a, 0x64, - 0xe4, 0x7a, 0x9f, 0x10, 0x9d, 0x18, 0x25, 0x92, 0xd0, 0xcf, 0x6d, 0x1c, - 0xdd, 0xc4, 0xd5, 0x51, 0x6c, 0x52, 0x92, 0x62, 0x57, 0xaa, 0x50, 0x44, - 0xdd, 0xc9, 0xef, 0x8d, 0x28, 0x8a, 0x8b, 0x9c, 0x2c, 0xf6, 0x8d, 0x42, - 0xa2, 0x83, 0xf9, 0xc8, 0xc6, 0x65, 0x0b, 0x6b, 0xd5, 0x5f, 0x76, 0x5e, - 0x76, 0xc1, 0x6f, 0x00, 0x2c, 0xc5, 0x8d, 0x27, 0x7b, 0x28, 0xf0, 0xa3, - 0x0d, 0x5d, 0x1e, 0xa9, 0x6e, 0xe6, 0x4c, 0xc0, 0x12, 0x22, 0x77, 0x0f, - 0x9e, 0x73, 0xba, 0x83, 0x41, 0xbf, 0x8f, 0x0d, 0x7c, 0x27, 0x65, 0x85, - 0x76, 0x88, 0xf4, 0xf1, 0x65, 0x33, 0x55, 0x27, 0x18, 0xcb, 0x1d, 0xd0, - 0xc8, 0xf7, 0x2d, 0x53, 0x94, 0x1f, 0x2a, 0xfa, 0xdd, 0x48, 0xf7, 0x9a, - 0x25, 0xf4, 0xba, 0x8c, 0x16, 0xd3, 0xfa, 0xec, 0x7f, 0x67, 0x28, 0x61, - 0x44, 0x0a, 0x55, 0xaf, 0x9e, 0xd1, 0x51, 0x69, 0x9d, 0x22, 0x3b, 0xf5, - 0x17, 0x23, 0x4c, 0xb9, 0x79, 0xcc, 0xac, 0x6e, 0xc0, 0x3e, 0x81, 0xa6, - 0x4e, 0xec, 0x98, 0x18, 0x6f, 0xf1, 0x05, 0x68, 0xd5, 0x9c, 0x43, 0x1c, - 0x17, 0xbc, 0x34, 0x9d, 0xa5, 0x9f, 0x87, 0x53, 0x0d, 0xdf, 0xf7, 0xa1, - 0xb2, 0xab, 0x5d, 0x0e, 0xc6, 0xb7, 0x7a, 0x0d, 0xe5, 0x35, 0xfc, 0xab, - 0xea, 0x40, 0xfb, 0xd5, 0xc6, 0xc0, 0x4c, 0xfc, 0x28, 0x5c, 0xc0, 0x0a, - 0x4d, 0xac, 0x1e, 0xb0, 0xb3, 0x63, 0xdd, 0x9d, 0x48, 0x87, 0xee, 0x2d, - 0xb3, 0x63, 0xbf, 0x9c, 0x21, 0xe2, 0x5c, 0xd6, 0x03, 0x79, 0x25, 0x00, - 0x98, 0xf8, 0xf6, 0xb5, 0x4c, 0x6f, 0xfb, 0x16, 0x09, 0xbc, 0x64, 0x10, - 0x78, 0xb7, 0x57, 0x26, 0x40, 0x0c, 0xf1, 0x09, 0xcc, 0x93, 0xc1, 0x52, - 0xf4, 0x74, 0xf6, 0x96, 0xb6, 0x97, 0x73, 0xcd, 0x1a, 0xb4, 0x4d, 0xac, - 0x4f, 0xfd, 0x76, 0x0a, 0xc1, 0xc0, 0xd7, 0x94, 0xe4, 0x89, 0xd5, 0xc6, - 0x37, 0xe1, 0xf8, 0x47, 0x20, 0x78, 0xc8, 0xf9, 0xe9, 0xdf, 0xaa, 0xe9, - 0x53, 0x51, 0x0c, 0xc5, 0xac, 0xea, 0x6c, 0xd4, 0x4d, 0x2e, 0x4d, 0x78, - 0x36, 0x00, 0x36, 0x5b, 0xce, 0xca, 0x92, 0xea, 0xb9, 0x90, 0x7e, 0x15, - 0xc2, 0xe2, 0xa9, 0xff, 0x53, 0xa5, 0x91, 0x0f, 0x26, 0x79, 0x72, 0x8e, - 0x69, 0xd9, 0xde, 0xdf, 0x41, 0x85, 0x5a, 0x9b, 0xbe, 0xb7, 0xf7, 0x0f, - 0x0c, 0x24, 0x55, 0xc9, 0x64, 0x85, 0x69, 0xa5, 0x09, 0x92, 0x25, 0x47, - 0x0a, 0x47, 0x49, 0x3d, 0x16, 0x2d, 0xe1, 0x44, 0xf9, 0x3a, 0x0a, 0x82, - 0xcf, 0x3a, 0xf4, 0x1f, 0x18, 0xc4, 0xba, 0x5c, 0x4a, 0xdb, 0xe8, 0xf3, - 0xbb, 0xa4, 0x71, 0x96, 0x6f, 0x5a, 0x77, 0x53, 0x74, 0xf9, 0x40, 0xbc, - 0xae, 0x54, 0xf5, 0x02, 0xae, 0xd1, 0x5f, 0x08, 0xf6, 0x44, 0x65, 0x70, - 0xc2, 0x97, 0x34, 0x10, 0x9a, 0x74, 0x6c, 0x4f, 0x22, 0xa1, 0x50, 0xdf, - 0x17, 0xec, 0x82, 0xed, 0x1d, 0xca, 0x19, 0xdd, 0x67, 0x56, 0x77, 0x3f, - 0x3d, 0x91, 0x19, 0x0e, 0xbb, 0x3b, 0x71, 0x4c, 0xfc, 0x48, 0x60, 0x49, - 0xb2, 0x40, 0x80, 0xbf, 0xc6, 0x71, 0xdf, 0x58, 0x59, 0x73, 0x68, 0x4e, - 0xdb, 0x63, 0xc8, 0xd8, 0x37, 0x97, 0x6a, 0x0a, 0x2a, 0x46, 0xbf, 0xd6, - 0xab, 0x38, 0xaf, 0xf6, 0x42, 0xe6, 0x82, 0x49, 0x3b, 0x6a, 0x0a, 0x43, - 0x04, 0x59, 0xd3, 0x29, 0xf5, 0xd7, 0xef, 0x9e, 0x81, 0x57, 0x3e, 0xa9, - 0x65, 0xa2, 0x20, 0xfd, 0xa3, 0xdc, 0x1e, 0xc3, 0xde, 0xcc, 0x7d, 0xc0, - 0x93, 0xb9, 0x60, 0x56, 0x52, 0x13, 0x51, 0x98, 0xac, 0x60, 0xc2, 0x5f, - 0x84, 0xe9, 0xd6, 0xaa, 0xc6, 0x3c, 0x50, 0x99, 0x98, 0xf5, 0x6e, 0xd7, - 0x7c, 0xe1, 0x08, 0x80, 0x24, 0x76, 0xd0, 0xcc, 0x3a, 0xbd, 0x31, 0x18, - 0x40, 0x7f, 0x79, 0x66, 0xf4, 0x74, 0xb5, 0x83, 0xb3, 0xe2, 0xcc, 0xbc, - 0x49, 0x67, 0x5f, 0x3a, 0x1f, 0xd2, 0x4f, 0x79, 0xf6, 0x38, 0x67, 0xf6, - 0x02, 0x55, 0x21, 0x64, 0xf2, 0x93, 0x5e, 0xbb, 0x3d, 0xa7, 0x5a, 0xc6, - 0xa7, 0x90, 0xd6, 0x46, 0x71, 0x13, 0xb0, 0xa3, 0x47, 0xfe, 0xd5, 0xe0, - 0x17, 0xbd, 0xdc, 0x35, 0x72, 0x68, 0x4e, 0xa0, 0x96, 0xc2, 0xbc, 0x78, - 0x5b, 0xb1, 0x4f, 0x34, 0x26, 0xdc, 0x0f, 0x84, 0x58, 0x6e, 0x7d, 0xb1, - 0x54, 0xc2, 0x9d, 0xac, 0x2c, 0xde, 0xf5, 0xf8, 0x72, 0x43, 0x15, 0x5c, - 0x52, 0x48, 0x0c, 0x67, 0x39, 0x25, 0x8c, 0x3f, 0x49, 0xd2, 0x8b, 0x51, - 0x43, 0xe8, 0x2f, 0x3c, 0x16, 0xdc, 0x48, 0x0b, 0x76, 0xee, 0xd9, 0xb7, - 0x8e, 0x2e, 0x99, 0xbb, 0xa5, 0xda, 0xdd, 0xfe, 0x99, 0x47, 0xf1, 0x22, - 0x53, 0xfc, 0x2e, 0xaa, 0xf7, 0xcf, 0x7b, 0x13, 0x1b, 0x08, 0x18, 0x3a, - 0x6b, 0xe4, 0x66, 0x8a, 0x3e, 0x77, 0xbd, 0x14, 0xb0, 0x90, 0x60, 0xaa, - 0x97, 0x65, 0x1a, 0xd5, 0x0e, 0xea, 0x12, 0xa5, 0x05, 0x87, 0x78, 0x0f, - 0xf4, 0x05, 0xd5, 0x8c, 0x2e, 0x14, 0x26, 0x80, 0x01, 0x7d, 0x06, 0x79, - 0x37, 0x63, 0x70, 0xb1, 0x57, 0x2b, 0x62, 0x2a, 0xe8, 0x76, 0x48, 0x46, - 0x79, 0xea, 0x4a, 0x7a, 0x35, 0xf2, 0xcb, 0x10, 0x7a, 0x3b, 0x62, 0x04, - 0x34, 0x76, 0xe0, 0xf7, 0x9c, 0x1d, 0x73, 0x89, 0x90, 0xf2, 0xc5, 0x79, - 0x7c, 0x15, 0xa0, 0x7f, 0x99, 0x5f, 0xb8, 0x73, 0x62, 0x75, 0x6b, 0x0f, - 0xbe, 0xf1, 0x34, 0x5f, 0x28, 0x14, 0x18, 0x71, 0xe9, 0xde, 0xb7, 0x28, - 0x00, 0x65, 0xa2, 0x08, 0x57, 0xdd, 0x5e, 0x14, 0xa9, 0xc5, 0x0b, 0xb1, - 0x92, 0xa8, 0x20, 0xb2, 0xbd, 0x42, 0x77, 0xf5, 0xb0, 0xa0, 0x00, 0xbe, - 0xa7, 0x82, 0xd0, 0x6a, 0xc8, 0xa9, 0x57, 0xfa, 0x07, 0x3a, 0x97, 0x69, - 0x60, 0xe8, 0xd1, 0x94, 0x0d, 0xa5, 0x7d, 0x74, 0x7f, 0x50, 0xc6, 0x50, - 0x9b, 0x05, 0x41, 0x8d, 0x08, 0x2b, 0x2b, 0x01, 0x37, 0xd0, 0xee, 0x4d, - 0xca, 0x15, 0x70, 0xca, 0x75, 0x4a, 0xc2, 0x54, 0x10, 0xc0, 0x80, 0x27, - 0xe1, 0xcd, 0x52, 0xec, 0x06, 0xb5, 0x73, 0xf4, 0xc2, 0x0b, 0xea, 0x79, - 0xe6, 0x30, 0x5d, 0x41, 0x07, 0x4c, 0x8a, 0xae, 0x03, 0xb0, 0x9b, 0xc2, - 0x5d, 0xf2, 0x43, 0x3f, 0x5e, 0xb7, 0x53, 0x36, 0xc3, 0x81, 0xf6, 0xe5, - 0xd9, 0x35, 0x69, 0x04, 0xe0, 0x36, 0xb8, 0xeb, 0x71, 0x58, 0x71, 0x6f, - 0x47, 0x17, 0xf2, 0x16, 0xe2, 0x09, 0xc7, 0xc2, 0x35, 0xa4, 0x4d, 0xfe, - 0x1a, 0xd2, 0x28, 0x06, 0x34, 0xb3, 0x0f, 0x33, 0xf0, 0xd6, 0x18, 0xf4, - 0x6d, 0x54, 0xb2, 0xbd, 0x88, 0x17, 0x02, 0x40, 0x11, 0x21, 0x59, 0x8b, - 0x62, 0xcb, 0x87, 0xad, 0x0f, 0xc0, 0x08, 0x14, 0x29, 0xf9, 0x5c, 0x3e, - 0xfc, 0xe4, 0x95, 0x1c, 0x9b, 0x60, 0x94, 0xcb, 0x83, 0xb4, 0x1c, 0x1b, - 0xbd, 0xfd, 0x55, 0x88, 0xbf, 0xa6, 0xa5, 0x94, 0xc2, 0xb3, 0x76, 0x5a, - 0x9b, 0xd4, 0xc1, 0xe1, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x51, 0x00, - 0x0a, 0xec, 0x05, 0xf9, 0x03, 0x35, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x85, 0x61, 0x04, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, - 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, - 0x56, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0x41, - 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, - 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, - 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, - 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, - 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, - 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x4e, 0x6b, 0x19, 0x54, 0xf5, 0xf0, 0xaf, 0x61, 0xfa, 0x1e, 0x1f, 0x1f, - 0x5e, 0x17, 0xd3, 0x8e, 0x04, 0x4b, 0xfa, 0x8d, 0x34, 0x55, 0x45, 0x92, - 0xd5, 0xd0, 0xb8, 0x8e, 0x56, 0xe9, 0x39, 0x37, 0x8e, 0x7d, 0x7e, 0x88, - 0x56, 0x30, 0x48, 0x61, 0xb4, 0xed, 0x1e, 0x15, 0x64, 0xfc, 0xa8, 0xb1, - 0x02, 0xbb, 0x9c, 0x14, 0xe9, 0xd1, 0xe0, 0xcf, 0x40, 0x41, 0x46, 0x5d, - 0xb0, 0xda, 0xba, 0x8c, 0x3a, 0x41, 0x12, 0x91, 0xeb, 0x13, 0xdf, 0x2c, - 0x6e, 0x25, 0x75, 0xb3, 0x92, 0xff, 0xb0, 0xa9, 0xa5, 0xef, 0x3a, 0x4c, - 0x6b, 0x54, 0x55, 0x0e, 0x7e, 0x93, 0x16, 0x7f, 0xe6, 0x22, 0x22, 0x51, - 0xe2, 0x22, 0xa4, 0x35, 0x33, 0xec, 0xdc, 0xa8, 0x73, 0x64, 0x59, 0xc1, - 0x4d, 0xad, 0xa0, 0x56, 0xbf, 0xad, 0x45, 0x64, 0xda, 0xb0, 0x08, 0x4a, - 0x82, 0xfc, 0x0d, 0x21, 0xb7, 0x8b, 0x59, 0x90, 0xac, 0xb2, 0x08, 0x1b, - 0x50, 0x82, 0x0c, 0x87, 0xd6, 0x48, 0x5c, 0xdd, 0x6b, 0x02, 0x7f, 0xab, - 0x3e, 0xdc, 0x25, 0x1f, 0x53, 0x49, 0xb5, 0x6d, 0x0f, 0x0c, 0xbe, 0xae, - 0x1d, 0xab, 0x8b, 0x13, 0x9d, 0xd7, 0x6c, 0x91, 0xaa, 0x90, 0xe8, 0x63, - 0x06, 0x6d, 0xa8, 0xf0, 0xea, 0x21, 0xf6, 0xa8, 0xfd, 0x15, 0x6d, 0x78, - 0x66, 0x42, 0xae, 0x4c, 0xa7, 0x7a, 0x85, 0x15, 0x7d, 0xf9, 0xed, 0x92, - 0x1c, 0xde, 0x7c, 0x71, 0xd0, 0x6b, 0x25, 0x24, 0x22, 0x6b, 0xe4, 0x5e, - 0x60, 0xda, 0xbd, 0x95, 0x32, 0x21, 0xe8, 0xb1, 0xcb, 0x07, 0x1b, 0x08, - 0xf5, 0x49, 0x4f, 0x60, 0x8c, 0xe8, 0xb0, 0x71, 0x2a, 0x8b, 0x91, 0x17, - 0x16, 0x93, 0x39, 0x49, 0x8d, 0x47, 0x1f, 0xe8, 0x2b, 0x12, 0xa6, 0x4f, - 0xa1, 0x77, 0x37, 0xe7, 0x39, 0x68, 0x5c, 0x68, 0x2b, 0xad, 0xa8, 0x3c, - 0xa0, 0x8a, 0xf5, 0xb7, 0x51, 0x9f, 0x2d, 0x85, 0x1a, 0x99, 0x02, 0x4c, - 0x84, 0x5f, 0x4d, 0xe6, 0x55, 0x64, 0xd7, 0x5b, 0x00, 0x48, 0xde, 0xf2, - 0x77, 0x39, 0x6e, 0x7b, 0x0e, 0x97, 0x81, 0xd2, 0x8a, 0x1b, 0x20, 0x30, - 0x60, 0xbe, 0x94, 0xf0, 0x09, 0x34, 0xfe, 0x64, 0xbb, 0xbb, 0xcb, 0x97, - 0x91, 0x43, 0x6d, 0x57, 0x45, 0x7d, 0xc5, 0x43, 0x5a, 0x78, 0x0d, 0xd8, - 0xb9, 0xf5, 0x43, 0x13, 0x21, 0xd6, 0x31, 0x6e, 0x21, 0x9a, 0x3f, 0x8f, - 0xe2, 0x57, 0x32, 0xdb, 0x50, 0x61, 0x45, 0x9f, 0xb9, 0x7b, 0x73, 0x10, - 0xb9, 0xd0, 0x66, 0xaf, 0xa0, 0x3a, 0x77, 0x93, 0x9b, 0xd3, 0x32, 0xb0, - 0xda, 0x01, 0x17, 0x90, 0x1a, 0xa5, 0x9f, 0x2b, 0x9f, 0x8f, 0x93, 0x6e, - 0x4d, 0x69, 0x40, 0xec, 0x56, 0x76, 0x61, 0x2d, 0xcd, 0xdf, 0xc5, 0xfe, - 0x9e, 0x26, 0x2f, 0x78, 0x78, 0xab, 0x5a, 0x32, 0xa6, 0xe9, 0x7a, 0x85, - 0x15, 0xc6, 0x2f, 0x10, 0x37, 0x35, 0xf6, 0xfa, 0xc0, 0xdd, 0xb0, 0xa9, - 0xa1, 0x0d, 0x22, 0xc1, 0xab, 0xc8, 0x8c, 0x2a, 0x77, 0x0b, 0xd3, 0x52, - 0xdb, 0x53, 0x33, 0x78, 0xf3, 0xf6, 0x33, 0x5d, 0x9f, 0xb7, 0xb6, 0x46, - 0xf6, 0x79, 0x9e, 0x08, 0x16, 0xd8, 0x48, 0xcf, 0x70, 0x4d, 0x00, 0x36, - 0x30, 0xdb, 0xb3, 0x76, 0xa5, 0x16, 0x78, 0xf8, 0xaf, 0x71, 0x6b, 0x50, - 0x92, 0xfc, 0x52, 0xd6, 0x2c, 0xee, 0xa8, 0xb0, 0xbe, 0x89, 0x18, 0xc0, - 0x7a, 0x72, 0xa5, 0x36, 0x31, 0x7b, 0x86, 0xca, 0xc0, 0xe4, 0x08, 0x17, - 0x1d, 0x6e, 0xe5, 0x4c, 0x82, 0x86, 0x3e, 0x8c, 0x60, 0xf7, 0x04, 0x8f, - 0x2c, 0x64, 0x3d, 0x2e, 0x23, 0x22, 0x10, 0x8e, 0x88, 0x45, 0xcd, 0x18, - 0xd6, 0xba, 0x4c, 0x40, 0x1e, 0x31, 0xfb, 0xbf, 0xda, 0xe7, 0xae, 0x87, - 0x72, 0x81, 0xb2, 0x69, 0x97, 0xe3, 0x2c, 0x5e, 0xbb, 0x26, 0x1b, 0xe2, - 0x83, 0xf3, 0x90, 0x37, 0x0d, 0xb1, 0xa2, 0x58, 0x88, 0x63, 0xe7, 0x6e, - 0x4a, 0xbd, 0x76, 0x90, 0x73, 0x65, 0x85, 0x96, 0xcc, 0x2d, 0xb7, 0x51, - 0x0d, 0xa7, 0x8a, 0xe2, 0x8c, 0x47, 0xb9, 0x44, 0x09, 0xc3, 0x8f, 0x24, - 0x65, 0x79, 0xf0, 0xd0, 0xc3, 0xa5, 0x1f, 0xc3, 0xca, 0xd7, 0x57, 0xac, - 0x1c, 0xcf, 0xa9, 0xfc, 0x81, 0x12, 0x53, 0x0b, 0xe5, 0x9d, 0x38, 0x29, - 0x14, 0xd6, 0xf5, 0x17, 0x06, 0xfb, 0xc2, 0x9d, 0x25, 0x10, 0xf9, 0xde, - 0x4b, 0x33, 0x0d, 0xf1, 0xdd, 0xf5, 0xbc, 0xa8, 0x2b, 0xdc, 0xdb, 0x51, - 0x7d, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x85, 0x41, 0x03, - 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, - 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, - 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, 0x16, 0x17, 0x13, 0x41, - 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0x41, 0xb7, 0x59, 0x5c, 0x83, - 0x25, 0xab, 0x8f, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, 0x0f, 0xc0, 0x25, 0xc5, - 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, 0x52, 0xf9, 0x26, 0x9b, - 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, - 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe3, 0xb5, 0xfb, 0x0d, - 0xa0, 0x75, 0xd1, 0xa9, 0x33, 0x31, 0xc6, 0x84, 0xba, 0x58, 0x50, 0xb0, - 0x71, 0x32, 0x4f, 0x72, 0x88, 0x46, 0x71, 0x06, 0xb3, 0x82, 0x5e, 0x30, - 0xfd, 0xc8, 0x5b, 0xc8, 0xf3, 0x24, 0x92, 0xe0, 0xce, 0x8b, 0xf7, 0x50, - 0x20, 0xc3, 0xeb, 0x1b, 0xf4, 0xef, 0x4f, 0xfa, 0x28, 0x4d, 0x02, 0x4d, - 0x7c, 0x46, 0xf1, 0x91, 0x89, 0xde, 0xc6, 0xfa, 0x79, 0xc5, 0xbd, 0x17, - 0xa1, 0xc6, 0x1d, 0x8c, 0xd4, 0x57, 0xa6, 0x58, 0x66, 0xce, 0xe5, 0xb0, - 0x8b, 0x54, 0xef, 0x3b, 0x24, 0x9b, 0xa4, 0xc4, 0x6a, 0xa9, 0xf3, 0x1b, - 0x73, 0x37, 0x10, 0xc0, 0xe1, 0xcb, 0xc8, 0x90, 0x14, 0x88, 0x97, 0x25, - 0x8b, 0x7c, 0xa2, 0x66, 0x36, 0x89, 0x55, 0x8d, 0x68, 0xe7, 0x55, 0x20, - 0x10, 0x68, 0x14, 0x2f, 0x05, 0x3b, 0xe3, 0x81, 0x08, 0xfe, 0x54, 0x7d, - 0xa5, 0x51, 0x2a, 0x39, 0x86, 0x11, 0xce, 0x26, 0x8d, 0xe1, 0xec, 0x30, - 0x3f, 0xf9, 0xa3, 0x3d, 0x43, 0x6c, 0xad, 0x23, 0x54, 0x20, 0x7d, 0x60, - 0xa5, 0x42, 0xbd, 0x3d, 0x22, 0xc8, 0x95, 0x9b, 0xab, 0x5b, 0xf7, 0xc1, - 0x11, 0xfb, 0xf1, 0x70, 0xa2, 0x43, 0xcb, 0x53, 0x8c, 0x18, 0x0d, 0x8a, - 0xb2, 0xa5, 0xbd, 0x87, 0x2b, 0x8b, 0xdf, 0x79, 0x96, 0x29, 0x20, 0x8e, - 0x34, 0x4a, 0x45, 0x96, 0x33, 0x8d, 0xa8, 0xb0, 0x47, 0x26, 0x4f, 0x8b, - 0xad, 0xb5, 0xa7, 0x2d, 0x15, 0x58, 0x92, 0x7b, 0x4b, 0x53, 0xa9, 0x5e, - 0x51, 0x39, 0x9c, 0xbd, 0x7e, 0x8f, 0x7f, 0x9f, 0xb7, 0x38, 0xcd, 0x7e, - 0xff, 0x7d, 0x73, 0x1f, 0xab, 0x3a, 0x61, 0xaa, 0xde, 0x73, 0x28, 0xb2, - 0x6f, 0x1e, 0xc9, 0x5e, 0x59, 0x71, 0x6b, 0xe8, 0x6d, 0x63, 0xf3, 0x9e, - 0xdf, 0x52, 0x86, 0x60, 0x1c, 0xbd, 0xc7, 0xeb, 0xaf, 0x82, 0x83, 0xaa, - 0x68, 0xa6, 0x71, 0x7a, 0xe8, 0xd3, 0xd4, 0xc8, 0xe7, 0x9a, 0xcc, 0x3c, - 0xc2, 0xdf, 0x0c, 0x42, 0xe8, 0xae, 0xc7, 0xd8, 0x1f, 0x66, 0x0a, 0x57, - 0x09, 0x14, 0x02, 0x74, 0x9a, 0x7a, 0x07, 0xb3, 0x19, 0x87, 0x8d, 0xa9, - 0x45, 0x25, 0x26, 0x48, 0xb3, 0x20, 0x3c, 0xf7, 0x5a, 0x1c, 0xae, 0xc7, - 0x06, 0x9e, 0x1a, 0x0a, 0x23, 0xf3, 0x39, 0x25, 0x2c, 0x91, 0x7c, 0x5e, - 0x87, 0xe7, 0x55, 0xc4, 0x69, 0xf3, 0x3e, 0xeb, 0xc5, 0x44, 0xa8, 0xe3, - 0xec, 0xc1, 0xfe, 0x70, 0xbf, 0xdd, 0xbb, 0xf0, 0x22, 0xe1, 0x19, 0xa1, - 0x6d, 0x7a, 0x9a, 0xa3, 0x36, 0x90, 0xbc, 0x1a, 0xa7, 0x37, 0xf8, 0xcf, - 0xdc, 0x9e, 0x23, 0x17, 0x42, 0xd5, 0xa0, 0xd3, 0x36, 0xb0, 0xb1, 0xf5, - 0x1a, 0x95, 0xbc, 0xe8, 0x0f, 0xb4, 0x58, 0x76, 0x40, 0x74, 0xd0, 0x21, - 0xaf, 0xae, 0xc6, 0xb4, 0x84, 0xd7, 0xfc, 0x70, 0x6a, 0x8f, 0x41, 0x57, - 0x2b, 0x8e, 0xbc, 0x6b, 0x21, 0x65, 0xcc, 0xa0, 0x8e, 0xb9, 0x0b, 0x46, - 0xef, 0xb3, 0x56, 0xec, 0x8a, 0xd6, 0x4d, 0xdd, 0x97, 0xbd, 0xdd, 0x65, - 0xbf, 0x26, 0xab, 0xba, 0x0d, 0xd1, 0x22, 0x7e, 0xb6, 0x8a, 0xb4, 0x92, - 0xc9, 0xa6, 0x48, 0xd4, 0x64, 0x17, 0xc6, 0xb5, 0xb9, 0xce, 0x45, 0x6d, - 0xf4, 0xd9, 0x3d, 0xa0, 0xb3, 0x86, 0x67, 0x19, 0xad, 0xd8, 0x32, 0x2b, - 0xf7, 0xab, 0x90, 0xee, 0x91, 0x8f, 0x73, 0xe4, 0xc0, 0x29, 0xde, 0x45, - 0x8a, 0xfb, 0xca, 0x74, 0x3b, 0x50, 0xf1, 0x34, 0x40, 0x36, 0x25, 0x8a, - 0xe0, 0xf9, 0x7f, 0x55, 0xc5, 0x59, 0x89, 0xbb, 0x43, 0x03, 0xa3, 0xdd, - 0x8c, 0x83, 0x03, 0xc6, 0xef, 0x60, 0x02, 0xc5, 0xd8, 0x29, 0x3f, 0x2f, - 0x56, 0xba, 0x8b, 0x97, 0x0a, 0xc4, 0xf3, 0x07, 0x3f, 0xca, 0x0f, 0xdf, - 0xb9, 0x5d, 0x59, 0x42, 0x36, 0x02, 0xf7, 0x0f, 0x03, 0xc8, 0xf2, 0xb7, - 0xd8, 0x64, 0xcd, 0x1e, 0xe4, 0xe1, 0xa0, 0xbd, 0x0f, 0x70, 0xfb, 0xcf, - 0x77, 0x77, 0xef, 0x9d, 0xdd, 0xc1, 0x61, 0xab, 0x3c, 0xdb, 0xe4, 0x35, - 0x11, 0xab, 0xde, 0x40, 0x7d, 0x51, 0xba, 0xb1, 0x7d, 0x13, 0xf1, 0x58, - 0x03, 0xca, 0xae, 0x12, 0x4a, 0xa3, 0xb6, 0xed, 0xd7, 0x18, 0x1c, 0xb6, - 0xd8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x89, 0x70, 0x02, - 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, - 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, - 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x91, 0x62, 0x29, 0x13, 0x41, - 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x41, 0xb7, 0x59, 0x5c, 0x4b, - 0xa2, 0xb8, 0x84, 0x37, 0xee, 0x5a, 0x85, 0xe1, 0xcb, 0xdd, 0xc8, 0xce, - 0x07, 0x77, 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, 0x30, 0x3a, 0xcd, 0x64, - 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, - 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xfa, 0x4b, 0x92, 0xea, - 0x4b, 0xef, 0xde, 0x03, 0xd5, 0xe2, 0xee, 0xe5, 0x67, 0xd4, 0x99, 0x63, - 0x37, 0x68, 0x91, 0xbc, 0x4f, 0xbc, 0x41, 0xe9, 0x01, 0xc5, 0x4d, 0x59, - 0x2a, 0x9b, 0x42, 0x60, 0x07, 0x7e, 0xc2, 0xbc, 0x62, 0xcc, 0xbc, 0xa7, - 0xf1, 0xe4, 0x20, 0x5f, 0xe3, 0xe8, 0x9f, 0x16, 0x7a, 0x77, 0xd2, 0xb7, - 0xad, 0x98, 0xc3, 0xb4, 0x99, 0xdb, 0x36, 0x1a, 0xe4, 0xf0, 0xfc, 0xe1, - 0xc8, 0x2f, 0x8c, 0xcf, 0x6f, 0x97, 0x48, 0x09, 0x4a, 0xae, 0xc7, 0xf9, - 0xfb, 0xb7, 0x5f, 0x64, 0x6a, 0x79, 0xa1, 0x27, 0xeb, 0x59, 0x7d, 0x0a, - 0xd3, 0x56, 0x27, 0x1d, 0x56, 0xd3, 0x62, 0x1e, 0x7f, 0xb5, 0x0f, 0x50, - 0x9c, 0x4d, 0x1d, 0xd5, 0x53, 0xcb, 0x08, 0x07, 0x56, 0x93, 0x9e, 0x4f, - 0xb2, 0xd0, 0x12, 0xc7, 0x50, 0xcf, 0x99, 0xac, 0x24, 0xdb, 0x94, 0xab, - 0x08, 0x89, 0x60, 0x2f, 0x6c, 0xd0, 0xc2, 0x2e, 0x6d, 0x08, 0xe0, 0xf9, - 0xfc, 0x7e, 0x5b, 0x54, 0x92, 0xaa, 0x01, 0xfd, 0xf6, 0x49, 0xb1, 0xfc, - 0xd4, 0x51, 0x83, 0x73, 0xaf, 0xac, 0x38, 0x78, 0x8e, 0x9b, 0x42, 0x4e, - 0x83, 0xbb, 0x9d, 0xd7, 0x5c, 0xdb, 0x73, 0xd3, 0x3d, 0x2c, 0xe2, 0x4c, - 0x57, 0xa4, 0xfa, 0xdf, 0x53, 0x44, 0x29, 0x71, 0x22, 0xb6, 0x89, 0x84, - 0x80, 0xca, 0xcb, 0x7c, 0x5f, 0x15, 0x19, 0x4b, 0x06, 0x28, 0x5d, 0x4a, - 0x9b, 0xc8, 0x59, 0xa7, 0x9e, 0xa2, 0xba, 0x32, 0x5d, 0xf2, 0xcb, 0xa9, - 0xc6, 0xba, 0x09, 0xee, 0xd2, 0x00, 0x32, 0x53, 0x8b, 0x39, 0xff, 0xc4, - 0x63, 0xac, 0xbc, 0x1c, 0x15, 0xb8, 0x79, 0xc2, 0xe3, 0xda, 0x8d, 0xb2, - 0x95, 0x8d, 0x3c, 0x10, 0xec, 0x93, 0x03, 0xc1, 0x07, 0x84, 0x47, 0xf3, - 0xeb, 0xe3, 0x10, 0x33, 0xa1, 0x2e, 0xc6, 0x48, 0x44, 0x2c, 0x38, 0x36, - 0xe1, 0x68, 0x3c, 0xe8, 0x0d, 0x5c, 0x8a, 0xdc, 0x1f, 0xe8, 0x3b, 0xb2, - 0x0f, 0xea, 0x27, 0x18, 0x7a, 0x7f, 0x82, 0x6a, 0x96, 0xfa, 0x63, 0xd3, - 0x5c, 0xbf, 0xf6, 0x1d, 0x9e, 0xf2, 0xd9, 0x83, 0x3b, 0xf0, 0x1b, 0x29, - 0x49, 0x8d, 0xb3, 0xdc, 0x60, 0x47, 0x9d, 0x2b, 0xac, 0xd6, 0x6e, 0x59, - 0xb3, 0x09, 0x0d, 0xa7, 0xfb, 0x0e, 0x43, 0x56, 0xa3, 0x80, 0x2c, 0x9f, - 0xc1, 0xe8, 0xd2, 0xef, 0x05, 0xc5, 0x25, 0x4c, 0x5b, 0x67, 0x1a, 0x54, - 0x0b, 0x55, 0x83, 0x3d, 0xfb, 0x38, 0x0e, 0xd2, 0xc0, 0x1a, 0xcd, 0x9f, - 0x81, 0x3e, 0x6d, 0x7f, 0xe4, 0x3f, 0x34, 0x0c, 0xdc, 0x99, 0x5a, 0x77, - 0xd4, 0xe4, 0xff, 0x4a, 0x7b, 0x8a, 0x95, 0xe4, 0x46, 0x3d, 0x7b, 0xc4, - 0x0e, 0xdd, 0xc7, 0x2d, 0xf4, 0xfa, 0x5e, 0x50, 0xae, 0x9c, 0xca, 0x64, - 0x97, 0xad, 0x03, 0x30, 0x3e, 0x05, 0xc4, 0x33, 0x1e, 0x2c, 0x03, 0x2b, - 0x06, 0x2c, 0x79, 0x13, 0xae, 0x1b, 0x65, 0xf1, 0x1f, 0xb9, 0xe4, 0x8a, - 0x06, 0x96, 0xea, 0xc4, 0x6e, 0x17, 0x19, 0x03, 0x54, 0xe8, 0x39, 0xe7, - 0xeb, 0x7b, 0xbc, 0x25, 0xd6, 0x55, 0x6c, 0x76, 0x5f, 0xf7, 0xd2, 0x0e, - 0x54, 0x46, 0x9f, 0x5d, 0xa4, 0x3d, 0xac, 0xa1, 0x19, 0x7b, 0x7c, 0x5a, - 0x44, 0x54, 0x65, 0x5d, 0x43, 0x26, 0x5f, 0x47, 0x63, 0x2b, 0x00, 0xe3, - 0xb4, 0xe9, 0x70, 0x8c, 0x31, 0x50, 0x7c, 0x37, 0x01, 0x43, 0x6c, 0x29, - 0xc3, 0xae, 0x59, 0xb7, 0x0b, 0xb9, 0x9a, 0x72, 0x69, 0xe0, 0xd1, 0xb0, - 0x47, 0x53, 0xf0, 0xb8, 0x8b, 0xc8, 0x80, 0x3c, 0x58, 0xfa, 0x34, 0xf2, - 0x44, 0x27, 0xb7, 0xfc, 0x44, 0x73, 0xfb, 0xe5, 0xe1, 0x8b, 0xdb, 0x2b, - 0xc5, 0x73, 0x97, 0x25, 0xb3, 0xef, 0x16, 0xfd, 0xba, 0x08, 0x3d, 0x15, - 0x2a, 0x03, 0xb5, 0x4d, 0x2a, 0x8c, 0xf5, 0x53, 0x11, 0x97, 0x3c, 0x35, - 0x66, 0x1d, 0x59, 0xc8, 0xc9, 0x79, 0x48, 0x6d, 0x19, 0x4f, 0xa7, 0x07, - 0x25, 0x4d, 0xb2, 0xfc, 0x1e, 0xbc, 0x9a, 0x0c, 0x6e, 0x46, 0x2b, 0x58, - 0x45, 0xbe, 0xe7, 0x8e, 0x09, 0xa5, 0xa0, 0xd3, 0x5a, 0xf5, 0x6e, 0x92, - 0x7b, 0x5b, 0x21, 0x07, 0xab, 0xf3, 0x57, 0xd6, 0x93, 0x4b, 0x56, 0x3b, - 0x9c, 0x3c, 0x4b, 0x85, 0xb0, 0x62, 0x18, 0x3e, 0x7c, 0xc5, 0x25, 0xe2, - 0xf2, 0xfc, 0xa3, 0xca, 0x88, 0xd6, 0xb2, 0x01, 0x11, 0xcd, 0x93, 0x9a, - 0x76, 0x84, 0xc2, 0x2d, 0x07, 0xd3, 0xbb, 0xac, 0x99, 0xde, 0x29, 0x00, - 0xf7, 0x3d, 0x06, 0xea, 0xdc, 0x88, 0xfd, 0xc6, 0x6e, 0xf5, 0x55, 0x64, - 0x73, 0x4e, 0x3b, 0xa9, 0x24, 0x44, 0x63, 0x1c, 0x50, 0x29, 0x66, 0xc4, - 0x74, 0x70, 0xcb, 0xd8, 0x57, 0x0c, 0x60, 0x50, 0x6d, 0x64, 0x64, 0xd1, - 0x53, 0xef, 0x62, 0xef, 0x61, 0xf4, 0xe2, 0xfe, 0x4c, 0xaa, 0x9f, 0xe9, - 0x81, 0x01, 0xe1, 0x97, 0xaa, 0xc0, 0x06, 0xbf, 0x40, 0x19, 0x64, 0x24, - 0x6e, 0x80, 0x73, 0x00, 0x5c, 0x86, 0x3e, 0xc2, 0xcf, 0x8c, 0x09, 0xc0, - 0xfa, 0x4a, 0xb3, 0x3a, 0x0d, 0x81, 0x1d, 0x49, 0x58, 0x09, 0xe8, 0x31, - 0x0e, 0xd7, 0x60, 0x8d, 0x9d, 0xfe, 0x9f, 0x35, 0xf7, 0x8d, 0xa1, 0x12, - 0x04, 0xb2, 0x47, 0xac, 0x31, 0x92, 0x03, 0x0a, 0x10, 0x50, 0xb7, 0x86, - 0x3d, 0xcd, 0x15, 0x8f, 0x25, 0x93, 0x24, 0x7a, 0x5f, 0xa0, 0x3c, 0x41, - 0xaa, 0xb2, 0x96, 0xce, 0xd3, 0x0c, 0xe9, 0x55, 0x66, 0x37, 0x5c, 0xf3, - 0x02, 0x3c, 0xa1, 0x09, 0xa4, 0x9e, 0x90, 0xc9, 0x82, 0xab, 0xd4, 0x04, - 0x2e, 0x8b, 0xb4, 0x8d, 0x5b, 0xcc, 0x19, 0x5a, 0xfe, 0x86, 0x9c, 0x6c, - 0x56, 0x09, 0x86, 0x36, 0xef, 0xe8, 0x1f, 0x3a, 0xbc, 0xda, 0x4c, 0x68, - 0xac, 0xa2, 0x1b, 0xd1, 0x23, 0x75, 0x28, 0xed, 0x9f, 0x84, 0x2e, 0x40, - 0x57, 0x5f, 0x0a, 0x85, 0xe4, 0x77, 0x59, 0x53, 0x12, 0x32, 0xd6, 0x3c, - 0x1b, 0xaf, 0x95, 0xa1, 0x1c, 0x14, 0x1a, 0x42, 0x7d, 0xc7, 0x7b, 0x21, - 0xd1, 0x4e, 0xb9, 0x29, 0x85, 0xef, 0xa2, 0x61, 0x1c, 0xe5, 0x16, 0x44, - 0xbe, 0xfb, 0xa3, 0x21, 0x4f, 0x94, 0x70, 0xff, 0x5c, 0xc2, 0x1d, 0x0b, - 0x39, 0x36, 0x84, 0x0e, 0x61, 0xe2, 0x1c, 0x63, 0x74, 0xe0, 0x30, 0x01, - 0xbe, 0x39, 0x0f, 0x6f, 0xe6, 0x29, 0xad, 0xd8, 0x8c, 0xdd, 0x8b, 0x24, - 0x38, 0x6f, 0x67, 0x8a, 0x2d, 0x82, 0x1e, 0x8e, 0x45, 0xcb, 0xec, 0x2d, - 0xe3, 0xb4, 0x03, 0x8e, 0x46, 0x2e, 0x01, 0xb0, 0xca, 0x4f, 0xe0, 0x2c, - 0x52, 0xd3, 0x4c, 0xdd, 0xd6, 0x62, 0xf3, 0x38, 0x3f, 0x3c, 0xc1, 0x58, - 0xaa, 0x87, 0x3d, 0x4f, 0xb2, 0xb1, 0x54, 0x65, 0xdc, 0x1c, 0xc8, 0x16, - 0x88, 0x15, 0x53, 0xb0, 0x4e, 0x77, 0xae, 0xe0, 0x34, 0x18, 0x36, 0x34, - 0x31, 0x74, 0x4c, 0x79, 0x0f, 0x2b, 0x1a, 0x11, 0x06, 0x06, 0xaa, 0x60, - 0x31, 0x6e, 0x65, 0x9e, 0x1b, 0xb0, 0x61, 0xd6, 0x90, 0xd1, 0x1d, 0x4c, - 0x36, 0xfe, 0xec, 0x26, 0xcc, 0xba, 0xce, 0xd7, 0xe7, 0x0c, 0x53, 0x90, - 0xe8, 0xce, 0xce, 0xed, 0x58, 0x37, 0x37, 0x3f, 0x40, 0x39, 0xeb, 0x8c, - 0xfb, 0x7d, 0x93, 0xa2, 0x26, 0x4e, 0xbf, 0x49, 0xe7, 0x95, 0xc0, 0x12, - 0x6a, 0xec, 0xfb, 0xbe, 0x00, 0x62, 0xb9, 0xc9, 0x0d, 0x5a, 0x37, 0xf9, - 0xae, 0x84, 0x95, 0x89, 0x20, 0x47, 0x48, 0xf6, 0xf8, 0x73, 0x92, 0x5f, - 0xe1, 0x4a, 0xb4, 0x9e, 0xd8, 0x75, 0xf3, 0x38, 0x48, 0xe1, 0x29, 0x95, - 0x0d, 0x74, 0x6b, 0x98, 0x96, 0x6e, 0xc9, 0x3f, 0xfc, 0x44, 0x91, 0x4d, - 0xf4, 0x4c, 0xb7, 0x38, 0xd7, 0xec, 0xbf, 0xf6, 0x78, 0x05, 0x7d, 0x1b, - 0xe5, 0x68, 0x8a, 0xbc, 0x6a, 0x6a, 0x29, 0xb6, 0xc6, 0x9a, 0x8d, 0x7a, - 0x0e, 0x00, 0x80, 0x73, 0xf5, 0x88, 0x5d, 0x2a, 0xa2, 0x60, 0x98, 0x1e, - 0xf5, 0x06, 0x3b, 0xef, 0xa9, 0x46, 0x6b, 0x89, 0x24, 0xb0, 0xf4, 0x34, - 0x42, 0x15, 0x87, 0xd3, 0xc9, 0x36, 0xe0, 0x52, 0x5f, 0x57, 0x8e, 0x65, - 0x5c, 0x7f, 0x7c, 0xf2, 0x66, 0xd8, 0xd1, 0xbf, 0x13, 0x95, 0x65, 0xb0, - 0x7a, 0xa0, 0xbb, 0xee, 0xc9, 0x20, 0xff, 0x26, 0xda, 0xa0, 0x61, 0x65, - 0xd5, 0x3c, 0xdf, 0xb5, 0xf0, 0xd2, 0x02, 0x4f, 0x97, 0x65, 0x48, 0x63, - 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, - 0x64, 0x64, 0x6b, 0x75, 0x8a, 0x11, 0x01, 0x23, 0x00, 0x07, 0x07, 0x09, - 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, - 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, - 0x08, 0x09, 0x92, 0x1a, 0x33, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, - 0xf6, 0xba, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, 0xf6, 0xba, 0xb1, 0x0a, - 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, 0xc7, 0x2e, 0xdb, 0x0f, - 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, - 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, - 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, - 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, - 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x12, 0x83, 0x28, 0x8c, 0xcd, 0x78, 0x8c, 0x1b, 0x02, - 0xa2, 0x38, 0xa7, 0x25, 0xc1, 0x25, 0x59, 0xcd, 0x36, 0xb2, 0x21, 0xa1, - 0x91, 0xd0, 0xc3, 0x54, 0x89, 0x64, 0xa8, 0x3d, 0x07, 0xcb, 0x8f, 0xf7, - 0xa6, 0x55, 0xc2, 0x96, 0xf6, 0x35, 0xc1, 0x67, 0xdf, 0x2f, 0x1f, 0xda, - 0xa8, 0xf8, 0x8c, 0xc9, 0xa7, 0x5e, 0x7f, 0x1f, 0xa8, 0xd3, 0x38, 0x57, - 0xa2, 0xf4, 0x57, 0x32, 0x17, 0xe3, 0x06, 0xe3, 0xb6, 0x56, 0x60, 0x6e, - 0xbe, 0x12, 0x60, 0x00, 0xfd, 0xa8, 0x4c, 0x3f, 0x2b, 0x54, 0x9c, 0xfb, - 0x87, 0x8b, 0xfa, 0x9e, 0xb8, 0xb2, 0x80, 0x36, 0xf1, 0x5b, 0xcd, 0x9d, - 0x74, 0xa1, 0x7b, 0xbf, 0xf6, 0x4c, 0x64, 0x58, 0x67, 0x8b, 0x68, 0x05, - 0x15, 0x7e, 0x4b, 0x54, 0xe9, 0x84, 0x59, 0x70, 0x42, 0x80, 0x67, 0x6c, - 0x45, 0x62, 0x12, 0x03, 0x27, 0x2b, 0x32, 0xdc, 0x78, 0x85, 0x3d, 0x74, - 0x28, 0x89, 0x5c, 0x33, 0x15, 0x79, 0x63, 0x1f, 0xd7, 0x26, 0xbf, 0x5d, - 0xf6, 0xb1, 0xb7, 0x9e, 0x37, 0x86, 0xd8, 0xf6, 0xf9, 0xc3, 0x66, 0x90, - 0x50, 0x5a, 0x0e, 0xeb, 0xcc, 0xe0, 0xf2, 0x19, 0xbb, 0xd7, 0x6a, 0xe4, - 0xea, 0x87, 0xf9, 0x17, 0x20, 0x88, 0xf6, 0xc0, 0xc7, 0xb7, 0x55, 0x25, - 0xef, 0x15, 0xec, 0xc5, 0x80, 0x52, 0x9a, 0x92, 0xdb, 0x32, 0xf3, 0xc2, - 0xa2, 0x55, 0xd6, 0xd9, 0x5b, 0xe6, 0xb1, 0x95, 0x18, 0x2b, 0xf8, 0x94, - 0x21, 0x56, 0x29, 0x30, 0xf3, 0x61, 0x39, 0x22, 0x03, 0x86, 0xce, 0x81, - 0x6d, 0x9e, 0xdb, 0x5b, 0x49, 0xdb, 0x2c, 0x1d, 0x0d, 0x45, 0xa9, 0xb3, - 0x1c, 0x1a, 0x43, 0x36, 0x1d, 0xd2, 0x76, 0x28, 0x27, 0xe0, 0xd3, 0x19, - 0x56, 0xd3, 0x52, 0xb2, 0xa0, 0x9c, 0xda, 0xb7, 0xac, 0x4d, 0xb1, 0x98, - 0x22, 0xa5, 0x86, 0x5d, 0x79, 0x6a, 0x69, 0x06, 0xd7, 0x07, 0xe7, 0x44, - 0x55, 0x6c, 0xc7, 0xd0, 0x8a, 0x2b, 0xa1, 0x45, 0xc6, 0xbf, 0xf3, 0x21, - 0x2e, 0x41, 0x5c, 0x84, 0xa2, 0x77, 0x46, 0x65, 0x80, 0x75, 0xba, 0x49, - 0xd6, 0xd7, 0x73, 0xeb, 0x35, 0x2c, 0x46, 0x58, 0xc4, 0x1d, 0x2f, 0x6b, - 0xe6, 0x6c, 0xa7, 0x5f, 0x95, 0x0c, 0xbc, 0x60, 0x00, 0x3d, 0xa9, 0x0a, - 0xd6, 0x0a, 0x66, 0x59, 0xc0, 0x9b, 0x49, 0x5b, 0x4c, 0x73, 0xf5, 0x9e, - 0x6d, 0x38, 0xdd, 0x0f, 0x25, 0xe4, 0x35, 0x84, 0x34, 0x25, 0xfe, 0x71, - 0x35, 0x78, 0xa7, 0x5b, 0xc1, 0x7a, 0xab, 0xd7, 0xeb, 0x2f, 0x54, 0x93, - 0x94, 0x49, 0x8a, 0x1e, 0x04, 0xe6, 0xfc, 0xd7, 0xe3, 0xa2, 0x41, 0x25, - 0x5a, 0xa5, 0x46, 0x59, 0x85, 0xfb, 0x21, 0xc7, 0x02, 0x48, 0x79, 0xd4, - 0xef, 0xc4, 0x03, 0xc2, 0x0a, 0x4b, 0x42, 0x1c, 0x73, 0x35, 0xcd, 0x21, - 0x8b, 0xd5, 0xfc, 0xa3, 0xdc, 0xbb, 0x4b, 0xa3, 0x45, 0x04, 0x73, 0xa1, - 0xdb, 0x3a, 0x97, 0x0e, 0xc7, 0x1c, 0xe2, 0x67, 0x04, 0xd4, 0x49, 0x68, - 0x0e, 0x05, 0xcb, 0x52, 0xd4, 0x37, 0x75, 0xd8, 0x2a, 0x17, 0xd3, 0x7a, - 0x93, 0x96, 0x46, 0xfb, 0x07, 0x6d, 0x3b, 0x92, 0x60, 0xf4, 0x35, 0x94, - 0x3b, 0xbd, 0x2e, 0xf6, 0x0b, 0x18, 0xd5, 0x0d, 0x1b, 0xe1, 0xd3, 0x14, - 0xc1, 0x84, 0xd7, 0x67, 0xd7, 0x96, 0x2d, 0xa9, 0xab, 0x59, 0x70, 0x43, - 0x7b, 0xea, 0x25, 0xa3, 0x05, 0x1c, 0x45, 0xf6, 0x34, 0x51, 0x8e, 0xaf, - 0x46, 0x33, 0x90, 0x68, 0x28, 0x4f, 0x38, 0x5b, 0xbb, 0x69, 0xee, 0xbb, - 0x0a, 0x4c, 0x76, 0x1c, 0x3d, 0xfd, 0xea, 0x1f, 0x77, 0x9e, 0xd4, 0xa1, - 0xeb, 0x74, 0x16, 0x60, 0x20, 0xe9, 0x44, 0xc1, 0x90, 0x2c, 0x7b, 0x77, - 0x6f, 0x70, 0xe3, 0x62, 0x0f, 0xc3, 0x20, 0xf6, 0xce, 0xc3, 0xa6, 0x0e, - 0x9c, 0x6d, 0xa3, 0xa0, 0x21, 0x1c, 0x28, 0x7f, 0x44, 0xd7, 0xa9, 0x87, - 0x62, 0x91, 0x4d, 0x2a, 0x93, 0xe2, 0xc7, 0x94, 0x0c, 0x75, 0x1d, 0xf6, - 0xc7, 0xf8, 0x36, 0x09, 0xa8, 0x23, 0xa3, 0x80, 0x52, 0x2d, 0xe7, 0x0b, - 0x44, 0x5d, 0x4b, 0xf5, 0xdc, 0x57, 0xa3, 0x02, 0x40, 0x89, 0xdc, 0x40, - 0xf7, 0x5c, 0xad, 0xea, 0x5c, 0x1a, 0x59, 0xfc, 0xb8, 0xaf, 0xcb, 0x71, - 0xe0, 0x08, 0xdc, 0x80, 0x08, 0x8a, 0x32, 0x85, 0x46, 0xa9, 0x9a, 0x17, - 0x6b, 0x25, 0x9c, 0xfe, 0x7d, 0x90, 0x22, 0x6e, 0x7b, 0x01, 0x24, 0x17, - 0xf6, 0xa7, 0x70, 0x93, 0x03, 0x60, 0xc2, 0x0d, 0x7b, 0x3b, 0xe8, 0x5b, - 0x02, 0xb0, 0x6d, 0x00, 0x62, 0x97, 0x1b, 0x84, 0x86, 0x27, 0x72, 0x2d, - 0x90, 0xee, 0xdc, 0xb6, 0xb8, 0xa5, 0x58, 0x73, 0x29, 0x9b, 0x06, 0x99, - 0xda, 0x4f, 0x12, 0x0c, 0x74, 0x0a, 0xc1, 0x1b, 0x34, 0x20, 0xfa, 0x6d, - 0x01, 0xd2, 0x1b, 0xf2, 0x0f, 0xe3, 0xfe, 0x34, 0x2d, 0x44, 0x4f, 0xa3, - 0x6a, 0xab, 0xaa, 0x7e, 0x1c, 0x35, 0xef, 0xfe, 0xa0, 0xc1, 0x8a, 0xeb, - 0x77, 0x80, 0xd6, 0x57, 0x20, 0x2e, 0x2b, 0xeb, 0x67, 0xa0, 0x82, 0x86, - 0xc8, 0x0e, 0x70, 0x76, 0x74, 0x52, 0x3e, 0x67, 0x96, 0xf0, 0x48, 0x3f, - 0x9b, 0xdc, 0x5f, 0x36, 0xd9, 0xae, 0x3a, 0xcb, 0x57, 0x5d, 0xe0, 0x7c, - 0x03, 0xa9, 0xe8, 0x88, 0x13, 0x6a, 0x70, 0x94, 0x4b, 0xf5, 0x92, 0x8f, - 0xc0, 0x34, 0x49, 0x3f, 0xf7, 0xe1, 0x59, 0xc4, 0xf2, 0xae, 0x7a, 0x88, - 0x58, 0x39, 0x74, 0x39, 0x6d, 0xaf, 0x7a, 0xec, 0xaf, 0x44, 0x0e, 0x11, - 0x7d, 0xa8, 0x3c, 0x50, 0x5b, 0x64, 0x8d, 0x8a, 0x21, 0x59, 0xc6, 0x8c, - 0x6c, 0xce, 0x05, 0xad, 0x1c, 0x2f, 0x5e, 0x4a, 0xa3, 0x2a, 0x46, 0x3a, - 0xaa, 0x12, 0x7e, 0xcc, 0x82, 0xb6, 0x62, 0xba, 0xe6, 0x1a, 0x52, 0xc6, - 0xe3, 0x96, 0x71, 0xf6, 0x81, 0x21, 0x46, 0xd0, 0x3f, 0x5d, 0xa1, 0x37, - 0x8b, 0xf5, 0xc7, 0x8c, 0x28, 0xf0, 0x2e, 0xe8, 0x44, 0x25, 0x48, 0x27, - 0x8e, 0x2f, 0x65, 0x83, 0xed, 0xf5, 0xb6, 0x9f, 0x02, 0xa7, 0x1b, 0x1e, - 0x90, 0x01, 0x55, 0x88, 0xe5, 0xdf, 0x0e, 0x7e, 0x16, 0x66, 0xa1, 0xc6, - 0x07, 0xf6, 0xb5, 0x84, 0x8d, 0x60, 0x6b, 0xe2, 0xad, 0xbd, 0x18, 0x39, - 0xe5, 0xd2, 0xd9, 0xe0, 0xab, 0xc2, 0xac, 0x2f, 0x36, 0x24, 0x03, 0x69, - 0x4c, 0xf9, 0xf3, 0x67, 0x8f, 0xf6, 0x8b, 0xde, 0xf9, 0x7c, 0x14, 0xfa, - 0x97, 0xc3, 0xe5, 0xc1, 0x7d, 0xcf, 0x16, 0x24, 0x26, 0xda, 0xde, 0x5c, - 0x70, 0x96, 0x90, 0xd9, 0x06, 0x2f, 0xf9, 0x61, 0xa3, 0x47, 0x19, 0x50, - 0x5e, 0xe2, 0xb6, 0x74, 0x5e, 0x55, 0xe6, 0x89, 0xaa, 0xde, 0x19, 0x27, - 0x26, 0x47, 0x95, 0x7b, 0xf0, 0x09, 0x21, 0xa9, 0xf3, 0xf2, 0xf0, 0xbc, - 0x1a, 0xa2, 0x25, 0x77, 0x3f, 0x8a, 0x57, 0x20, 0xfc, 0x48, 0x45, 0xd8, - 0x8b, 0xcb, 0x33, 0x04, 0x10, 0x1d, 0xc6, 0x4b, 0x4c, 0xe4, 0x92, 0x1f, - 0xef, 0x27, 0x5e, 0xd5, 0xac, 0xab, 0xcc, 0x69, 0xbe, 0xd6, 0x35, 0x0e, - 0x0d, 0x96, 0x99, 0x3b, 0x67, 0x8d, 0x33, 0xa0, 0xe3, 0x16, 0xcc, 0x4a, - 0x29, 0x80, 0xc8, 0x47, 0xd1, 0x0c, 0xb1, 0xa0, 0xc1, 0xbe, 0xcc, 0x16, - 0xab, 0xf7, 0xee, 0x8a, 0x77, 0xef, 0xca, 0x08, 0x82, 0x0a, 0x9e, 0x11, - 0xcf, 0x3c, 0xbb, 0x1b, 0x44, 0x96, 0xd1, 0x5e, 0x65, 0xf9, 0xe7, 0xc7, - 0xa1, 0x94, 0x42, 0xa9, 0x0e, 0x36, 0x9a, 0x5b, 0x7f, 0xf0, 0x91, 0x95, - 0xeb, 0xd1, 0xb6, 0x1d, 0x18, 0x44, 0x93, 0xa4, 0xc1, 0x31, 0x97, 0x07, - 0x09, 0x9b, 0x50, 0xae, 0xf3, 0x74, 0x7f, 0xbe, 0x0d, 0xc2, 0xc3, 0x11, - 0x8f, 0xa1, 0xea, 0x1f, 0x4e, 0x84, 0x94, 0x18, 0x7e, 0x7c, 0xbd, 0xe6, - 0xc9, 0x78, 0x0e, 0x39, 0x1e, 0x1a, 0x71, 0xc4, 0xbc, 0x5c, 0x99, 0x76, - 0xf7, 0x26, 0x66, 0x9c, 0x8f, 0xd4, 0xad, 0xa9, 0x6e, 0x96, 0xb9, 0x54, - 0x5b, 0xae, 0xa2, 0x0d, 0x94, 0xa8, 0x5a, 0x34, 0xc3, 0xdb, 0x52, 0x59, - 0x3f, 0xdd, 0x53, 0x72, 0xfc, 0xf6, 0x1d, 0x3c, 0xe0, 0x1f, 0x4a, 0xee, - 0xf5, 0x74, 0xa5, 0x95, 0x7a, 0x5d, 0x75, 0xbd, 0x27, 0x4a, 0x49, 0x18, - 0xcf, 0xf0, 0xe5, 0x32, 0x4f, 0x1b, 0xa0, 0xeb, 0x00, 0x19, 0x21, 0xbd, - 0xf7, 0xf5, 0x4b, 0x47, 0x1d, 0x3b, 0x8b, 0xe6, 0xca, 0xdc, 0xb6, 0x52, - 0x41, 0xa7, 0xab, 0x68, 0xb3, 0xfb, 0x8f, 0x40, 0xc3, 0x59, 0xd9, 0x2d, - 0x13, 0x3a, 0x99, 0x93, 0x9f, 0xa6, 0x90, 0xdd, 0x65, 0x17, 0x6c, 0x6f, - 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x64, 0x6b, 0x75, 0x0d, 0x00, 0x00, 0x00, - 0x02, 0x07, 0x57, 0x00, 0x0c, 0xce, 0x07, 0x57, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x8a, 0x74, 0x06, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, - 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, - 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x93, 0x7c, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd8, 0xc4, - 0xac, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd8, 0xc4, 0xac, 0xdb, 0x80, 0x31, - 0x14, 0x76, 0xc0, 0x68, 0x81, 0x87, 0xa3, 0xfd, 0xf3, 0xa2, 0xd6, 0x51, - 0xa9, 0xbf, 0x9e, 0x90, 0x88, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, - 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, - 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, - 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, - 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x08, 0xd8, 0x16, 0x86, 0x7c, 0x84, 0xb6, 0xc0, 0xb3, 0x50, - 0x2d, 0x2a, 0x95, 0x72, 0x8c, 0x1b, 0x64, 0xd9, 0xce, 0xbb, 0x9c, 0xc8, - 0xc6, 0x63, 0x5a, 0xd5, 0x38, 0x7c, 0x27, 0x74, 0xaa, 0x87, 0x88, 0x30, - 0xf3, 0x87, 0x6a, 0x7d, 0x11, 0xc7, 0x6a, 0xf8, 0x5a, 0x6c, 0xd9, 0xaf, - 0xae, 0xb7, 0x3e, 0x35, 0x89, 0x91, 0x11, 0xe7, 0x44, 0x9c, 0xc1, 0xa1, - 0x18, 0x0e, 0x78, 0x20, 0xfe, 0x4a, 0xf9, 0x47, 0x3a, 0xf4, 0x23, 0x28, - 0x3c, 0x45, 0xa2, 0x22, 0xe8, 0x63, 0x71, 0x92, 0xc8, 0xfd, 0x85, 0xf8, - 0x03, 0x28, 0x38, 0xb6, 0x09, 0x66, 0x5b, 0x56, 0xc8, 0xa6, 0x52, 0x03, - 0xea, 0xbf, 0xb5, 0x6f, 0xaf, 0x68, 0xdc, 0xb6, 0x9c, 0xa2, 0x16, 0xa5, - 0x33, 0x1a, 0xb7, 0x13, 0x15, 0x1d, 0x52, 0x29, 0x54, 0x51, 0xc4, 0x3e, - 0xa0, 0x03, 0xf9, 0x73, 0xa9, 0x3e, 0xf6, 0x45, 0xd8, 0xf2, 0x1e, 0xa9, - 0x40, 0x14, 0xc4, 0x5f, 0xbc, 0xce, 0x6f, 0xb5, 0xa2, 0x93, 0x7b, 0xf2, - 0x7c, 0xfa, 0xa5, 0x82, 0x97, 0x64, 0x77, 0x2e, 0x6d, 0x8f, 0x00, 0x71, - 0x64, 0xed, 0xc9, 0x51, 0x61, 0x69, 0x8f, 0x2a, 0xf4, 0x80, 0xd2, 0x24, - 0x6c, 0xc3, 0x53, 0x9f, 0xca, 0x72, 0x9d, 0x22, 0x54, 0x27, 0xd5, 0xba, - 0xae, 0x53, 0xb4, 0x7e, 0xae, 0xa9, 0xe1, 0x48, 0x67, 0xf5, 0x7b, 0xd7, - 0x7e, 0x36, 0x6f, 0xd1, 0xf8, 0x40, 0x8a, 0x9b, 0x07, 0x80, 0x2c, 0x17, - 0x6c, 0x42, 0x2f, 0x7b, 0x8b, 0x98, 0xc4, 0x20, 0xaf, 0x5b, 0x25, 0x73, - 0xb5, 0x5b, 0xa3, 0x4d, 0xe6, 0xeb, 0x66, 0x21, 0x91, 0x9d, 0x85, 0xa3, - 0x8b, 0xfa, 0x40, 0x2d, 0x0b, 0x20, 0x66, 0x47, 0x70, 0x83, 0xe3, 0x02, - 0x0f, 0xc2, 0x56, 0xd6, 0x49, 0x83, 0x3d, 0xad, 0x16, 0x1f, 0x55, 0x33, - 0xcf, 0x79, 0x6d, 0x8d, 0xb1, 0xf7, 0x5d, 0x08, 0x10, 0xd8, 0xe2, 0x0e, - 0xe7, 0xa1, 0x74, 0xdb, 0xef, 0x19, 0xc0, 0xe7, 0xf3, 0xb7, 0x73, 0xf8, - 0x4d, 0x78, 0x98, 0xf0, 0x64, 0xc3, 0xc5, 0x99, 0xb7, 0xf6, 0x07, 0xd4, - 0xae, 0x17, 0xe4, 0xee, 0xd9, 0x35, 0x53, 0xb6, 0x2d, 0xb5, 0xa0, 0xc4, - 0x50, 0x48, 0x3e, 0x16, 0x18, 0xea, 0x20, 0x34, 0x9c, 0xeb, 0xeb, 0xef, - 0xee, 0xb8, 0xf4, 0x32, 0xb1, 0xda, 0x32, 0x35, 0x4e, 0x47, 0x1a, 0x4e, - 0xad, 0x46, 0x53, 0xe6, 0xce, 0x22, 0x7e, 0xe3, 0xf3, 0xbc, 0x34, 0x77, - 0xb0, 0x53, 0x21, 0x81, 0x19, 0x42, 0xb7, 0x1d, 0x0d, 0x81, 0x0f, 0x29, - 0xea, 0x2f, 0x3d, 0xba, 0x40, 0x0c, 0xea, 0x2e, 0xaf, 0x20, 0x88, 0x96, - 0x88, 0xc2, 0xea, 0x3b, 0xec, 0x58, 0x4f, 0x16, 0x66, 0xec, 0x9c, 0xe3, - 0xc8, 0x77, 0x6b, 0xfe, 0xc5, 0xeb, 0x5f, 0xab, 0xbc, 0xc2, 0x6b, 0x03, - 0xdb, 0xbc, 0x0e, 0xd6, 0xd2, 0x8d, 0x3e, 0xd8, 0x63, 0xe7, 0x13, 0xa9, - 0xc3, 0x98, 0xfa, 0xf6, 0xbd, 0xe9, 0x53, 0x33, 0x83, 0x26, 0x2b, 0x78, - 0xa4, 0x91, 0xb5, 0x5b, 0x39, 0xcf, 0x1d, 0x26, 0xc4, 0x05, 0xbe, 0xeb, - 0x8b, 0xa4, 0xee, 0xcd, 0xe0, 0x76, 0xac, 0x41, 0xdf, 0x85, 0x05, 0x60, - 0xe3, 0xc2, 0x5e, 0x57, 0x73, 0x00, 0x48, 0xa2, 0x3f, 0x3c, 0xd2, 0x3c, - 0x78, 0x8e, 0x20, 0xa2, 0xbd, 0xc6, 0xb6, 0x09, 0xdb, 0xdd, 0xf5, 0x39, - 0x8b, 0x5f, 0x2d, 0x13, 0xb9, 0x18, 0x3c, 0x43, 0x55, 0xcc, 0xf6, 0x87, - 0x97, 0xbe, 0x82, 0x03, 0x18, 0xa2, 0xb0, 0xf5, 0x05, 0xec, 0xe3, 0x64, - 0x43, 0x67, 0xef, 0xf7, 0x3c, 0x23, 0xde, 0x2a, 0xa7, 0xff, 0xee, 0xc1, - 0x95, 0x3d, 0xc8, 0x99, 0xea, 0xb7, 0x73, 0x2a, 0x89, 0xc8, 0x1b, 0x2e, - 0x47, 0x25, 0xae, 0x2a, 0x40, 0x77, 0x87, 0x6d, 0xea, 0xa9, 0x71, 0x49, - 0xa0, 0x11, 0xe5, 0x89, 0x0e, 0xd8, 0x01, 0x10, 0xe2, 0x6f, 0xea, 0xb2, - 0xbf, 0x6d, 0x2b, 0x03, 0x92, 0x28, 0x2a, 0xe8, 0x21, 0x70, 0x55, 0x48, - 0xe5, 0x9f, 0xf4, 0xea, 0x37, 0x69, 0x22, 0xb9, 0x3f, 0x48, 0x06, 0xd1, - 0x97, 0x6e, 0x72, 0x13, 0x4b, 0x20, 0xb5, 0x55, 0x64, 0x5c, 0xfc, 0x0b, - 0xec, 0xf9, 0x6f, 0x0d, 0xfa, 0x2d, 0xa4, 0xf9, 0x6a, 0x98, 0x5f, 0xd2, - 0x17, 0x31, 0xbf, 0x86, 0xc4, 0xd8, 0x21, 0x0a, 0x51, 0x62, 0xf1, 0x30, - 0x72, 0xef, 0x39, 0xb5, 0x05, 0x6b, 0xc9, 0x15, 0x1f, 0xbd, 0xb5, 0xfc, - 0xe5, 0x0b, 0x35, 0x13, 0x9b, 0xc5, 0x48, 0x3e, 0xf1, 0x1f, 0x7a, 0x1d, - 0x7f, 0xcb, 0x61, 0xba, 0x58, 0xbb, 0x74, 0xc2, 0x1b, 0xd9, 0xc0, 0x45, - 0x45, 0xe9, 0xbf, 0x3b, 0x56, 0x14, 0x9c, 0xd7, 0xaa, 0xcd, 0x77, 0xc4, - 0x32, 0x6c, 0x7e, 0x5d, 0xc0, 0x1c, 0xde, 0xad, 0xbb, 0xe4, 0x46, 0xca, - 0x6c, 0x13, 0x08, 0x58, 0x07, 0xd6, 0xa7, 0xc5, 0xa1, 0x90, 0xc6, 0x93, - 0x4d, 0xbd, 0xc4, 0xd7, 0x75, 0x02, 0x16, 0x47, 0x38, 0x33, 0x92, 0x11, - 0xb9, 0x6a, 0x85, 0xc4, 0x97, 0x7d, 0xdc, 0x54, 0x31, 0x07, 0xf9, 0xcd, - 0xeb, 0x09, 0x85, 0xae, 0x14, 0x6d, 0x2c, 0xb0, 0xfa, 0xa3, 0x49, 0x26, - 0xb6, 0x98, 0x69, 0xb1, 0x85, 0x52, 0x02, 0x0d, 0x3a, 0x8d, 0x40, 0x3b, - 0x83, 0x05, 0x66, 0x5c, 0xe3, 0xb1, 0x51, 0xe4, 0xc9, 0x59, 0x74, 0x0a, - 0x8a, 0xbb, 0xcb, 0x95, 0xde, 0x81, 0xa4, 0x92, 0x09, 0x63, 0x9d, 0xef, - 0x27, 0xf4, 0xe1, 0x66, 0xf6, 0x4f, 0xe9, 0x6d, 0xce, 0x8d, 0xcb, 0x91, - 0x55, 0xd7, 0xf9, 0xba, 0x49, 0xf2, 0x27, 0x0c, 0x15, 0x68, 0x21, 0x42, - 0x2d, 0x69, 0xe2, 0x0d, 0xee, 0x69, 0x55, 0x68, 0xc3, 0xb5, 0x8d, 0xd7, - 0x37, 0x32, 0xda, 0x6f, 0x78, 0x2b, 0xc8, 0xf9, 0x30, 0x3b, 0xd1, 0xe5, - 0xa5, 0x4c, 0xcb, 0xfe, 0xeb, 0x6f, 0x5d, 0x3c, 0x99, 0xfb, 0x33, 0xc1, - 0x8e, 0xac, 0x48, 0x70, 0x8c, 0x30, 0x85, 0xe1, 0x30, 0x69, 0xde, 0x82, - 0x82, 0x18, 0xe2, 0xc5, 0x6b, 0xb7, 0x1d, 0xdb, 0xce, 0x09, 0x4d, 0x9a, - 0x8e, 0x93, 0x89, 0x46, 0x5f, 0x8c, 0xe9, 0xf5, 0x4c, 0xa1, 0x62, 0xd9, - 0x22, 0x4c, 0xad, 0xbe, 0x77, 0x5c, 0x4f, 0x34, 0xc0, 0x64, 0x23, 0x0d, - 0x9d, 0xed, 0x3e, 0x70, 0x9b, 0x5f, 0x65, 0x84, 0x98, 0x63, 0x1a, 0x0b, - 0xd9, 0x7c, 0xb0, 0x95, 0xee, 0x6a, 0x9a, 0x5c, 0xc3, 0x76, 0x7c, 0x18, - 0x75, 0xba, 0x86, 0xca, 0x43, 0xa5, 0xb5, 0xe1, 0x0b, 0x26, 0xc0, 0xfb, - 0xd6, 0x3a, 0x23, 0x9f, 0xfb, 0xba, 0x68, 0xa3, 0x9b, 0xc0, 0xe5, 0x21, - 0xe3, 0x77, 0x75, 0x84, 0x40, 0x1d, 0x9b, 0xc9, 0xf2, 0x25, 0x6c, 0xba, - 0x6c, 0x8c, 0xb2, 0x2e, 0xec, 0xce, 0x90, 0xb1, 0x4a, 0x90, 0x24, 0xf3, - 0x34, 0x9d, 0xc3, 0x62, 0xb2, 0x11, 0x02, 0xd1, 0xf5, 0x67, 0x95, 0x48, - 0x45, 0x04, 0xe1, 0xd4, 0xb3, 0xdd, 0x1e, 0x00, 0x35, 0x84, 0x7c, 0x41, - 0xea, 0xf9, 0x50, 0xd3, 0x82, 0x14, 0x7d, 0xe7, 0x72, 0xe2, 0xb4, 0x9e, - 0xfc, 0xe7, 0x2e, 0xf7, 0x06, 0xb4, 0x29, 0xfe, 0x7e, 0x72, 0x6a, 0xe1, - 0xde, 0xa8, 0xfa, 0xd9, 0xde, 0xf4, 0xdd, 0xce, 0xff, 0xdb, 0xdc, 0x09, - 0x31, 0x14, 0x1d, 0x09, 0x53, 0xb5, 0x3f, 0x2c, 0x66, 0x74, 0xa8, 0x66, - 0xaa, 0xa2, 0x3d, 0x32, 0x61, 0xed, 0x43, 0xa5, 0x69, 0xf8, 0x6b, 0x0d, - 0x16, 0xe4, 0x67, 0xf5, 0x62, 0xaa, 0x76, 0xac, 0x01, 0x3f, 0x5f, 0x44, - 0x29, 0x34, 0x95, 0x0c, 0x1a, 0x07, 0x96, 0x6b, 0xf4, 0x60, 0x96, 0x5b, - 0xe2, 0x53, 0x2a, 0x87, 0x02, 0xc6, 0xf4, 0x01, 0xf3, 0x7a, 0xdb, 0x82, - 0x5f, 0xc3, 0x85, 0xd4, 0x1a, 0x9b, 0x63, 0xc4, 0x60, 0xb7, 0x82, 0x3c, - 0x9c, 0x70, 0x6f, 0x62, 0x72, 0x10, 0x13, 0xe2, 0xf5, 0x7b, 0x06, 0x41, - 0x48, 0xc7, 0x63, 0xa0, 0xb9, 0xde, 0x56, 0x96, 0x0f, 0x0d, 0x67, 0xd9, - 0x0e, 0x8a, 0x94, 0x3f, 0xca, 0x2f, 0x94, 0x19, 0xff, 0x47, 0xad, 0x59, - 0x3b, 0x9b, 0xb4, 0xc5, 0x4b, 0x51, 0x0d, 0x18, 0x74, 0xc9, 0x53, 0x34, - 0xf0, 0x6c, 0x58, 0x51, 0xbe, 0x4b, 0xfe, 0x24, 0x37, 0xd2, 0x0b, 0x4d, - 0xfa, 0x54, 0xfd, 0x92, 0xc4, 0x25, 0xb3, 0xe8, 0xe2, 0xb5, 0xda, 0xd1, - 0xd1, 0x44, 0x82, 0xb9, 0x2b, 0xb7, 0x03, 0xd9, 0xca, 0x78, 0x71, 0x9c, - 0xc6, 0x8f, 0xb6, 0x59, 0x37, 0xbd, 0x15, 0x02, 0x5e, 0xfb, 0xf5, 0x8c, - 0x7c, 0x46, 0x8e, 0xe2, 0xc8, 0xed, 0xf9, 0x96, 0xdb, 0xa8, 0xbe, 0xe5, - 0x09, 0x70, 0x3f, 0xf4, 0xfb, 0xbf, 0xf4, 0xf5, 0xe1, 0xd4, 0x5e, 0xda, - 0x60, 0x8f, 0x9d, 0xff, 0x94, 0x00, 0xa2, 0xe6, 0x40, 0xd2, 0x47, 0xdb, - 0x2d, 0x0e, 0x82, 0x7c, 0x7f, 0xab, 0x94, 0x2b, 0xc2, 0x6b, 0x46, 0x4d, - 0x55, 0x44, 0x7b, 0xb9, 0x2e, 0x68, 0x89, 0xbb, 0xc0, 0x69, 0x44, 0x77, - 0xa1, 0x41, 0xf8, 0x3b, 0x3f, 0xe5, 0xfb, 0x3c, 0x12, 0x0f, 0x59, 0x78, - 0x6a, 0x52, 0x6e, 0xe1, 0x2a, 0xf7, 0xab, 0xcd, 0xc8, 0xb2, 0x5d, 0x8d, - 0x1c, 0xf6, 0x24, 0xae, 0xb3, 0xda, 0x8a, 0xa7, 0x75, 0x3b, 0x58, 0x77, - 0x08, 0x72, 0xa9, 0x06, 0x0c, 0x7e, 0x4d, 0xad, 0x52, 0x42, 0xc5, 0x9d, - 0x32, 0x10, 0x49, 0xbb, 0xe1, 0x32, 0xc6, 0xb6, 0x2a, 0x68, 0xd3, 0x8d, - 0xba, 0x9e, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x86, 0x2f, - 0x05, 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, - 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, - 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x8a, 0x72, 0x17, 0x13, - 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd3, 0xa8, 0x82, 0x41, 0xb7, 0x59, 0x5c, - 0x83, 0xd3, 0xa8, 0x82, 0xdb, 0x80, 0x31, 0x14, 0x76, 0xc0, 0x68, 0x81, - 0x87, 0xa3, 0xfd, 0xf3, 0xa2, 0xd6, 0x51, 0xa9, 0xbf, 0x9e, 0x90, 0x88, - 0xfc, 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, - 0xff, 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, - 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, - 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0xe1, 0x14, - 0x34, 0xc4, 0xb0, 0x8c, 0x51, 0x96, 0xb8, 0x94, 0xef, 0xe7, 0xf0, 0x5b, - 0x0e, 0x91, 0xf7, 0x07, 0x87, 0x90, 0x3f, 0x8d, 0x5f, 0xf6, 0x59, 0x69, - 0x11, 0x87, 0xdb, 0xaa, 0xdb, 0x60, 0x19, 0xe3, 0x42, 0xdd, 0xd2, 0x2e, - 0xbf, 0xc3, 0x0d, 0x32, 0x66, 0x01, 0xb9, 0xde, 0xce, 0xb5, 0x23, 0xa4, - 0x8e, 0x40, 0x6f, 0xe6, 0xa9, 0xea, 0xc6, 0x1e, 0x64, 0xc9, 0x57, 0x83, - 0x42, 0x36, 0x52, 0x9b, 0xa5, 0x29, 0x32, 0x5f, 0xe9, 0xc2, 0xe3, 0x2d, - 0x5b, 0x00, 0x7b, 0x3e, 0xad, 0xd4, 0x78, 0x7f, 0xfa, 0x02, 0x30, 0xb0, - 0x02, 0xfd, 0xd2, 0xbc, 0xa5, 0xe8, 0x0b, 0x4f, 0x96, 0x16, 0x79, 0x43, - 0x1a, 0xc1, 0x6d, 0xb5, 0xcf, 0x11, 0x35, 0x58, 0x61, 0x08, 0x64, 0x23, - 0xa3, 0x07, 0x76, 0xdb, 0x4d, 0x7d, 0x0e, 0xe0, 0x43, 0x7d, 0xc9, 0x3d, - 0x5e, 0xf4, 0x05, 0x0d, 0xb2, 0xbe, 0x23, 0x13, 0x19, 0x5f, 0x2a, 0xe9, - 0x10, 0xe7, 0x69, 0xed, 0x95, 0x7b, 0x66, 0xb3, 0xe5, 0xa5, 0x8b, 0x6f, - 0xe7, 0xa8, 0x2c, 0xab, 0xed, 0xd1, 0x12, 0xcf, 0xfb, 0xc7, 0x9a, 0xa5, - 0xf0, 0xe9, 0x2a, 0x98, 0x38, 0x96, 0x6a, 0xbb, 0x8d, 0xf2, 0xbf, 0x08, - 0x7f, 0xa7, 0x52, 0xd6, 0x12, 0x3b, 0x00, 0x47, 0xfe, 0xf3, 0x35, 0x63, - 0xf8, 0xc0, 0xec, 0xcf, 0x47, 0x72, 0x45, 0x81, 0x77, 0x4f, 0x23, 0x89, - 0x57, 0x15, 0x3c, 0xd7, 0xf9, 0x51, 0x14, 0xbd, 0x2a, 0x3d, 0xf4, 0x3d, - 0x83, 0xc1, 0xd0, 0x58, 0x07, 0x65, 0x5e, 0xe9, 0x23, 0x9a, 0xb9, 0x76, - 0xd1, 0xe1, 0x5f, 0xfd, 0x7c, 0xfe, 0x31, 0xad, 0xcd, 0xd6, 0x03, 0xb9, - 0x37, 0xe0, 0xae, 0x49, 0x85, 0x6b, 0x3c, 0x03, 0x97, 0x29, 0x99, 0x7c, - 0x1d, 0x36, 0x1a, 0xdd, 0xda, 0x47, 0xa1, 0x38, 0x21, 0xfa, 0x91, 0x4a, - 0x8d, 0xe7, 0x26, 0x9d, 0xaa, 0x44, 0xf7, 0x91, 0x25, 0xca, 0xa8, 0x84, - 0x77, 0x58, 0x2a, 0x50, 0xd6, 0xa4, 0xab, 0x69, 0xd3, 0xd4, 0xac, 0x1e, - 0x08, 0xfc, 0xa2, 0xbd, 0xab, 0x27, 0x72, 0xa4, 0x5a, 0x40, 0x76, 0x15, - 0x24, 0x0e, 0x50, 0x5a, 0x6f, 0x5d, 0x00, 0x75, 0x6c, 0x75, 0x75, 0xbb, - 0x13, 0x85, 0x0e, 0xcf, 0x27, 0x28, 0x94, 0x41, 0x64, 0xf0, 0x76, 0x97, - 0xbb, 0x58, 0x20, 0x12, 0x46, 0xa9, 0xf5, 0x23, 0xc2, 0x6b, 0xf6, 0x9b, - 0xd1, 0x20, 0xc5, 0x98, 0xa5, 0xdb, 0x77, 0xd9, 0x2a, 0xe7, 0xd8, 0x06, - 0xfc, 0x5d, 0xca, 0x85, 0xd8, 0x6e, 0x44, 0xf0, 0x4a, 0x32, 0x37, 0x66, - 0xbf, 0xde, 0x0a, 0x4c, 0xd8, 0xd8, 0xeb, 0x96, 0x0f, 0x6a, 0x37, 0x16, - 0x09, 0x63, 0x48, 0x8d, 0x31, 0xe8, 0x7c, 0xa6, 0x5b, 0xf0, 0xd3, 0x51, - 0xad, 0x5b, 0x12, 0xd5, 0x42, 0x86, 0xbd, 0x46, 0x7c, 0x62, 0x9c, 0x92, - 0x10, 0xeb, 0xdd, 0x5f, 0xc4, 0x16, 0xcc, 0x2d, 0xe1, 0xce, 0x42, 0xb0, - 0x80, 0x26, 0xcf, 0x49, 0x11, 0x0e, 0x4b, 0xe3, 0x63, 0xb4, 0x6f, 0x84, - 0x9b, 0x4d, 0xaf, 0x67, 0x56, 0x5f, 0x51, 0xff, 0xc9, 0xbd, 0xd5, 0xe4, - 0x7d, 0x96, 0x2c, 0x64, 0xe8, 0xa2, 0x42, 0x95, 0x2f, 0xf9, 0xb3, 0xa5, - 0x3c, 0xb2, 0x33, 0xa9, 0x4a, 0x03, 0xfe, 0x2c, 0x56, 0x00, 0xaa, 0xc6, - 0x5b, 0xea, 0x89, 0x0e, 0xa7, 0xae, 0xa0, 0x92, 0x7c, 0x04, 0xe5, 0x91, - 0xf4, 0x91, 0x8e, 0x77, 0xc0, 0x74, 0xd9, 0x85, 0xd6, 0x4f, 0x13, 0x11, - 0xc4, 0xd7, 0xeb, 0xd6, 0xfa, 0xbd, 0x70, 0x09, 0xb2, 0xa5, 0x77, 0x8d, - 0xbe, 0x23, 0x0b, 0xb3, 0x4c, 0xd6, 0x2f, 0xd0, 0x37, 0x62, 0x60, 0x88, - 0xd1, 0xbd, 0xec, 0x1c, 0x98, 0xbb, 0xd4, 0x9b, 0xa8, 0x50, 0x1e, 0xa4, - 0xb3, 0xe1, 0x1f, 0xe2, 0x49, 0x5b, 0x09, 0xc8, 0x3c, 0xb4, 0x38, 0xaf, - 0x5c, 0xec, 0xf8, 0x5d, 0xa1, 0xe1, 0xbf, 0xad, 0x5a, 0x33, 0xc8, 0x65, - 0x6a, 0x21, 0x10, 0x94, 0x70, 0x5c, 0x16, 0xd2, 0x5a, 0xfd, 0x52, 0x13, - 0xb8, 0xb7, 0xdb, 0xc2, 0x26, 0x7f, 0x24, 0xb2, 0xc3, 0x19, 0x19, 0x7c, - 0x7c, 0x5e, 0x70, 0x8a, 0x99, 0x74, 0x27, 0x3e, 0x5a, 0xb3, 0x17, 0x10, - 0xd8, 0x8a, 0x3e, 0xc2, 0x7e, 0x99, 0x67, 0x74, 0xe3, 0x65, 0x32, 0x18, - 0x90, 0x66, 0x7f, 0xe1, 0x74, 0x7d, 0xe7, 0xb8, 0xd1, 0xe2, 0xd3, 0x29, - 0xf1, 0xf2, 0x5d, 0xf1, 0x05, 0xca, 0x11, 0x7b, 0xf7, 0x32, 0xdf, 0x68, - 0x37, 0x84, 0xce, 0x00, 0x16, 0x5f, 0x9d, 0x9a, 0x5e, 0x04, 0xe0, 0xb1, - 0xa8, 0x39, 0x08, 0xfe, 0x75, 0xcc, 0x6b, 0x7c, 0x99, 0x28, 0x8d, 0x4c, - 0x50, 0x81, 0x0a, 0x4a, 0xba, 0x72, 0xbe, 0x90, 0x96, 0xcc, 0xac, 0x36, - 0x11, 0x5e, 0x9f, 0xe3, 0xc8, 0x97, 0x8b, 0x86, 0x87, 0x05, 0x68, 0x59, - 0x4d, 0xfa, 0xf7, 0xb8, 0x83, 0x0b, 0x42, 0xbd, 0xba, 0x63, 0x64, 0x3f, - 0xd6, 0xba, 0x66, 0x65, 0xbb, 0x1c, 0x69, 0x5d, 0xab, 0x22, 0x73, 0xd9, - 0xbc, 0x86, 0x0d, 0x06, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x35, 0x1d, 0x3e, 0x1d, 0x24, 0xd4, 0x92, - 0xad, 0x2d, 0xbe, 0xf7, 0x22, 0xa4, 0x69, 0xce, 0x73, 0xef, 0xfc, 0x8d, - 0xfa, 0x05, 0xac, 0xfe, 0xf0, 0xa4, 0xe5, 0xb1, 0x82, 0x82, 0x42, 0xbd, - 0xaf, 0xba, 0xb2, 0x56, 0xf3, 0x3f, 0x14, 0x2c, 0xc6, 0xf5, 0x78, 0xb1, - 0x7f, 0x9e, 0xa5, 0xfb, 0x83, 0x3c, 0x1a, 0xdf, 0x4f, 0x79, 0x59, 0x61, - 0xed, 0xa5, 0x9a, 0x9b, 0x35, 0x8e, 0x10, 0x15, 0xb2, 0x49, 0x4d, 0x07, - 0x88, 0x4f, 0xc6, 0xb2, 0x3e, 0xca, 0x64, 0xae, 0xa3, 0x70, 0x5b, 0x2b, - 0xad, 0x74, 0x05, 0x2b, 0xc7, 0xcb, 0xff, 0x0e, 0x65, 0x85, 0xcc, 0xf3, - 0x4c, 0x85, 0x59, 0xa8, 0x34, 0x86, 0x92, 0xa5, 0xef, 0x3c, 0xdd, 0x52, - 0x13, 0x96, 0x52, 0x18, 0x3b, 0xd2, 0xaf, 0xab, 0x00, 0x17, 0x32, 0x82, - 0x71, 0xee, 0x90, 0x05, 0x81, 0x57, 0x52, 0x4f, 0x24, 0xff, 0xb3, 0xe6, - 0x3b, 0x94, 0xa3, 0x90, 0x7f, 0xd0, 0x26, 0xb0, 0x8b, 0x3e, 0xad, 0x36, - 0x5f, 0xb7, 0x28, 0x67, 0xac, 0xed, 0x35, 0xce, 0x51, 0xee, 0x78, 0xd5, - 0x99, 0x36, 0xea, 0x49, 0x22, 0x60, 0xc0, 0x75, 0x30, 0x7e, 0x96, 0x9d, - 0x60, 0x6e, 0x6a, 0xfb, 0x82, 0xb7, 0xa6, 0x41, 0xdf, 0x0c, 0x36, 0x9d, - 0xd2, 0xf7, 0xb7, 0xd1, 0x89, 0x95, 0x07, 0xac, 0x41, 0xa4, 0x60, 0x0a, - 0x6e, 0x4f, 0x41, 0xc3, 0x26, 0xed, 0xa0, 0x48, 0x91, 0xdd, 0xff, 0xc2, - 0xe9, 0x65, 0x2f, 0x76, 0x53, 0x05, 0xc3, 0x6f, 0x6a, 0x51, 0x27, 0xf8, - 0x55, 0xdf, 0xd7, 0xc3, 0x13, 0x25, 0x2d, 0x6b, 0xf1, 0x99, 0xd2, 0xda, - 0x9a, 0xed, 0x6d, 0x4f, 0xd0, 0x40, 0x73, 0xc2, 0x35, 0xeb, 0x8d, 0xa7, - 0x0f, 0x78, 0xc7, 0x43, 0x04, 0x53, 0x8d, 0x20, 0x6d, 0xb4, 0xd1, 0x18, - 0xf8, 0xd9, 0x5e, 0x92, 0x98, 0x0a, 0xa1, 0x16, 0xe8, 0x9f, 0x5a, 0x2a, - 0x2a, 0x89, 0x50, 0xda, 0xa3, 0xd6, 0xb1, 0xea, 0x50, 0x0c, 0x84, 0x7a, - 0xd9, 0xd8, 0x10, 0x75, 0x9d, 0x04, 0x3e, 0x4a, 0x5a, 0x8d, 0x9f, 0xf4, - 0xf9, 0xc4, 0x11, 0x6b, 0x76, 0x80, 0xf0, 0x56, 0x28, 0x13, 0xe3, 0x05, - 0x6b, 0x78, 0x23, 0x79, 0x88, 0x16, 0x51, 0x0c, 0x9b, 0xde, 0x4e, 0x90, - 0xd0, 0x2c, 0x53, 0x1c, 0x70, 0x41, 0xe7, 0xad, 0x73, 0xa3, 0xed, 0xc2, - 0x91, 0xc2, 0xb3, 0x3e, 0x99, 0xf2, 0x57, 0xf9, 0x7d, 0xc7, 0xc9, 0xe5, - 0x3e, 0xe2, 0x0b, 0x4b, 0xb6, 0xee, 0x29, 0x5b, 0xc9, 0xc5, 0xa6, 0x70, - 0x77, 0xe5, 0xbc, 0x43, 0x9e, 0xa2, 0x01, 0x22, 0x32, 0xb5, 0xdd, 0x1f, - 0x35, 0xd5, 0x3c, 0xdc, 0x7a, 0x4e, 0x85, 0x5f, 0xe2, 0x8f, 0x48, 0x28, - 0x70, 0x46, 0x89, 0x38, 0x5f, 0x72, 0x00, 0x65, 0x96, 0xfd, 0xc4, 0x36, - 0x01, 0xd6, 0x64, 0x70, 0xcc, 0xda, 0xd0, 0xc1, 0xee, 0x5b, 0x5a, 0xde, - 0x27, 0x1e, 0x35, 0xda, 0xae, 0x3c, 0xaf, 0xd3, 0x1c, 0x1a, 0x57, 0x24, - 0x0a, 0xf0, 0x79, 0xf0, 0xc1, 0xd7, 0x04, 0xcb, 0x21, 0xb2, 0xf4, 0x1e, - 0x1a, 0xa8, 0xc7, 0x89, 0xca, 0x1e, 0x68, 0x55, 0x71, 0x96, 0x68, 0x16, - 0x19, 0xb9, 0x9c, 0x96, 0xfa, 0xab, 0x34, 0xbb, 0xe0, 0x21, 0xb1, 0xae, - 0xb5, 0x8d, 0xf2, 0xd6, 0xce, 0x69, 0xc4, 0x58, 0x3f, 0x3c, 0xec, 0x28, - 0xcd, 0x9f, 0xfa, 0x97, 0xb3, 0xb0, 0xa4, 0x80, 0x7b, 0x07, 0x51, 0x0b, - 0x01, 0x23, 0x09, 0xcc, 0x7d, 0x94, 0x5d, 0xb4, 0xe9, 0x81, 0x5c, 0x3a, - 0x6b, 0xc4, 0x52, 0xc1, 0x86, 0xcc, 0xdf, 0x24, 0xcb, 0x3e, 0xbe, 0xc7, - 0xeb, 0xd7, 0xe0, 0x3a, 0xfc, 0xa1, 0x4d, 0x17, 0x8b, 0x41, 0x82, 0xeb, - 0x79, 0x2b, 0x87, 0x4d, 0xea, 0x27, 0xfb, 0x9e, 0x03, 0x75, 0xfc, 0x29, - 0x05, 0x4e, 0x76, 0xf3, 0x0f, 0x6d, 0xf2, 0x0f, 0xf6, 0x33, 0x58, 0x58, - 0xce, 0x67, 0xe7, 0x18, 0x97, 0x3a, 0x21, 0x4c, 0xaf, 0x64, 0x55, 0xd9, - 0x84, 0x53, 0xfd, 0x8b, 0x84, 0xad, 0x1a, 0xa5, 0x1c, 0x22, 0xac, 0xa5, - 0x21, 0xfb, 0xa2, 0x26, 0x69, 0x85, 0x24, 0xa3, 0x50, 0x24, 0x62, 0xe2, - 0xf8, 0x6c, 0x45, 0x97, 0xf6, 0xca, 0xe3, 0xbb, 0xb3, 0x02, 0x73, 0x7d, - 0x8b, 0x86, 0x69, 0xe6, 0x3a, 0x0c, 0x38, 0xa1, 0x85, 0xf5, 0xc8, 0xe6, - 0xbf, 0xce, 0x67, 0xeb, 0x68, 0xea, 0xe1, 0x05, 0x28, 0x48, 0xa6, 0xd5, - 0x2a, 0x35, 0xb5, 0x81, 0xaf, 0x3c, 0x47, 0xbb, 0x10, 0x4a, 0xc1, 0x29, - 0x9b, 0xa3, 0x16, 0x2b, 0x34, 0x18, 0x44, 0x2a, 0x1d, 0x43, 0x57, 0x1b, - 0x14, 0xea, 0x25, 0xbf, 0x1c, 0x95, 0x3e, 0x1e, 0x0d, 0x65, 0x50, 0x5a, - 0xe1, 0xd7, 0x14, 0x3f, 0xbb, 0xe2, 0xdd, 0x6f, 0x53, 0x5f, 0xd3, 0xc2, - 0x68, 0xa6, 0x14, 0xb2, 0x70, 0x36, 0x60, 0x99, 0x9d, 0x12, 0x9f, 0xee, - 0xcd, 0x99, 0x50, 0xbd, 0x41, 0x6f, 0x1b, 0xd4, 0x0d, 0x3b, 0xde, 0x00, - 0x20, 0xfd, 0x4c, 0x49, 0x80, 0x2e, 0x99, 0x4e, 0x23, 0xa8, 0x50, 0x14, - 0x42, 0x80, 0xb1, 0x4b, 0xe1, 0x97, 0x01, 0x1f, 0x8f, 0xf8, 0x05, 0x15, - 0xe6, 0x0e, 0x92, 0xdb, 0x10, 0xa2, 0x24, 0xf7, 0x4f, 0xc2, 0xf2, 0xe5, - 0xd8, 0xbc, 0xcc, 0x43, 0x10, 0xa0, 0x94, 0xff, 0x75, 0xee, 0xc2, 0x35, - 0x62, 0x2d, 0x9c, 0xe1, 0xd0, 0x0c, 0x02, 0x5b, 0xf0, 0x78, 0x32, 0xfe, - 0xf2, 0xf8, 0xdf, 0xd6, 0x7a, 0xdc, 0xc5, 0x82, 0xcd, 0xd4, 0x46, 0xd4, - 0x80, 0x99, 0xd6, 0x68, 0xb0, 0x60, 0xb2, 0x27, 0xdf, 0xbb, 0x41, 0x7f, - 0x49, 0x53, 0x93, 0x25, 0x05, 0x9a, 0xce, 0xc0, 0xd6, 0xc6, 0x46, 0xff, - 0xd7, 0xaa, 0x2d, 0xfa, 0x6b, 0x45, 0x09, 0xb0, 0xd2, 0x35, 0xfa, 0x8a, - 0xb4, 0xbb, 0xc2, 0x76, 0xe9, 0xd1, 0x91, 0x18, 0xde, 0x65, 0xd7, 0x81, - 0xa5, 0xbd, 0xd8, 0xf9, 0x89, 0xc6, 0x6f, 0xd9, 0xd3, 0xe4, 0x03, 0x4f, - 0x83, 0xf2, 0xd4, 0xd7, 0x41, 0x74, 0x5e, 0xe3, 0xcc, 0x8b, 0xf2, 0x22, - 0xb3, 0x89, 0xbc, 0xd5, 0x42, 0x43, 0x06, 0x76, 0xee, 0x0e, 0x79, 0x05, - 0xbd, 0xb2, 0x1e, 0xf6, 0x76, 0x12, 0x30, 0x2b, 0xd1, 0x9c, 0xe0, 0xd4, - 0xc9, 0x44, 0x09, 0x0a, 0xed, 0xae, 0x16, 0xdc, 0x9a, 0x26, 0xf4, 0xbb, - 0x37, 0xec, 0xc8, 0xa3, 0x7b, 0x12, 0x09, 0xcf, 0x17, 0x5c, 0x17, 0x74, - 0x0a, 0xa7, 0x71, 0x7c, 0xb0, 0x88, 0x15, 0xac, 0x98, 0xea, 0xfb, 0x3d, - 0x73, 0x3b, 0x46, 0xe9, 0xb0, 0x29, 0x73, 0xac, 0xe9, 0xdd, 0x1d, 0x8e, - 0xff, 0x79, 0xb9, 0x87, 0xf6, 0x07, 0x24, 0x49, 0xbf, 0xf6, 0x97, 0x71, - 0xbc, 0x5d, 0x14, 0x3f, 0x0f, 0x81, 0x6f, 0xcb, 0x49, 0x09, 0x51, 0x9e, - 0x4f, 0x24, 0x19, 0x7a, 0x00, 0x22, 0x9a, 0xa0, 0x52, 0xe3, 0x5b, 0x4a, - 0x9d, 0xe5, 0xb0, 0x96, 0xfc, 0x40, 0x15, 0xeb, 0x48, 0x1c, 0x4f, 0x25, - 0x64, 0xe9, 0x79, 0xbf, 0xb5, 0xef, 0x5f, 0xc3, 0x29, 0xbe, 0x7c, 0x6e, - 0x14, 0xe5, 0xe4, 0x36, 0xeb, 0x66, 0x27, 0x07, 0xbc, 0x2d, 0x1c, 0x2e, - 0x71, 0x51, 0x67, 0x60, 0x4d, 0xfc, 0x6c, 0x74, 0x8f, 0xc7, 0x84, 0x3e, - 0xe3, 0x8a, 0xfb, 0x34, 0xe3, 0x8e, 0x84, 0x5c, 0xdd, 0xc9, 0x0c, 0x3a, - 0xf4, 0x8c, 0xac, 0x40, 0xb0, 0x6b, 0x08, 0xe7, 0x4e, 0xa3, 0x92, 0xe3, - 0x57, 0xfc, 0x25, 0x08, 0x82, 0xd5, 0xf6, 0x35, 0x35, 0x41, 0x6a, 0xd9, - 0xf6, 0x78, 0x81, 0xca, 0x81, 0xe7, 0x5b, 0x58, 0x15, 0x5c, 0x57, 0x6e, - 0x5e, 0xe1, 0x65, 0xe5, 0xfc, 0xb1, 0xe9, 0x1a, 0x97, 0x9d, 0x86, 0xb9, - 0xb1, 0xa1, 0xb0, 0xbd, 0x3e, 0xb8, 0x0d, 0xc6, 0x33, 0x7e, 0xb5, 0x47, - 0xcc, 0x0a, 0x29, 0xcb, 0xf9, 0xaa, 0xff, 0x14, 0x33, 0x01, 0xd0, 0x3d, - 0x12, 0xb6, 0xc9, 0x33, 0x5d, 0xa8, 0x99, 0x30, 0x38, 0x38, 0xe3, 0x35, - 0x5a, 0x36, 0xf9, 0xca, 0xaf, 0x1d, 0xfe, 0x8c, 0x6a, 0xb7, 0xce, 0x67, - 0x0c, 0x6d, 0xc2, 0x29, 0xcd, 0x9e, 0x32, 0x46, 0xe8, 0xf4, 0x23, 0xa3, - 0xf3, 0xff, 0xf5, 0x74, 0xa6, 0xeb, 0xbd, 0xc3, 0x3e, 0xe2, 0x14, 0xd9, - 0xa5, 0xe8, 0x0e, 0xf6, 0x6f, 0xbd, 0xc3, 0x08, 0x56, 0x0a, 0xf0, 0x8a, - 0x14, 0xa1, 0xd6, 0x2d, 0xaf, 0xf7, 0x03, 0xff, 0xdc, 0x1c, 0x85, 0xdb, - 0xc9, 0x10, 0x33, 0xa2, 0x8d, 0x46, 0x69, 0x51, 0x70, 0x59, 0xc9, 0x4d, - 0x38, 0xb2, 0x69, 0x0e, 0xa8, 0xf4, 0xef, 0xdf, 0xb6, 0x34, 0xcf, 0x3d, - 0xec, 0xe8, 0x37, 0xea, 0xb3, 0x8e, 0x70, 0xb6, 0xf8, 0x5a, 0xa5, 0x13, - 0xde, 0x4c, 0x18, 0x6d, 0x04, 0xc5, 0xfd, 0xa4, 0x28, 0x15, 0x1b, 0x49, - 0xb3, 0x39, 0xfe, 0x9b, 0x54, 0xc1, 0x1e, 0x7f, 0x86, 0xe8, 0x3c, 0xe7, - 0xd5, 0x55, 0xa8, 0x89, 0xe1, 0xf4, 0xb5, 0x94, 0x0b, 0xff, 0xa8, 0xc2, - 0x56, 0xaa, 0xba, 0x6d, 0xb9, 0xc7, 0x54, 0xea, 0xbb, 0x1a, 0x17, 0x2a, - 0x3e, 0xae, 0x10, 0x2b, 0x89, 0xa8, 0x5d, 0xb1, 0x13, 0x46, 0xb1, 0x1c, - 0x6c, 0x7c, 0x58, 0x27, 0xc6, 0xf8, 0xfb, 0x9b, 0xca, 0x6b, 0x12, 0xd4, - 0x14, 0xbf, 0x3b, 0xb8, 0xea, 0xa7, 0xfa, 0x76, 0x55, 0x16, 0x0b, 0x2c, - 0xbb, 0x94, 0xd1, 0x12, 0x47, 0x0f, 0x3f, 0x89, 0xf4, 0xc2, 0xc3, 0x8d, - 0x03, 0x11, 0x0c, 0xe8, 0xe3, 0x96, 0x8f, 0x89, 0x25, 0x90, 0xa5, 0xe1, - 0xf4, 0x20, 0xf4, 0xfc, 0x24, 0xfe, 0xf0, 0x28, 0x11, 0x2a, 0x74, 0x10, - 0x9e, 0x20, 0x79, 0x11, 0xd4, 0x8b, 0x4b, 0x26, 0x75, 0x4f, 0x82, 0xd8, - 0x17, 0x64, 0xdf, 0x21, 0x73, 0x85, 0xa7, 0x57, 0x35, 0x8d, 0x67, 0x37, - 0x4a, 0x9a, 0xfe, 0x87, 0xa7, 0x45, 0x87, 0x51, 0xf3, 0x19, 0x3b, 0x1a, - 0xd4, 0x39, 0x37, 0x45, 0x99, 0xe9, 0x71, 0x96, 0x8b, 0x3e, 0xd8, 0xa6, - 0x8e, 0xc7, 0xf5, 0x62, 0x14, 0x1c, 0x8c, 0x4c, 0xfa, 0x60, 0x48, 0x35, - 0xb1, 0xba, 0xcd, 0xf5, 0xba, 0xf5, 0x67, 0xb6, 0xa2, 0x38, 0xf9, 0xd2, - 0xa3, 0xde, 0xbc, 0xfb, 0x58, 0xb2, 0xd2, 0x3d, 0x10, 0x63, 0x12, 0xed, - 0x23, 0xfd, 0xab, 0x65, 0x18, 0x6d, 0x94, 0x61, 0x06, 0xaa, 0x0b, 0xcc, - 0x3c, 0xd2, 0x91, 0xc9, 0x1b, 0x1e, 0x66, 0x38, 0x26, 0x0b, 0x0a, 0xb8, - 0x15, 0x88, 0xaf, 0x93, 0x03, 0x41, 0x2f, 0x0c, 0x2b, 0x68, 0x94, 0x1f, - 0xa7, 0x8d, 0xed, 0x3d, 0xa1, 0xca, 0x53, 0x93, 0xf8, 0x81, 0x95, 0x07, - 0xc5, 0x92, 0xf0, 0xa4, 0x74, 0x76, 0x1b, 0x14, 0x6e, 0xe6, 0x2f, 0x71, - 0x43, 0x8e, 0x79, 0x4c, 0x91, 0x71, 0xd7, 0x1e, 0x63, 0x94, 0xbd, 0xba, - 0x40, 0xb2, 0x86, 0x95, 0x90, 0x8c, 0xad, 0x22, 0x65, 0xfa, 0x65, 0x4c, - 0x65, 0xc4, 0x78, 0x7c, 0xef, 0x7a, 0x46, 0x25, 0xad, 0xac, 0xfc, 0x9c, - 0x6f, 0x24, 0xdf, 0xe4, 0xfe, 0x5f, 0x67, 0x31, 0x4e, 0xb9, 0x2a, 0xdb, - 0xfd, 0xfc, 0x9b, 0x99, 0xe4, 0xc3, 0x7b, 0x61, 0x04, 0x76, 0x0f, 0x4d, - 0x21, 0xcb, 0x27, 0xd9, 0x6d, 0x62, 0x42, 0x4f, 0x6c, 0xd8, 0x0a, 0xbc, - 0xa9, 0xbb, 0xc6, 0x61, 0x4b, 0xc3, 0xec, 0x82, 0x8b, 0xcc, 0x7b, 0x55, - 0xdd, 0xaa, 0xc1, 0x9e, 0x93, 0xd8, 0x77, 0xae, 0x34, 0x83, 0xbc, 0x90, - 0x85, 0x73, 0x4f, 0xba, 0x55, 0xa6, 0x66, 0x31, 0xe3, 0x8b, 0x11, 0x6b, - 0xce, 0xdf, 0x6a, 0xa3, 0x6e, 0xca, 0xe5, 0x65, 0x77, 0xd6, 0x08, 0x22, - 0x20, 0x20, 0x44, 0x04, 0xc7, 0x2a, 0x46, 0x4f, 0x17, 0xc7, 0xf6, 0x6f, - 0x45, 0x6a, 0xd3, 0xfc, 0xce, 0xa0, 0x9c, 0x43, 0xe3, 0x68, 0x83, 0x9b, - 0x70, 0x7f, 0x74, 0x1e, 0x8f, 0x9b, 0x61, 0x2d, 0x7f, 0x1f, 0x45, 0xd1, - 0xef, 0x92, 0xfb, 0x5f, 0xfa, 0x7a, 0x7f, 0x20, 0x0d, 0x86, 0xc6, 0x6f, - 0x5d, 0x8a, 0x0a, 0xd2, 0xb7, 0xe6, 0x82, 0xc9, 0x66, 0xb7, 0x54, 0x20, - 0x80, 0x19, 0xc9, 0x09, 0x10, 0x7e, 0x81, 0x92, 0x93, 0xab, 0x4e, 0xc9, - 0x49, 0x2d, 0xf4, 0xef, 0x5d, 0x08, 0x37, 0x6e, 0x0c, 0xfa, 0xfc, 0xd3, - 0xe0, 0xc4, 0x43, 0x04, 0x15, 0x47, 0x51, 0x9b, 0xc3, 0x9b, 0x6b, 0x80, - 0x03, 0xc6, 0x8b, 0x9a, 0x0d, 0x3c, 0xf1, 0x49, 0x0b, 0xd6, 0x39, 0x36, - 0x42, 0xd4, 0x81, 0xb2, 0x63, 0xe0, 0xa0, 0x8a, 0x34, 0xc0, 0x8a, 0xd0, - 0x67, 0xed, 0x3f, 0xed, 0x5f, 0x46, 0xa6, 0x04, 0x6b, 0x07, 0x81, 0xaa, - 0xc6, 0xc5, 0x0f, 0x17, 0x82, 0x28, 0xe9, 0xc7, 0xcd, 0xe5, 0xfc, 0xc3, - 0xb6, 0x45, 0xce, 0xe9, 0xd5, 0xe6, 0xe1, 0xc3, 0x92, 0x88, 0xe3, 0x22, - 0x3d, 0x63, 0x99, 0x47, 0x00, 0x3c, 0x21, 0x71, 0x02, 0x84, 0xd5, 0xb0, - 0x05, 0x9d, 0x19, 0x71, 0x5c, 0x9c, 0xea, 0x21, 0x64, 0x59, 0x0c, 0xa2, - 0x33, 0xdd, 0xcb, 0xcc, 0x5d, 0xcf, 0xd3, 0xc5, 0xc5, 0x38, 0xfc, 0xe1, - 0x9d, 0xd7, 0xff, 0xe4, 0x13, 0x76, 0x9d, 0xe7, 0xa5, 0xa1, 0x76, 0xc5, - 0xd3, 0xa6, 0xfa, 0x62, 0x5e, 0xb0, 0xf9, 0x8c, 0x1d, 0x8a, 0x75, 0x7f, - 0xef, 0x5b, 0x73, 0x76, 0xb6, 0x0a, 0x0e, 0xca, 0x34, 0x77, 0x7c, 0x42, - 0xcb, 0xe3, 0x62, 0x34, 0xda, 0xf2, 0x5a, 0x83, 0x37, 0xdd, 0xba, 0x06, - 0x4c, 0xa6, 0xf2, 0x80, 0x87, 0xfe, 0x61, 0x0b, 0xa3, 0x27, 0x84, 0x28, - 0x80, 0x81, 0x9a, 0x07, 0x4f, 0x77, 0xbf, 0x56, 0x7c, 0xe9, 0x24, 0xdc, - 0xa0, 0xe7, 0x1c, 0x0a, 0x32, 0x67, 0x22, 0x64, 0x47, 0x1c, 0x41, 0x06, - 0xac, 0x0a, 0x1f, 0x34, 0xa2, 0x08, 0xd9, 0x94, 0x02, 0x91, 0x79, 0x73, - 0x1e, 0x86, 0xd2, 0x21, 0x71, 0x02, 0x8d, 0xf3, 0xef, 0x9f, 0x17, 0xac, - 0xe2, 0x74, 0xec, 0x11, 0xbb, 0xe4, 0x62, 0xfc, 0x17, 0x38, 0x7d, 0x57, - 0x21, 0x0d, 0x5a, 0x4e, 0x8d, 0xa5, 0x8b, 0xc6, 0x44, 0xd9, 0xfb, 0x42, - 0xd5, 0x0b, 0x18, 0xdd, 0xf1, 0x7d, 0xca, 0x3b, 0x02, 0x00, 0x23, 0x38, - 0xd6, 0xa9, 0xb8, 0x4b, 0x1f, 0x7a, 0xe8, 0x55, 0x4a, 0xb3, 0xaf, 0xf8, - 0x0a, 0x57, 0xe5, 0xd7, 0xff, 0xee, 0x2b, 0xbc, 0xb5, 0x1f, 0xb5, 0xf1, - 0x43, 0xd0, 0x6f, 0xcf, 0xf1, 0x4e, 0x22, 0xe0, 0x01, 0x79, 0xc1, 0xbd, - 0x1e, 0xdb, 0x48, 0xb6, 0x9c, 0x26, 0xc2, 0xa9, 0x91, 0xee, 0x89, 0x1b, - 0xd5, 0x23, 0x08, 0x8c, 0x62, 0xc9, 0x86, 0x3e, 0x33, 0x6a, 0xb9, 0x7f, - 0x63, 0x51, 0x28, 0xab, 0xba, 0x60, 0x2c, 0x12, 0xcf, 0x66, 0x43, 0x38, - 0x0d, 0xc5, 0x3b, 0x2f, 0xf0, 0x70, 0x9c, 0xeb, 0x39, 0xe0, 0x8f, 0xcd, - 0x4c, 0x73, 0x1c, 0x70, 0x01, 0xfa, 0x78, 0xd3, 0x16, 0x1a, 0xae, 0x27, - 0x2d, 0x02, 0xdc, 0xdb, 0xba, 0x4b, 0xed, 0xae, 0x61, 0x1f, 0x55, 0x77, - 0xf5, 0xff, 0x88, 0xdb, 0x8b, 0xfc, 0x18, 0xc4, 0x9b, 0x41, 0xf1, 0x0e, - 0x6f, 0x6e, 0xc6, 0x77, 0x05, 0x8c, 0x6a, 0x7d, 0xbd, 0x69, 0xb8, 0x26, - 0x68, 0xd1, 0x55, 0x93, 0x9b, 0x4c, 0x66, 0xd6, 0xcf, 0xb4, 0x33, 0x5e, - 0x6a, 0xc1, 0x96, 0xca, 0xe6, 0x8b, 0x2d, 0xdf, 0xd6, 0x1d, 0xa6, 0x67, - 0xfc, 0x26, 0x96, 0xfc, 0xfa, 0xcd, 0x65, 0x77, 0x43, 0x44, 0x10, 0x01, - 0x08, 0x93, 0xa6, 0xb2, 0x1a, 0x27, 0x9c, 0x50, 0xde, 0xc0, 0xcf, 0xba, - 0x8d, 0x35, 0x6c, 0x57, 0x5b, 0x0e, 0x11, 0x7c, 0x89, 0x74, 0xca, 0x7e, - 0xf5, 0x08, 0xaf, 0xe4, 0x9f, 0x78, 0x14, 0x8d, 0x2e, 0x1f, 0x47, 0x0a, - 0x18, 0x26, 0xb0, 0x7d, 0xce, 0x36, 0x63, 0x30, 0xa5, 0x63, 0x5e, 0x10, - 0x98, 0xf9, 0xe2, 0x57, 0xe2, 0x0c, 0x17, 0x34, 0xfd, 0x4c, 0x35, 0xe5, - 0x44, 0xbf, 0xf1, 0xa1, 0x9f, 0x07, 0x4c, 0x5f, 0xb1, 0xff, 0x57, 0xd3, - 0xf9, 0xe8, 0xd6, 0x76, 0xae, 0xda, 0xd0, 0xd8, 0x49, 0x44, 0x65, 0x76, - 0xd1, 0xa3, 0x1b, 0xe5, 0x5e, 0x86, 0x12, 0xd2, 0x77, 0x6c, 0x19, 0xfa, - 0x32, 0x9b, 0xe6, 0xf8, 0x6d, 0xc8, 0x87, 0x52, 0xad, 0x80, 0xcd, 0xbd, - 0x83, 0xa7, 0x94, 0x68, 0x39, 0x01, 0x32, 0xa4, 0x91, 0x20, 0xe9, 0xb8, - 0xcc, 0x49, 0x8a, 0xad, 0x9f, 0x59, 0x11, 0x2a, 0x8a, 0x8c, 0xaa, 0x54, - 0x82, 0x58, 0x97, 0xc9, 0x4e, 0x2e, 0x99, 0xa0, 0xc6, 0x29, 0xc3, 0x3b, - 0x61, 0x51, 0xf8, 0x65, 0xa5, 0x76, 0x33, 0xf5, 0xa4, 0x5d, 0x3e, 0x3f, - 0xdc, 0xfc, 0x4d, 0xa9, 0x78, 0x16, 0x29, 0x61, 0x5f, 0x2b, 0x1d, 0x82, - 0x61, 0x8e, 0x5e, 0xb6, 0x10, 0xfc, 0x6c, 0x07, 0x9d, 0xe8, 0x34, 0x5d, - 0xe0, 0xad, 0x81, 0x19, 0x4c, 0x32, 0x9b, 0x1c, 0x5d, 0xae, 0xe6, 0x4e, - 0xaf, 0xba, 0xf3, 0x0d, 0x54, 0x7a, 0x9f, 0x84, 0x5b, 0xc0, 0x6c, 0xba, - 0x21, 0x14, 0x19, 0x57, 0x09, 0x63, 0x48, 0x92, 0xdb, 0x8b, 0x02, 0xff, - 0xf9, 0x3b, 0xd5, 0xe7, 0xa1, 0x97, 0x57, 0x88, 0x95, 0xc9, 0xf7, 0x99, - 0xc8, 0xab, 0x28, 0x6f, 0x89, 0x06, 0xde, 0x54, 0x2e, 0xe5, 0xeb, 0x51, - 0x0f, 0x36, 0xfd, 0xcf, 0x37, 0x43, 0x67, 0x21, 0xd8, 0xeb, 0xa4, 0xeb, - 0x5d, 0xf4, 0x64, 0xd5, 0xb7, 0x1d, 0xf6, 0xea, 0x0a, 0xe9, 0x75, 0x77, - 0xe5, 0x4e, 0xa4, 0x28, 0xdc, 0xc4, 0x09, 0xce, 0xf0, 0x66, 0x8f, 0x8c, - 0xa0, 0x28, 0x81, 0xc5, 0x87, 0x00, 0x61, 0x6b, 0xd3, 0x15, 0x3b, 0x81, - 0x9b, 0x72, 0xc5, 0xfc, 0x04, 0x22, 0x4c, 0x29, 0xfa, 0x42, 0x41, 0x0b, - 0x7c, 0xe5, 0xd9, 0xf6, 0xcd, 0x0d, 0xd5, 0x98, 0x05, 0x3c, 0x5e, 0x4c, - 0x0d, 0x4d, 0x1b, 0x8c, 0x8e, 0xb2, 0x13, 0xa9, 0xf7, 0x46, 0x38, 0xa1, - 0x52, 0x20, 0x67, 0x96, 0xa9, 0x50, 0x33, 0x7f, 0xb3, 0x00, 0x21, 0x3e, - 0x4e, 0x47, 0xd9, 0x9c, 0x53, 0x8d, 0xf7, 0xb6, 0xfa, 0x45, 0x19, 0x57, - 0x56, 0xfa, 0x4e, 0x75, 0x07, 0x9f, 0xe4, 0x5e, 0x13, 0xa9, 0x2b, 0xd7, - 0x70, 0x3b, 0xca, 0x2b, 0xd4, 0x65, 0xb1, 0xbc, 0xb6, 0xc0, 0xbc, 0xfa, - 0x58, 0x3a, 0x09, 0x9e, 0x4e, 0x8c, 0x08, 0xd0, 0x3c, 0xd1, 0xb0, 0x1c, - 0xd2, 0x60, 0xdd, 0x4e, 0xaf, 0xef, 0x62, 0x97, 0x01, 0x80, 0xb8, 0xab, - 0x22, 0x74, 0x2e, 0x0f, 0xd2, 0x34, 0x1b, 0x88, 0x86, 0x9a, 0xa1, 0x5f, - 0xf1, 0x2a, 0x4b, 0x90, 0xd4, 0x1c, 0x68, 0x7a, 0xb0, 0xb8, 0x6a, 0x2c, - 0xeb, 0x80, 0xdf, 0x6d, 0x4c, 0xf6, 0x43, 0x0e, 0x52, 0x91, 0x89, 0x10, - 0x6d, 0x71, 0xec, 0x03, 0xe9, 0x27, 0x2a, 0xa6, 0x31, 0xbb, 0xaa, 0x39, - 0x40, 0xef, 0x97, 0xe3, 0xec, 0x88, 0xb8, 0x47, 0x98, 0x4e, 0xc6, 0xf7, - 0xa3, 0x98, 0x6d, 0xc7, 0x1c, 0x12, 0x55, 0xf2, 0x4f, 0x8e, 0x61, 0xad, - 0x68, 0xb3, 0xf2, 0xf2, 0x1f, 0x20, 0x85, 0xba, 0x9f, 0x8a, 0x7d, 0x91, - 0xe2, 0x3f, 0xf7, 0xa6, 0x7f, 0x3f, 0xee, 0x09, 0x47, 0xf9, 0x7f, 0x68, - 0xcf, 0x83, 0xaf, 0x01, 0xda, 0x33, 0x0b, 0x88, 0xf0, 0xf7, 0xcb, 0x7a, - 0xa5, 0x92, 0x42, 0x0f, 0xd6, 0xc8, 0x25, 0xc1, 0xff, 0x8e, 0x32, 0xc0, - 0xbc, 0x72, 0x92, 0xc9, 0xf4, 0xf5, 0xfa, 0x15, 0x9b, 0x00, 0x46, 0x25, - 0x6e, 0x24, 0xf6, 0x10, 0x95, 0xea, 0x1c, 0xb0, 0x96, 0x0e, 0x8f, 0xb5, - 0x70, 0x68, 0xa7, 0x8f, 0x60, 0x23, 0xc7, 0xeb, 0x26, 0x09, 0xc9, 0x45, - 0x6a, 0xdc, 0x6e, 0xde, 0x82, 0x0f, 0xac, 0xea, 0x22, 0x5d, 0x47, 0x26, - 0xee, 0x9a, 0x6e, 0x0a, 0x42, 0xf2, 0xda, 0x18, 0x3c, 0x7d, 0xd8, 0x68, - 0x7e, 0x4a, 0x4c, 0xbd, 0xb0, 0x00, 0x73, 0x2c, 0x5c, 0x33, 0xf8, 0xb3, - 0x3e, 0x5c, 0xc7, 0x3b, 0xf4, 0x8d, 0xee, 0xee, 0x83, 0x21, 0x5c, 0x42, - 0x24, 0xb3, 0x13, 0xb3, 0x28, 0x1b, 0x85, 0xf5, 0xaa, 0x1c, 0xf9, 0xd8, - 0x90, 0x91, 0xaf, 0x98, 0x40, 0x7c, 0xce, 0x8c, 0x12, 0x5c, 0x68, 0x86, - 0xd4, 0x55, 0xd8, 0x80, 0x93, 0x01, 0x64, 0x34, 0x98, 0x8b, 0x9a, 0x7a, - 0x85, 0x62, 0xc0, 0x76, 0x92, 0xa3, 0x98, 0x11, 0x13, 0x60, 0xc3, 0x72, - 0xb4, 0xb1, 0x8b, 0xf4, 0xf8, 0xc6, 0x23, 0xf6, 0xe6, 0x98, 0x5a, 0xde, - 0x48, 0xff, 0x86, 0x28, 0x41, 0x6c, 0xcb, 0xc7, 0x70, 0x90, 0x17, 0xb9, - 0x61, 0x0f, 0x26, 0x2f, 0x8f, 0xb9, 0x56, 0x49, 0x79, 0x09, 0x88, 0xf2, - 0x3e, 0xff, 0x06, 0x90, 0xb5, 0x78, 0x8e, 0xb1, 0xac, 0x89, 0xe8, 0x8b, - 0x26, 0x4b, 0x6e, 0x7c, 0xbd, 0x54, 0x76, 0xdb, 0x6f, 0x78, 0xfc, 0xdd, - 0x9d, 0x31, 0x17, 0x15, 0xb7, 0x65, 0xc7, 0x9f, 0x55, 0x76, 0x5e, 0xa0, - 0xb9, 0x8e, 0xd9, 0xa1, 0x93, 0x23, 0x6c, 0x18, 0x47, 0x31, 0xee, 0x73, - 0x77, 0xa1, 0x44, 0xb2, 0x53, 0xd8, 0xd6, 0x82, 0x07, 0x0e, 0x1b, 0x86, - 0x2d, 0xb0, 0xe2, 0x22, 0x9f, 0xac, 0xb6, 0xb7, 0x88, 0xa0, 0x03, 0x07, - 0xe6, 0xbd, 0x45, 0x4d, 0x50, 0xec, 0xce, 0x4d, 0xe9, 0x43, 0x90, 0x8e, - 0xaf, 0xdf, 0xc0, 0x4d, 0xe8, 0x3d, 0xfe, 0xb8, 0x34, 0x2b, 0x81, 0xbf, - 0x02, 0x50, 0x87, 0x40, 0xaa, 0x70, 0x43, 0xc8, 0xda, 0x8e, 0xc0, 0xa6, - 0x7a, 0xab, 0xe7, 0x5a, 0x4d, 0xf2, 0x44, 0x9d, 0xbd, 0x7e, 0x76, 0x63, - 0xd8, 0x00, 0x45, 0xb2, 0x1e, 0x20, 0xb7, 0x96, 0x08, 0xb9, 0x4c, 0x06, - 0x81, 0x43, 0x26, 0xd4, 0x5b, 0x90, 0x3c, 0x39, 0xc3, 0x3b, 0xee, 0x27, - 0x7a, 0x4e, 0x1d, 0x5f, 0x9e, 0xeb, 0xe1, 0x2f, 0x10, 0xf0, 0xd9, 0x2e, - 0x61, 0x8a, 0x67, 0xca, 0xbb, 0xbf, 0x17, 0xe3, 0xf6, 0x58, 0xaa, 0xeb, - 0x5f, 0xd7, 0xda, 0xfb, 0x81, 0x63, 0x0e, 0xe0, 0xac, 0x93, 0xe8, 0x1b, - 0x11, 0x3a, 0x1f, 0x51, 0x26, 0x99, 0xea, 0xf3, 0x73, 0x99, 0x2a, 0xd0, - 0xaf, 0x76, 0xd1, 0xda, 0xcc, 0xfe, 0xce, 0x82, 0x69, 0x6d, 0xe4, 0xc3, - 0x44, 0xa6, 0x7a, 0x8e, 0xda, 0x44, 0xdf, 0x07, 0xaf, 0xf0, 0x6d, 0x33, - 0x90, 0x8a, 0xc4, 0x8c, 0x68, 0xa6, 0x86, 0xa8, 0x59, 0x00, 0x62, 0x36, - 0x0c, 0x55, 0x7d, 0x63, 0xd2, 0xea, 0x3a, 0x2b, 0x6a, 0x5b, 0x76, 0x9d, - 0xab, 0x26, 0xb6, 0x25, 0xe7, 0x95, 0x42, 0x54, 0x11, 0xf5, 0x05, 0x33, - 0x7f, 0x6e, 0x8a, 0xa0, 0x4c, 0x25, 0x63, 0x3f, 0x13, 0xfe, 0x81, 0x54, - 0x7b, 0x86, 0x45, 0x9b, 0xba, 0x6b, 0x34, 0x4a, 0x1e, 0xeb, 0x92, 0x67, - 0x9e, 0x13, 0x30, 0xc1, 0x3c, 0xfd, 0xe1, 0xe8, 0xbe, 0xe2, 0x5c, 0x93, - 0xf5, 0xd9, 0xf6, 0x9d, 0x42, 0x88, 0x59, 0x2f, 0x76, 0x77, 0x6a, 0x4a, - 0x4c, 0x8e, 0xed, 0x0e, 0x49, 0x7e, 0xdc, 0x08, 0xef, 0x84, 0x74, 0x1e, - 0x27, 0x37, 0x53, 0xd4, 0x7e, 0xbf, 0xac, 0x32, 0x94, 0x00, 0x06, 0xf4, - 0x57, 0x0f, 0xa6, 0xe7, 0xa6, 0x70, 0x25, 0x3a, 0x2e, 0x8d, 0x83, 0xa0, - 0x1c, 0xa8, 0x08, 0x2c, 0xbd, 0x14, 0x71, 0xad, 0x57, 0xd1, 0xb1, 0xed, - 0x49, 0x91, 0x1f, 0x72, 0xe8, 0xab, 0x46, 0x83, 0x89, 0xb8, 0x16, 0xe4, - 0xf5, 0x7f, 0x73, 0x1f, 0x44, 0x01, 0xc9, 0x88, 0x9c, 0xdc, 0x65, 0xb4, - 0x44, 0xbd, 0x47, 0x8b, 0x52, 0x48, 0x5c, 0x30, 0xf9, 0x73, 0xa0, 0x8c, - 0x72, 0xa3, 0x4c, 0x93, 0x0f, 0xb1, 0xda, 0x0b, 0x8c, 0x02, 0xb4, 0x07, - 0x06, 0xda, 0x78, 0xed, 0x7a, 0x4c, 0x4a, 0xb2, 0x21, 0xee, 0x23, 0xe8, - 0x56, 0x4c, 0x6d, 0x03, 0xa0, 0x71, 0x2c, 0xdf, 0x6a, 0xc4, 0x68, 0xa4, - 0xf0, 0x18, 0x49, 0xcd, 0x7e, 0x66, 0xef, 0x62, 0x1e, 0xe7, 0x23, 0x3b, - 0x87, 0x19, 0x54, 0x12, 0x67, 0x63, 0xb7, 0x5f, 0xa6, 0xd2, 0x26, 0xed, - 0x33, 0x09, 0xfe, 0x58, 0xae, 0x78, 0x48, 0x03, 0x17, 0x00, 0x01, 0x7f, - 0x70, 0xe2, 0xde, 0xc0, 0x1d, 0x4c, 0x32, 0x66, 0xec, 0xe0, 0x8f, 0x00, - 0x3e, 0xf3, 0x57, 0x77, 0xe3, 0x9b, 0x8d, 0x70, 0xac, 0x3c, 0x36, 0x0e, - 0x7b, 0x67, 0xc6, 0x1d, 0xc5, 0x64, 0x9c, 0x0a, 0xfb, 0xdb, 0x40, 0xf9, - 0x85, 0x42, 0x1a, 0x01, 0x4b, 0x86, 0xb2, 0x60, 0xc3, 0xc6, 0x69, 0x48, - 0xff, 0x22, 0xf8, 0xcb, 0xc2, 0x4a, 0xb2, 0x36, 0x62, 0xdb, 0xaa, 0x1f, - 0xe5, 0xdc, 0x2c, 0xa5, 0x2c, 0x33, 0x42, 0xf0, 0xe3, 0x9b, 0x48, 0xa7, - 0x50, 0xaa, 0x0f, 0x3e, 0x6c, 0xfb, 0xed, 0x4b, 0xbd, 0xd1, 0x1b, 0x5d, - 0x96, 0xa2, 0x9c, 0x1a, 0xe3, 0xb6, 0x32, 0xf0, 0xcb, 0x08, 0x60, 0xdf, - 0x48, 0xde, 0x04, 0x62, 0xfc, 0x01, 0x30, 0x29, 0x9e, 0x39, 0x4a, 0x0c, - 0x4f, 0x79, 0x3b, 0xc9, 0xce, 0xd8, 0xc4, 0xee, 0xcc, 0xdc, 0x63, 0x50, - 0xe5, 0xa4, 0x6c, 0x95, 0x66, 0xc0, 0x47, 0x0f, 0xbe, 0xa2, 0x02, 0x6d, - 0xcd, 0x32, 0xc3, 0x14, 0x0e, 0x95, 0x21, 0xbc, 0x61, 0xee, 0x25, 0x65, - 0xfc, 0x4c, 0x23, 0xe0, 0xa5, 0x0a, 0x65, 0xc0, 0xe3, 0xe8, 0x56, 0x10, - 0xb3, 0xb1, 0x6a, 0xd1, 0xd3, 0x71, 0xb2, 0xb5, 0x90, 0x74, 0x32, 0x24, - 0xe5, 0xa7, 0x04, 0x37, 0xde, 0x71, 0xef, 0x08, 0x4c, 0x1c, 0x80, 0x6b, - 0x99, 0x17, 0x47, 0x72, 0x44, 0x31, 0x22, 0xd9, 0xce, 0xff, 0x61, 0x2d, - 0x72, 0xe0, 0xbd, 0x48, 0x3e, 0xfd, 0x5a, 0xc5, 0x7b, 0x16, 0x96, 0xbd, - 0x47, 0x60, 0x6d, 0xa1, 0x6a, 0x34, 0xe9, 0xaa, 0xd5, 0xfe, 0x09, 0x1d, - 0xfa, 0x94, 0xb8, 0xc0, 0x63, 0xa9, 0x1d, 0x8a, 0x27, 0x7b, 0xf0, 0xd2, - 0xe7, 0x3e, 0x5e, 0x6e, 0x6a, 0x8e, 0xe3, 0x4b, 0xa8, 0x0c, 0xac, 0xc4, - 0x50, 0x1c, 0xa0, 0xfc, 0x48, 0x42, 0x53, 0x54, 0x08, 0x64, 0xae, 0x9f, - 0x19, 0xd6, 0xd3, 0xc9, 0x55, 0x0e, 0x72, 0x18, 0x53, 0xef, 0x02, 0xd1, - 0x14, 0x81, 0xa9, 0xa8, 0xb6, 0xf5, 0x93, 0x56, 0xcb, 0xd0, 0x63, 0xbc, - 0xb9, 0xfd, 0x77, 0xa4, 0x1d, 0x3f, 0x29, 0xba, 0x97, 0xb5, 0xed, 0x7c, - 0xe5, 0x35, 0xe5, 0x74, 0x6b, 0x08, 0xe8, 0x3f, 0x6d, 0xc4, 0x70, 0x06, - 0x3b, 0xd1, 0x92, 0xcc, 0xab, 0x7a, 0x22, 0x13, 0x96, 0x41, 0xfc, 0x92, - 0x81, 0xb7, 0x39, 0xdf, 0x68, 0xaa, 0x77, 0x21, 0x87, 0xff, 0x78, 0x83, - 0xf5, 0xca, 0x8b, 0x08, 0xa9, 0xcd, 0xc0, 0xa0, 0xb8, 0x7c, 0x52, 0x93, - 0xec, 0x93, 0x5c, 0xe6, 0xd9, 0xc9, 0x49, 0x94, 0x60, 0xac, 0x1c, 0x9e, - 0x1e, 0x19, 0xac, 0xc3, 0xfa, 0x3f, 0xe0, 0x36, 0x1d, 0x99, 0x8f, 0xea, - 0xc7, 0xe6, 0x1e, 0x0b, 0x7f, 0x02, 0x73, 0x3c, 0xda, 0x49, 0x68, 0x44, - 0x91, 0x76, 0x3c, 0x4d, 0x53, 0xfc, 0xda, 0x99, 0x8d, 0x13, 0xcf, 0xd3, - 0x88, 0xbb, 0xdf, 0x3f, 0xab, 0x42, 0x08, 0x9b, 0xeb, 0x1f, 0x93, 0x09, - 0x59, 0x39, 0x21, 0x2c, 0x91, 0xe5, 0xef, 0x97, 0xf7, 0x8c, 0x56, 0x34, - 0x66, 0x94, 0x05, 0x18, 0x1b, 0x50, 0x41, 0xf3, 0xa6, 0xca, 0x82, 0xdf, - 0xa3, 0x8e, 0xa9, 0x3f, 0x6d, 0xa0, 0xfb, 0x74, 0x2b, 0x35, 0x2c, 0x02, - 0xc3, 0xd3, 0xba, 0x21, 0x0e, 0xef, 0x23, 0x35, 0x06, 0xcd, 0xc7, 0x5e, - 0x44, 0x6f, 0xa5, 0x5d, 0xee, 0x9a, 0x42, 0x54, 0x47, 0x78, 0xbe, 0x47, - 0x9e, 0x17, 0x56, 0x94, 0xf7, 0xb2, 0x6c, 0x97, 0x45, 0x16, 0xea, 0xa0, - 0xe4, 0xb4, 0x84, 0xf0, 0xda, 0xb6, 0x3a, 0xb6, 0xee, 0x1d, 0x5f, 0x87, - 0x0d, 0xa4, 0x13, 0x19, 0xa3, 0x4b, 0x27, 0x4c, 0xec, 0x9e, 0x66, 0x2b, - 0x6f, 0x91, 0x85, 0x22, 0xee, 0x2e, 0x55, 0xa2, 0xe5, 0x52, 0x09, 0x78, - 0x05, 0x39, 0x32, 0x27, 0xda, 0x7c, 0xe2, 0xcc, 0x78, 0x40, 0xfc, 0x11, - 0xab, 0x95, 0xbc, 0xb6, 0x3f, 0x26, 0x90, 0x15, 0xcb, 0x59, 0xd5, 0x10, - 0x36, 0xeb, 0x03, 0x25, 0x8e, 0x46, 0xcf, 0x63, 0x1d, 0x34, 0x76, 0xda, - 0x61, 0xef, 0xfd, 0x86, 0x66, 0x7a, 0x23, 0x9a, 0xff, 0xcb, 0xe1, 0x61, - 0xc7, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0xd3, 0x13, 0xc6, - 0x7f, 0x6c, 0x2b, 0xef, 0x9b, 0xbf, 0x66, 0x14, 0xe8, 0x6f, 0xb2, 0xaf, - 0xf4, 0x61, 0x91, 0x3f, 0x7b, 0xf7, 0x9b, 0xb5, 0x34, 0x6b, 0x8f, 0xca, - 0xcf, 0x32, 0x6c, 0xe0, 0xb4, 0xea, 0x51, 0xff, 0x01, 0x8b, 0xd7, 0x80, - 0x95, 0x46, 0xb9, 0xbc, 0xe3, 0x92, 0x52, 0x3b, 0xec, 0x63, 0xc3, 0x6e, - 0x34, 0xef, 0xc7, 0xb1, 0x52, 0x41, 0x87, 0x21, 0xa5, 0xf1, 0xe5, 0x37, - 0xc5, 0x7c, 0x9d, 0xa3, 0x14, 0xb8, 0xee, 0x35, 0x63, 0xed, 0x00, 0xce, - 0x91, 0xf8, 0xc7, 0x88, 0x41, 0xf6, 0xbf, 0x5a, 0x6c, 0x73, 0xca, 0x0b, - 0x1a, 0xde, 0x7e, 0x49, 0x7c, 0xc1, 0xe8, 0xeb, 0xe3, 0xba, 0xf2, 0x8a, - 0x98, 0xce, 0x19, 0x98, 0xdb, 0x62, 0x03, 0x15, 0x08, 0x33, 0x83, 0x77, - 0x3f, 0x7c, 0xc8, 0x27, 0xef, 0x2d, 0x4b, 0x4b, 0x7f, 0x80, 0xfc, 0x12, - 0x41, 0x4b, 0x89, 0x88, 0x32, 0x19, 0xaa, 0xf4, 0xff, 0x39, 0x61, 0xc9, - 0x06, 0xfd, 0x78, 0x79, 0xc0, 0x52, 0x7e, 0xe6, 0x79, 0x7d, 0x50, 0x43, - 0xb3, 0xf2, 0x86, 0xb2, 0xf3, 0x38, 0x35, 0x72, 0xbf, 0xb7, 0x35, 0x45, - 0x34, 0xb3, 0x05, 0x67, 0x3e, 0xb7, 0x71, 0x5e, 0x55, 0x36, 0xc7, 0xbf, - 0x3b, 0x6d, 0xc3, 0xf9, 0x9c, 0x94, 0x4f, 0x63, 0x3e, 0x34, 0x44, 0x9e, - 0x5f, 0x2b, 0x65, 0xc2, 0xeb, 0x5b, 0x5c, 0x61, 0x20, 0x6a, 0x3e, 0xb5, - 0x38, 0xf0, 0x5b, 0xde, 0x45, 0xa7, 0x1f, 0xa7, 0xad, 0xd0, 0xb5, 0x0d, - 0x2d, 0x15, 0x9f, 0x7c, 0x62, 0x7a, 0xf1, 0x2a, 0xb8, 0x6c, 0xeb, 0x0f, - 0xd5, 0x84, 0xa9, 0xfa, 0x5f, 0xc6, 0x39, 0x66, 0xd7, 0xaa, 0x8c, 0x4b, - 0xbe, 0xaf, 0x26, 0xc1, 0x7b, 0xbb, 0xbb, 0x45, 0xa9, 0x58, 0xb7, 0x62, - 0x6b, 0x96, 0x3a, 0xe9, 0xb0, 0x87, 0x1b, 0x5d, 0x8b, 0x77, 0xe0, 0xcc, - 0x9c, 0xad, 0x3b, 0xfb, 0xe9, 0x53, 0x85, 0x1c, 0xae, 0xf8, 0x70, 0x06, - 0x66, 0x88, 0x30, 0x12, 0x44, 0xa5, 0x31, 0xd8, 0x23, 0xdc, 0x4f, 0x80, - 0x36, 0x02, 0x9c, 0x9e, 0x36, 0x09, 0x70, 0xd5, 0xa4, 0x41, 0xa6, 0x48, - 0xfd, 0xd3, 0x39, 0x19, 0xa0, 0x43, 0x7e, 0x8d, 0xe9, 0x41, 0x3b, 0x1b, - 0x58, 0x6b, 0xb0, 0xe2, 0x28, 0x21, 0x21, 0xe3, 0x6d, 0xa1, 0x84, 0x29, - 0x1e, 0xcf, 0x5f, 0xeb, 0x81, 0xf9, 0xc6, 0x07, 0x09, 0xc9, 0xe1, 0x6d, - 0x53, 0x47, 0x59, 0xf7, 0x14, 0x23, 0x5d, 0x39, 0x12, 0x4b, 0xbe, 0x7e, - 0x28, 0xb9, 0x9c, 0x23 -}; -unsigned int ios6_1_keychain_2_db_len = 126976; - diff --git a/OSX/sec/securityd/Regressions/ios8-inet-keychain-2.h b/OSX/sec/securityd/Regressions/ios8-inet-keychain-2.h deleted file mode 100644 index 4c531164..00000000 --- a/OSX/sec/securityd/Regressions/ios8-inet-keychain-2.h +++ /dev/null @@ -1,9902 +0,0 @@ -unsigned char ios8_inet_keychain_2_db[] = { - 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x20, 0x33, 0x00, 0x10, 0x00, 0x02, 0x02, 0x00, 0x40, 0x20, 0x20, - 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, - 0x00, 0x2d, 0xe6, 0x08, 0x0d, 0x0f, 0xfc, 0x00, 0x1b, 0x02, 0x81, 0x00, - 0x0e, 0x23, 0x0f, 0xd3, 0x0d, 0xd1, 0x0b, 0x4f, 0x0d, 0xa8, 0x09, 0x9c, - 0x0b, 0x26, 0x06, 0x6c, 0x09, 0x73, 0x06, 0x28, 0x05, 0xf1, 0x05, 0xba, - 0x05, 0x83, 0x05, 0x4c, 0x05, 0x15, 0x04, 0xde, 0x04, 0xa7, 0x04, 0x70, - 0x04, 0x39, 0x04, 0x02, 0x03, 0xcb, 0x03, 0x94, 0x03, 0x5d, 0x03, 0x26, - 0x02, 0xef, 0x02, 0xb8, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1b, 0x06, 0x17, 0x17, 0x15, 0x01, - 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x6b, - 0x65, 0x79, 0x73, 0x1d, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, - 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x20, 0x4f, - 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x75, 0x6e, 0x77, 0x70, 0x29, - 0x35, 0x1a, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x69, 0x77, 0x72, 0x61, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x1c, 0x43, - 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, - 0x69, 0x77, 0x72, 0x61, 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, - 0x73, 0x28, 0x77, 0x72, 0x61, 0x70, 0x29, 0x35, 0x19, 0x06, 0x17, 0x17, - 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x76, 0x72, 0x66, - 0x79, 0x6b, 0x65, 0x79, 0x73, 0x1b, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, - 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x76, 0x72, 0x66, 0x79, - 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x76, 0x72, 0x66, - 0x79, 0x29, 0x35, 0x18, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x6b, 0x65, 0x79, 0x73, - 0x1a, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, - 0x58, 0x20, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x4e, 0x20, 0x6b, - 0x65, 0x79, 0x73, 0x28, 0x73, 0x69, 0x67, 0x6e, 0x29, 0x35, 0x17, 0x06, - 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, - 0x72, 0x76, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x19, 0x43, 0x52, 0x45, 0x41, - 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x72, - 0x76, 0x65, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, - 0x72, 0x76, 0x65, 0x29, 0x35, 0x16, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, 0x65, 0x63, 0x72, 0x6b, 0x65, - 0x79, 0x73, 0x18, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, - 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x65, 0x63, 0x72, 0x20, 0x4f, 0x4e, - 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, 0x65, 0x63, 0x72, 0x29, 0x35, - 0x15, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x69, 0x65, 0x6e, 0x63, 0x72, 0x6b, 0x65, 0x79, 0x73, 0x17, 0x43, 0x52, - 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, - 0x65, 0x6e, 0x63, 0x72, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, - 0x28, 0x65, 0x6e, 0x63, 0x72, 0x29, 0x35, 0x14, 0x06, 0x17, 0x17, 0x15, - 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x6b, 0x6c, 0x62, 0x6c, - 0x6b, 0x65, 0x79, 0x73, 0x16, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, - 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x20, - 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6b, 0x6c, 0x62, 0x6c, - 0x29, 0x35, 0x13, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x69, 0x6b, 0x63, 0x6c, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x15, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, - 0x20, 0x69, 0x6b, 0x63, 0x6c, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, - 0x79, 0x73, 0x28, 0x6b, 0x63, 0x6c, 0x73, 0x29, 0x35, 0x12, 0x06, 0x17, - 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x70, 0x6b, - 0x68, 0x68, 0x63, 0x65, 0x72, 0x74, 0x14, 0x43, 0x52, 0x45, 0x41, 0x54, - 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x70, 0x6b, 0x68, - 0x68, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x70, 0x6b, - 0x68, 0x68, 0x29, 0x35, 0x11, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x69, 0x73, 0x6b, 0x69, 0x64, 0x63, 0x65, 0x72, - 0x74, 0x13, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, - 0x45, 0x58, 0x20, 0x69, 0x73, 0x6b, 0x69, 0x64, 0x20, 0x4f, 0x4e, 0x20, - 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x6b, 0x69, 0x64, 0x29, 0x35, 0x10, - 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, - 0x73, 0x75, 0x62, 0x6a, 0x63, 0x65, 0x72, 0x74, 0x12, 0x43, 0x52, 0x45, - 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, - 0x75, 0x62, 0x6a, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, - 0x73, 0x75, 0x62, 0x6a, 0x29, 0x35, 0x0f, 0x06, 0x17, 0x17, 0x15, 0x01, - 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x63, - 0x65, 0x72, 0x74, 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, - 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x4f, - 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x61, 0x6c, 0x69, 0x73, 0x29, - 0x35, 0x0e, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x69, 0x6b, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x79, 0x73, 0x10, 0x43, - 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, - 0x69, 0x6b, 0x73, 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, - 0x73, 0x28, 0x73, 0x68, 0x61, 0x31, 0x29, 0x35, 0x0d, 0x06, 0x17, 0x17, - 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x63, 0x73, 0x68, - 0x61, 0x63, 0x65, 0x72, 0x74, 0x0f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, - 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x63, 0x73, 0x68, 0x61, - 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x68, 0x61, - 0x31, 0x29, 0x35, 0x0c, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x69, 0x69, 0x73, 0x68, 0x61, 0x69, 0x6e, 0x65, 0x74, - 0x0e, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, - 0x58, 0x20, 0x69, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x69, - 0x6e, 0x65, 0x74, 0x28, 0x73, 0x68, 0x61, 0x31, 0x29, 0x35, 0x0b, 0x06, - 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x67, - 0x73, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x70, 0x0d, 0x43, 0x52, 0x45, 0x41, - 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x67, 0x73, - 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x67, 0x65, 0x6e, 0x70, 0x28, 0x73, - 0x68, 0x61, 0x31, 0x29, 0x42, 0x0a, 0x06, 0x17, 0x1d, 0x1d, 0x01, 0x59, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0c, 0x43, 0x52, - 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x74, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x29, - 0x86, 0x04, 0x08, 0x07, 0x17, 0x15, 0x15, 0x01, 0x8b, 0x6b, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x0a, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, - 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, - 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, - 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, - 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, - 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6b, 0x63, 0x6c, 0x73, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x30, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, - 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x65, - 0x72, 0x6d, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, - 0x72, 0x69, 0x76, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x6d, 0x6f, 0x64, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, - 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, - 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, - 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x61, 0x74, 0x61, 0x67, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, - 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, - 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x79, 0x70, - 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, - 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x62, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, - 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, - 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x64, 0x61, - 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x30, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, - 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x65, 0x6e, 0x73, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x61, 0x73, 0x65, 0x6e, - 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x65, 0x78, 0x74, - 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, - 0x78, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x65, - 0x6e, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x64, 0x65, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, - 0x2c, 0x64, 0x72, 0x76, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x2c, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x2c, 0x76, 0x72, 0x66, 0x79, 0x20, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x45, 0x52, 0x2c, 0x73, 0x6e, 0x72, 0x63, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x79, 0x72, 0x63, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x77, 0x72, 0x61, 0x70, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x75, 0x6e, 0x77, 0x70, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x64, 0x61, 0x74, 0x61, - 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, - 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, - 0x54, 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, - 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, - 0x6d, 0x62, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, - 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, - 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x6b, - 0x63, 0x6c, 0x73, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x2c, 0x61, 0x74, 0x61, - 0x67, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x2c, - 0x62, 0x73, 0x69, 0x7a, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x2c, 0x73, 0x64, - 0x61, 0x74, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x2c, 0x61, 0x67, 0x72, 0x70, - 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x09, 0x06, 0x17, 0x3b, - 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, - 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x5f, 0x31, 0x6b, 0x65, 0x79, 0x73, 0x0b, - 0x83, 0x07, 0x06, 0x07, 0x17, 0x15, 0x15, 0x01, 0x85, 0x71, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x63, 0x65, 0x72, 0x74, 0x63, 0x65, 0x72, 0x74, 0x08, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, - 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, - 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, - 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, - 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, - 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x63, 0x74, 0x79, 0x70, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x30, 0x2c, 0x63, 0x65, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, - 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x73, - 0x75, 0x62, 0x6a, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x73, 0x73, - 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x27, 0x27, 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, - 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, - 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x6b, 0x69, - 0x64, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x6b, 0x68, 0x68, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, - 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x73, - 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, - 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, 0x62, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, - 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, - 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, 0x4f, 0x42, - 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x63, 0x74, 0x79, 0x70, - 0x2c, 0x69, 0x73, 0x73, 0x72, 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x2c, 0x61, - 0x67, 0x72, 0x70, 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x07, - 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, - 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x31, 0x63, 0x65, - 0x72, 0x74, 0x09, 0x84, 0x56, 0x04, 0x07, 0x17, 0x15, 0x15, 0x01, 0x89, - 0x0f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x74, 0x69, 0x6e, - 0x65, 0x74, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, - 0x42, 0x4c, 0x45, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x28, 0x72, 0x6f, 0x77, - 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, - 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, - 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, - 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, - 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, 0x65, 0x73, - 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, 0x74, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, 0x70, 0x20, - 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, - 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, - 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, 0x20, 0x49, - 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, - 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, - 0x64, 0x6d, 0x6e, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, - 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, - 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, - 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x70, - 0x74, 0x63, 0x6c, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, - 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, - 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, - 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x70, 0x61, 0x74, - 0x68, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x27, 0x27, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, - 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, - 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x73, 0x79, 0x6e, - 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, - 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, 0x62, 0x20, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, - 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, - 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x55, - 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, - 0x64, 0x6d, 0x6e, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x2c, 0x70, 0x74, 0x63, - 0x6c, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x2c, - 0x70, 0x61, 0x74, 0x68, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x2c, 0x73, 0x79, - 0x6e, 0x63, 0x29, 0x29, 0x27, 0x05, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, - 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x6e, - 0x65, 0x74, 0x5f, 0x31, 0x69, 0x6e, 0x65, 0x74, 0x07, 0x50, 0x03, 0x06, - 0x17, 0x2b, 0x2b, 0x01, 0x59, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x71, - 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x05, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, - 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, - 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x28, 0x6e, 0x61, - 0x6d, 0x65, 0x2c, 0x73, 0x65, 0x71, 0x29, 0x83, 0x2d, 0x01, 0x07, 0x17, - 0x15, 0x15, 0x01, 0x86, 0x3d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x67, 0x65, - 0x6e, 0x70, 0x67, 0x65, 0x6e, 0x70, 0x03, 0x43, 0x52, 0x45, 0x41, 0x54, - 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x67, 0x65, 0x6e, 0x70, - 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, - 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, - 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, - 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, - 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, - 0x2c, 0x64, 0x65, 0x73, 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, - 0x63, 0x6d, 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, - 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, - 0x63, 0x72, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, - 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, - 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, - 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, - 0x61, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, - 0x73, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, - 0x72, 0x6f, 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, - 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, - 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, - 0x27, 0x27, 0x2c, 0x73, 0x76, 0x63, 0x65, 0x20, 0x42, 0x4c, 0x4f, 0x42, - 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, - 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x67, 0x65, 0x6e, - 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, - 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, - 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, - 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, - 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, - 0x62, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, - 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, - 0x4f, 0x42, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, - 0x63, 0x74, 0x2c, 0x73, 0x76, 0x63, 0x65, 0x2c, 0x61, 0x67, 0x72, 0x70, - 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x02, 0x06, 0x17, 0x3b, - 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, - 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x67, 0x65, 0x6e, 0x70, 0x5f, 0x31, 0x67, 0x65, 0x6e, 0x70, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xd7, 0x00, - 0x0f, 0xf5, 0x0f, 0xeb, 0x0f, 0xe1, 0x0f, 0xd7, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x04, 0x03, 0x15, 0x01, 0x69, 0x6e, 0x65, 0x74, - 0x77, 0x08, 0x03, 0x03, 0x15, 0x01, 0x63, 0x65, 0x72, 0x74, 0x05, 0x08, - 0x02, 0x03, 0x15, 0x01, 0x6b, 0x65, 0x79, 0x73, 0x0e, 0x09, 0x01, 0x03, - 0x15, 0x02, 0x67, 0x65, 0x6e, 0x70, 0x00, 0xd6, 0x0d, 0x00, 0x00, 0x00, - 0x02, 0x0a, 0xdc, 0x00, 0x0d, 0x6e, 0x0a, 0xdc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x85, 0x0f, 0x09, 0x1d, 0x00, 0x07, 0x07, 0x34, - 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, - 0x34, 0x15, 0x34, 0x08, 0x34, 0x86, 0x36, 0x33, 0x11, 0x09, 0x08, 0x34, - 0x41, 0xb8, 0x54, 0x5c, 0xc8, 0xd9, 0xbb, 0x38, 0x41, 0xb8, 0x54, 0x5c, - 0xc8, 0xd9, 0xbb, 0x38, 0x3e, 0x72, 0xab, 0x36, 0x98, 0xa6, 0xab, 0x50, - 0x6e, 0xf3, 0x74, 0x41, 0xd3, 0xda, 0x7d, 0xb4, 0x6b, 0x01, 0xe8, 0xcf, - 0x75, 0x05, 0xd6, 0x4a, 0x54, 0xe0, 0x61, 0xb7, 0xac, 0xd5, 0x4c, 0xcd, - 0x58, 0xb4, 0x9d, 0xc4, 0x35, 0x00, 0xb6, 0x35, 0x44, 0x87, 0x31, 0x70, - 0x51, 0x1a, 0x23, 0xb6, 0x21, 0x60, 0x8c, 0x6c, 0x65, 0xbf, 0xf1, 0xd1, - 0x7e, 0x07, 0x56, 0x8a, 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, - 0x7c, 0xca, 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, - 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, - 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, - 0xc0, 0x39, 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, - 0xc5, 0x1c, 0xff, 0xec, 0x68, 0x74, 0x70, 0x73, 0xd0, 0x0b, 0x39, 0x81, - 0x5c, 0x18, 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, - 0x07, 0x28, 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, - 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, - 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x17, 0xf9, 0xcd, 0x4d, 0xa5, 0x0e, 0x24, 0x36, 0x1a, 0x8e, 0x43, 0x7e, - 0x1a, 0x0c, 0xe6, 0xa1, 0xe7, 0x70, 0x86, 0x1e, 0x6e, 0x14, 0x98, 0xd3, - 0x70, 0x37, 0x04, 0xda, 0x23, 0x9c, 0x19, 0x25, 0xb3, 0x56, 0x67, 0x5d, - 0x6f, 0xa1, 0x14, 0xbd, 0x6e, 0xc5, 0xfc, 0x34, 0x80, 0x39, 0xc0, 0x98, - 0x8b, 0x0b, 0xc9, 0xe9, 0x12, 0xe2, 0x33, 0xbc, 0x33, 0xae, 0x57, 0xc1, - 0x5b, 0xc2, 0xa8, 0x09, 0xf2, 0xc6, 0xd2, 0xbf, 0x6c, 0x3a, 0xd7, 0x36, - 0xa5, 0x47, 0x0a, 0x21, 0x43, 0x09, 0xaa, 0x0d, 0x4a, 0x57, 0x3c, 0xd1, - 0xa5, 0x2b, 0xaf, 0x5e, 0x8b, 0xcb, 0x37, 0xd1, 0x40, 0x88, 0x6d, 0x52, - 0x3e, 0x3d, 0x0e, 0xe8, 0x0d, 0xba, 0x4e, 0x61, 0x52, 0xcc, 0xe6, 0xa2, - 0xaa, 0xfe, 0x11, 0x7a, 0x49, 0x83, 0x82, 0xfe, 0xf8, 0xed, 0xb7, 0xc5, - 0xe6, 0x62, 0x8a, 0x01, 0x52, 0x74, 0x41, 0x97, 0x4f, 0xa5, 0x56, 0xc7, - 0x89, 0x45, 0x19, 0x6e, 0x0f, 0x37, 0xaf, 0x26, 0xef, 0xe6, 0x95, 0x75, - 0xc2, 0x81, 0xc7, 0xdc, 0x92, 0xbe, 0x7d, 0xb3, 0xc7, 0x41, 0xa4, 0x6e, - 0x55, 0xff, 0x90, 0x98, 0x0b, 0xb4, 0x38, 0x90, 0xd3, 0x7f, 0x45, 0x20, - 0x15, 0xc9, 0x63, 0xda, 0xe8, 0xac, 0x55, 0x47, 0x29, 0xbe, 0x02, 0xff, - 0x61, 0x8e, 0x17, 0x5a, 0x20, 0x60, 0x0c, 0x86, 0xdb, 0x80, 0x4b, 0x8e, - 0xb4, 0xd2, 0xad, 0x11, 0x3e, 0x5e, 0xf1, 0xed, 0xdf, 0xf1, 0xef, 0x53, - 0x09, 0x22, 0x43, 0x8f, 0xbd, 0x20, 0xbe, 0x81, 0x78, 0x85, 0x69, 0xc5, - 0x6f, 0x25, 0xca, 0xfb, 0x51, 0x48, 0x5a, 0xd9, 0x49, 0x24, 0x5e, 0x94, - 0x69, 0xeb, 0x64, 0x71, 0xb2, 0x2c, 0xbe, 0x73, 0x9d, 0x75, 0xe9, 0x67, - 0x37, 0xa6, 0x35, 0xc8, 0x07, 0xf9, 0xfe, 0xde, 0xc0, 0xab, 0x42, 0xa6, - 0x78, 0x8f, 0x72, 0xd7, 0x9f, 0xd1, 0x98, 0x08, 0x35, 0x25, 0x01, 0xaf, - 0x92, 0xca, 0x57, 0x74, 0x36, 0xee, 0x1d, 0x08, 0x3a, 0x2d, 0x5d, 0xf3, - 0x1d, 0x5f, 0x0b, 0x9e, 0xac, 0x28, 0x26, 0x77, 0xcf, 0x37, 0x9b, 0x4c, - 0x31, 0x14, 0x4f, 0xfe, 0xaf, 0x4f, 0x7e, 0x41, 0x26, 0xab, 0x41, 0x6d, - 0x61, 0x6b, 0xfd, 0xbc, 0xe3, 0xda, 0x2f, 0x81, 0xfc, 0xa6, 0x45, 0xc9, - 0x0e, 0xeb, 0x20, 0x03, 0x04, 0x3d, 0xce, 0x76, 0xc7, 0x1c, 0x52, 0xc5, - 0x03, 0x98, 0x2e, 0x3b, 0x2b, 0x9f, 0x51, 0xcb, 0x25, 0x89, 0x59, 0xd7, - 0xad, 0xce, 0x7a, 0x9e, 0x65, 0x6b, 0x32, 0x60, 0x7a, 0x62, 0x99, 0xd4, - 0xb7, 0xa3, 0x88, 0xae, 0x1e, 0x2a, 0x49, 0xcb, 0x7b, 0x61, 0x8c, 0xa6, - 0x66, 0xc8, 0x67, 0x01, 0x13, 0x0d, 0x48, 0xb0, 0xbd, 0x9a, 0x9e, 0xdb, - 0x56, 0x2e, 0xb9, 0xae, 0xec, 0xa4, 0x05, 0xa0, 0xb7, 0x43, 0x16, 0xe6, - 0x6e, 0x24, 0x39, 0xdf, 0x1b, 0x6e, 0x80, 0x21, 0x66, 0x63, 0x6f, 0x6d, - 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x61, 0x6b, 0x1d, 0x3d, 0x99, 0x45, 0x23, 0x73, - 0xf5, 0xb8, 0xec, 0x97, 0xe1, 0xc2, 0x84, 0xee, 0xec, 0xa3, 0xbc, 0x53, - 0xf3, 0xcd, 0x85, 0x0f, 0x08, 0x1d, 0x00, 0x07, 0x07, 0x34, 0x34, 0x00, - 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x15, - 0x34, 0x08, 0x34, 0x86, 0x36, 0x33, 0x11, 0x09, 0x08, 0x34, 0x41, 0xb7, - 0x81, 0x93, 0xca, 0x19, 0x3f, 0x18, 0x41, 0xb7, 0x81, 0x93, 0xca, 0x19, - 0x3f, 0x18, 0x3e, 0x72, 0xab, 0x36, 0x98, 0xa6, 0xab, 0x50, 0x6e, 0xf3, - 0x74, 0x41, 0xd3, 0xda, 0x7d, 0xb4, 0x6b, 0x01, 0xe8, 0xcf, 0x75, 0x05, - 0xd6, 0x4a, 0x54, 0xe0, 0x61, 0xb7, 0xac, 0xd5, 0x4c, 0xcd, 0x58, 0xb4, - 0x9d, 0xc4, 0x35, 0x00, 0xb6, 0x35, 0x44, 0x87, 0x31, 0x70, 0x51, 0x1a, - 0x23, 0xb6, 0x21, 0x60, 0x8c, 0x6c, 0x65, 0xbf, 0xf1, 0xd1, 0x7e, 0x07, - 0x56, 0x8a, 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, 0x7c, 0xca, - 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, 0xda, 0x39, - 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, - 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, 0xc0, 0x39, - 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, 0xc5, 0x1c, - 0xff, 0xec, 0x68, 0x74, 0x74, 0x70, 0xd0, 0x0b, 0x39, 0x81, 0x5c, 0x18, - 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, 0x07, 0x28, - 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, - 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x03, 0x00, - 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa1, 0x6f, - 0x3f, 0x1b, 0x33, 0x82, 0x64, 0x59, 0xaa, 0x01, 0x83, 0x01, 0xcb, 0x07, - 0x08, 0x16, 0x9c, 0xdf, 0x17, 0xf4, 0x20, 0x74, 0x62, 0xf4, 0xc4, 0xfc, - 0x8b, 0x8d, 0xef, 0x7b, 0x2d, 0x3d, 0x14, 0x52, 0x10, 0x2f, 0x9a, 0x7f, - 0xfa, 0xad, 0x48, 0xbf, 0x88, 0x10, 0x5f, 0xa9, 0xf0, 0x66, 0x80, 0x0a, - 0x72, 0xb0, 0x04, 0x8c, 0x81, 0x72, 0x4f, 0x1a, 0xc2, 0x24, 0x04, 0xec, - 0x78, 0x71, 0x26, 0x0f, 0xd8, 0x74, 0x86, 0x9e, 0x46, 0xc1, 0x83, 0x13, - 0x11, 0x1f, 0xb1, 0x16, 0x02, 0x41, 0x69, 0x4b, 0x4a, 0xca, 0x62, 0x1e, - 0xd3, 0xdf, 0xf9, 0x4a, 0xda, 0x34, 0x42, 0x49, 0xd5, 0x16, 0x69, 0x4f, - 0x21, 0x89, 0xf4, 0x74, 0xb1, 0xd8, 0x3a, 0xf3, 0x44, 0x80, 0x1c, 0x06, - 0x1a, 0xe3, 0xc8, 0x0d, 0x95, 0x03, 0x39, 0x5a, 0xb6, 0xc8, 0x20, 0x72, - 0x2a, 0xc0, 0xad, 0x92, 0x7c, 0xc1, 0xcf, 0xee, 0x68, 0x14, 0xde, 0x35, - 0x96, 0x1d, 0x58, 0x54, 0x9f, 0x8f, 0xf1, 0xfb, 0xfc, 0x64, 0xba, 0xbd, - 0x01, 0x01, 0x78, 0xb7, 0x97, 0xcc, 0x59, 0x82, 0x8e, 0x76, 0x2e, 0xa5, - 0x68, 0x73, 0x3f, 0x48, 0xb7, 0xbf, 0xf7, 0x7f, 0x57, 0x56, 0x9c, 0xc7, - 0xcc, 0xe8, 0x85, 0xdb, 0x2f, 0x52, 0xa1, 0xfe, 0x22, 0x99, 0xcf, 0xa4, - 0xd8, 0xc8, 0xc5, 0xa0, 0x25, 0xbf, 0x5c, 0x9f, 0x1a, 0x85, 0x6e, 0x56, - 0xa7, 0x5e, 0x3e, 0x86, 0xfa, 0x2f, 0xa2, 0x17, 0xed, 0x64, 0xce, 0x5c, - 0xce, 0x7c, 0x09, 0x5a, 0xe3, 0x41, 0x2a, 0x57, 0x15, 0xd7, 0xac, 0xd9, - 0x24, 0x98, 0xb3, 0x2b, 0x03, 0x0e, 0x2b, 0x8f, 0x28, 0xe0, 0x70, 0x6d, - 0x7a, 0xeb, 0xb2, 0x6b, 0xcb, 0x0e, 0x1a, 0x44, 0xed, 0x9b, 0x3a, 0x5c, - 0xee, 0x60, 0x37, 0xcf, 0xb4, 0xa4, 0x38, 0x4b, 0xf1, 0x2e, 0xa6, 0xee, - 0x7e, 0xa2, 0x61, 0x25, 0x89, 0x10, 0x84, 0xa3, 0x9b, 0x30, 0x6d, 0x62, - 0x9a, 0x64, 0x62, 0x82, 0xcd, 0xfc, 0xf2, 0x47, 0x50, 0x8c, 0x41, 0x18, - 0x58, 0x81, 0x3e, 0x32, 0xc7, 0x04, 0xd6, 0x2c, 0xb0, 0x5a, 0x85, 0x80, - 0x09, 0x76, 0xba, 0x90, 0xe2, 0x2b, 0xc3, 0x32, 0xf0, 0xe5, 0xed, 0xdc, - 0x55, 0x39, 0xd2, 0xab, 0x4b, 0xc6, 0x19, 0xfb, 0xbe, 0xf9, 0xc0, 0x4a, - 0x92, 0x18, 0x46, 0x5c, 0x77, 0xf5, 0x7f, 0xac, 0x11, 0xdb, 0x9c, 0x53, - 0xf1, 0xd9, 0x5f, 0xb1, 0x04, 0x3f, 0x75, 0x26, 0xab, 0x22, 0xd8, 0x1e, - 0x9e, 0x1e, 0x30, 0x73, 0x54, 0xad, 0x3e, 0x66, 0x94, 0x94, 0x55, 0xe7, - 0xc7, 0x51, 0x3e, 0xa6, 0x91, 0x52, 0x02, 0x56, 0xba, 0xed, 0x4a, 0x60, - 0x3a, 0x2b, 0x3e, 0xc4, 0xce, 0xd0, 0xf9, 0xd7, 0x47, 0x06, 0x92, 0x5a, - 0x78, 0x90, 0x8a, 0x09, 0x53, 0x17, 0x4d, 0xf2, 0x5c, 0x6d, 0x3c, 0xad, - 0x8a, 0xe3, 0x31, 0xe8, 0xfd, 0x00, 0xdb, 0x63, 0x6f, 0x6d, 0x2e, 0x61, - 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x61, 0x6b, 0x1c, 0xfb, 0xd0, 0x84, 0xfc, 0xf6, 0xdf, 0x84, - 0xc7, 0x3d, 0x97, 0x62, 0x33, 0x4b, 0x7a, 0x73, 0x32, 0x97, 0xda, 0xe4, - 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xee, 0x00, 0x0f, 0x77, 0x0e, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x0b, 0x34, 0x34, 0x34, - 0x15, 0x34, 0x08, 0x34, 0x33, 0x09, 0x01, 0x83, 0xdc, 0xc4, 0xea, 0x61, - 0x0c, 0x2a, 0x01, 0x7c, 0xca, 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, - 0x56, 0xcb, 0x20, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, - 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, - 0xed, 0x75, 0x5e, 0xc0, 0x39, 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, - 0xbb, 0x76, 0xf1, 0xc5, 0x1c, 0xff, 0xec, 0x68, 0x74, 0x74, 0x70, 0xd0, - 0x0b, 0x39, 0x81, 0x5c, 0x18, 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, - 0x7a, 0x77, 0x58, 0x07, 0x28, 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, - 0xd8, 0x07, 0x09, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, - 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x08, 0x81, - 0x07, 0x0b, 0x34, 0x34, 0x34, 0x15, 0x34, 0x08, 0x34, 0x33, 0x09, 0x01, - 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, 0x7c, 0xca, 0x21, 0x9c, - 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, 0xda, 0x39, 0xa3, 0xee, - 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, - 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, 0xc0, 0x39, 0x77, 0x37, - 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, 0xc5, 0x1c, 0xff, 0xec, - 0x68, 0x74, 0x70, 0x73, 0xd0, 0x0b, 0x39, 0x81, 0x5c, 0x18, 0x7d, 0x83, - 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, 0x07, 0x28, 0xdc, 0x47, - 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, - 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x63, 0x6f, 0x6d, 0x2e, - 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x09, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x0f, 0xfb, 0x00, 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x01, 0x06, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xce, 0x00, - 0x0f, 0xe7, 0x0f, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0x1d, 0x3d, - 0x99, 0x45, 0x23, 0x73, 0xf5, 0xb8, 0xec, 0x97, 0xe1, 0xc2, 0x84, 0xee, - 0xec, 0xa3, 0xbc, 0x53, 0xf3, 0xcd, 0x09, 0x18, 0x03, 0x34, 0x01, 0x1c, - 0xfb, 0xd0, 0x84, 0xfc, 0xf6, 0xdf, 0x84, 0xc7, 0x3d, 0x97, 0x62, 0x33, - 0x4b, 0x7a, 0x73, 0x32, 0x97, 0xda, 0xe4, 0x08, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -unsigned int ios8_inet_keychain_2_db_len = 118784; diff --git a/OSX/sec/securityd/Regressions/sd-10-policytree.m b/OSX/sec/securityd/Regressions/sd-10-policytree.m deleted file mode 100644 index 682f8305..00000000 --- a/OSX/sec/securityd/Regressions/sd-10-policytree.m +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2009,2012 Apple Inc. All Rights Reserved. - */ - -#include - -#include -#include -#include - -#include "securityd_regressions.h" - -#define DUMP_POLICY_TREE 0 - -int verbose = DUMP_POLICY_TREE; - -static bool randomly_add_children(policy_tree_t node, void *ctx) { - int i, count; - uint32_t rnd = arc4random(); -#if 1 - count = rnd % 7; - if (count > 4) - count = 0; -#else - if (rnd < 0x40000000) { - count = 1; - } else if (rnd < 0x80000000) { - count = 2; - } else if (rnd < 0xc0000000) { - count = 3; - } else if (rnd < 0xf0000000) { - count = 4; - } else { - count = 0; - } -#endif - -#if DUMP_POLICY_TREE - diag("node %p add %d children", node, count); -#endif - for (i = 1; i <= count ; ++i) { - policy_tree_add_child(node, &oidAnyPolicy, NULL); - //diag("node %p %d/%d children added", node, i, count); - //policy_tree_dump(node); - } - return count != 0; -} - -static void tests(void) -{ - policy_qualifier_t p_q = NULL; - policy_tree_t tree; - ok(tree = policy_tree_create(&oidAnyPolicy, p_q), - "create tree root"); - if (verbose) policy_tree_dump(tree); - -#if 0 - int i, count = 4; - for (i = 1; i <= count ; ++i) { - policy_tree_add_child(tree, &oidAnyPolicy, NULL); -#if DUMP_POLICY_TREE - diag("node %p %d/%d children added", tree, i, count); -#endif - } - policy_tree_dump(tree); -#else - int depth; - for (depth = 0; tree && depth < 7; ++depth) { - bool added = false; - while (!added) { - added = policy_tree_walk_depth(tree, depth, - randomly_add_children, NULL); -#if DUMP_POLICY_TREE - diag("depth: %d %s", depth, - (added ? "added children" : "no children added")); -#endif - } - if (verbose) policy_tree_dump(tree); -#if DUMP_POLICY_TREE - diag("prune_childless depth: %d", depth); -#endif - policy_tree_prune_childless(&tree, depth); - if (verbose) { - if (tree) - policy_tree_dump(tree); - else { -#if DUMP_POLICY_TREE - diag("tree empty at depth: %d", depth); -#endif - break; - } - } - } -#endif - if (tree) - policy_tree_prune(&tree); -} - -int sd_10_policytree(int argc, char *const *argv) -{ - plan_tests(1); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-01-items.m b/OSX/sec/securityd/Regressions/secd-01-items.m deleted file mode 100644 index ffd19e82..00000000 --- a/OSX/sec/securityd/Regressions/secd-01-items.m +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include "secd_regressions.h" - -#include -#include - -#include -#include - -#include - -#include "SecdTestKeychainUtilities.h" - -#if USE_KEYSTORE -#include "OSX/utilities/SecAKSWrappers.h" - -int secd_01_items(int argc, char *const *argv) -{ - plan_tests(24 + kSecdTestSetupTestCount); - - secd_test_setup_testviews(); // if running all tests get the test views setup first - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_01_items", NULL); - - /* custom keybag */ - keybag_handle_t keybag; - keybag_state_t state; - char *passcode="password"; - int passcode_len=(int)strlen(passcode); - - ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(keybag); - - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - - - SecKeychainDbReset(NULL); - - /* Creating a password */ - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - const void *keys[] = { - kSecClass, - kSecAttrServer, - kSecAttrAccount, - kSecAttrPort, - kSecAttrProtocol, - kSecAttrAuthenticationType, - kSecReturnData, - kSecValueData - }; - const void *values[] = { - kSecClassInternetPassword, - CFSTR("members.spamcop.net"), - CFSTR("smith"), - eighty, - CFSTR("http"), - CFSTR("dflt"), - kCFBooleanTrue, - pwdata - }; - - CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - - - is_status(SecItemAdd(item, NULL), errSecInteractionNotAllowed, "add internet password while locked"); - - /* unlock */ - ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "unlock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - - ok_status(SecItemAdd(item, NULL), "add internet password, while unlocked"); - - - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - - is_status(SecItemAdd(item, NULL), errSecInteractionNotAllowed, - "add internet password again, while locked"); - - /* unlock */ - ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "unlock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - - is_status(SecItemAdd(item, NULL), errSecDuplicateItem, - "add internet password again, while unlocked"); - - CFTypeRef results = NULL; - /* Create a dict with all attrs except the data. */ - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - (array_size(keys)) - 1, NULL, NULL); - ok_status(SecItemCopyMatching(query, &results), "find internet password, while unlocked "); - if (results) { - CFRelease(results); - results = NULL; - } - - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - - is_status(SecItemCopyMatching(query, &results), errSecInteractionNotAllowed, "find internet password, while locked "); - - /* Reset keybag and custom $HOME */ - SecItemServerResetKeychainKeybag(); - SetCustomHomePath(NULL); - SecKeychainDbReset(NULL); - - - CFReleaseNull(pwdata); - CFReleaseNull(eighty); - CFReleaseSafe(item); - CFReleaseSafe(query); - - return 0; -} - -#else - -int secd_01_items(int argc, char *const *argv) -{ - plan_tests(1); - - todo("Not yet working in simulator"); - -TODO: { - ok(false); -} - - /* not implemented in simulator (no keybag) */ - return 0; -} -#endif - diff --git a/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m b/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m deleted file mode 100644 index e6e17a34..00000000 --- a/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "secd_regressions.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#if TARGET_OS_IPHONE && USE_KEYSTORE -#include "OSX/utilities/SecAKSWrappers.h" - -#include "SecdTestKeychainUtilities.h" - -#include "ios6_1_keychain_2_db.h" - -static OSStatus query_one(void) -{ - OSStatus ok; - - /* querying a password */ - const void *keys[] = { - kSecClass, - kSecAttrAccessGroup, - }; - const void *values[] = { - kSecClassGenericPassword, - CFSTR("test"), - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - CFTypeRef results = NULL; - - ok = SecItemCopyMatching(query, &results); - - CFReleaseSafe(results); - CFReleaseSafe(query); - - return ok; -} - - - -static void *do_query(void *arg) -{ - /* querying a password */ - const void *keys[] = { - kSecClass, - kSecAttrAccessGroup, - }; - const void *values[] = { - kSecClassGenericPassword, - CFSTR("test"), - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - CFTypeRef results = NULL; - - for(int i=0;i<20;i++) - verify_action(SecItemCopyMatching(query, &results)==errSecInteractionNotAllowed, CFReleaseSafe(query); return (void *)-1); - - CFReleaseSafe(query); - - return NULL; -} - -static void *do_sos(void *arg) -{ - - for(int i=0;i<20;i++) - verify_action(SOSCCThisDeviceIsInCircle_Server(NULL)==-1, return (void *)-1); - - return NULL; -} - - -#define N_THREADS 10 - -void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); -CFArrayRef SecAccessGroupsGetCurrent(void); - -int secd_02_upgrade_while_locked(int argc, char *const *argv) -{ - plan_tests(11 + N_THREADS + kSecdTestSetupTestCount); - - __block keybag_handle_t keybag; - __block keybag_state_t state; - char *passcode="password"; - int passcode_len=(int)strlen(passcode); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_02_upgrade_while_locked", ^{ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - writeFile(keychain_path, ios6_1_keychain_2_db, ios6_1_keychain_2_db_len); - - /* custom notification */ - SecItemServerSetKeychainChangedNotification("com.apple.secdtests.keychainchanged"); - - /* Create and lock custom keybag */ - ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(keybag); - - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - }); - - CFReleaseSafe(keychain_path_cf); - }); - - CFArrayRef old_ag = CFRetainSafe(SecAccessGroupsGetCurrent()); - CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); - CFArrayAppendValue(test_ag, CFSTR("test")); - SecAccessGroupsSetCurrent(test_ag); - - pthread_t query_thread[N_THREADS]; - pthread_t sos_thread; - void *query_err[N_THREADS] = {NULL,}; - void *sos_err = NULL; - - for(int i=0; i -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include "SecdTestKeychainUtilities.h" - -static OSStatus do_query(void) -{ - /* querying a password */ - const void *keys[] = { - kSecClass, - kSecAttrServer, - kSecReturnAttributes, - }; - const void *values[] = { - kSecClassInternetPassword, - CFSTR("corrupt.spamcop.net"), - kCFBooleanTrue, - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - CFTypeRef results = NULL; - - OSStatus err = SecItemCopyMatching(query, &results); - CFReleaseNull(query); - return err; -} - -static void *do_add(void *arg) -{ - int tid=(int)(arg); - - for(int i=0;i<20;i++) { - /* Creating a password */ - SInt32 v_eighty = (tid+1)*1000+i; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - const void *keys[] = { - kSecClass, - kSecAttrServer, - kSecAttrAccount, - kSecAttrPort, - kSecAttrProtocol, - kSecAttrAuthenticationType, - kSecValueData - }; - const void *values[] = { - kSecClassInternetPassword, - CFSTR("members.spamcop.net"), - CFSTR("smith"), - eighty, - CFSTR("http"), - CFSTR("dflt"), - pwdata - }; - - CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - - ok_status(SecItemAdd(item, NULL), "add internet password"); - CFReleaseNull(item); - CFReleaseNull(eighty); - CFReleaseNull(pwdata); - } - - return NULL; -} - - -#define N_THREADS 10 - -static const char *corrupt_item_sql = "UPDATE inet SET data=X'12345678' WHERE rowid=1"; - - -int secd_03_corrupted_items(int argc, char *const *argv) -{ - plan_tests(4 + N_THREADS*21 + kSecdTestSetupTestCount); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_03_corrupted_items", NULL); - - /* add a password */ - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrServer, CFSTR("corrupt.spamcop.net")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); - CFDictionaryAddValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "add internet password"); - - /* corrupt the password */ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - /* Create a new keychain sqlite db */ - sqlite3 *db; - - is(sqlite3_open(keychain_path, &db), SQLITE_OK, "create keychain"); - is(sqlite3_exec(db, corrupt_item_sql, NULL, NULL, NULL), SQLITE_OK, - "corrupting keychain item1"); - - }); - - pthread_t add_thread[N_THREADS]; - void *add_err[N_THREADS] = {NULL,}; - - for(int i=0; i -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include "SecdTestKeychainUtilities.h" - -/* Corrupt 1st and 3rd item */ -static const char *corrupt_item_sql = "UPDATE inet SET data=X'12345678' WHERE rowid=1 OR rowid=3"; - -int secd_04_corrupted_items(int argc, char *const *argv) -{ - plan_tests(11 + kSecdTestSetupTestCount); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_04_corrupted_items", NULL); - - /* add a password */ - CFTypeRef ref1 = NULL; - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrServer, CFSTR("corrupt.spamcop.net")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); - CFDictionaryAddValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); - CFDictionaryAddValue(query, kSecValueData, pwdata); - CFDictionaryAddValue(query, kSecReturnPersistentRef, kCFBooleanTrue); - ok_status(SecItemAdd(query, &ref1), "add internet password port 80"); - - /* add another one */ - CFTypeRef ref2 = NULL; - int v_eighty_one = 81; - CFNumberRef eighty_one = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty_one); - CFDictionarySetValue(query, kSecAttrPort, eighty_one); - ok_status(SecItemAdd(query, &ref2), "add internet password port 81"); - - /* add another one */ - CFTypeRef ref3 = NULL; - int v_eighty_two = 82; - CFNumberRef eighty_two = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty_two); - CFDictionarySetValue(query, kSecAttrPort, eighty_two); - ok_status(SecItemAdd(query, &ref3), "add internet password port 82"); - - /* remove the data, and return key from the query */ - CFDictionaryRemoveValue(query, kSecValueData); - CFDictionaryRemoveValue(query, kSecReturnPersistentRef); - - /* update second password to conflict with first one */ - CFDictionarySetValue(query, kSecAttrPort, eighty_one); - CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(attributes, kSecAttrPort, eighty); - is_status(SecItemUpdate(query, attributes), errSecDuplicateItem, "update internet password port 80 to 81"); - - /* corrupt the first and 3rd password */ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - /* Create a new keychain sqlite db */ - sqlite3 *db; - - is(sqlite3_open(keychain_path, &db), SQLITE_OK, "open keychain"); - is(sqlite3_exec(db, corrupt_item_sql, NULL, NULL, NULL), SQLITE_OK, - "corrupting keychain items"); - - }); - - /* Try the update again */ - ok_status(SecItemUpdate(query, attributes), "update internet password port 80 to 81 (after corrupting item)"); - - /* query the persistent ref */ - CFTypeRef ref = NULL; - CFDictionarySetValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecReturnPersistentRef, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &ref), "Item 80 found"); - - CFDictionaryRemoveValue(query, kSecReturnPersistentRef); - ok(CFEqual(ref, ref2), "persistent ref of item 2"); - - CFReleaseNull(attributes); - - /* Update the 3rd item (82) */ - CFDictionarySetValue(query, kSecAttrPort, eighty_two); - - attributes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(attributes, kSecAttrLabel, CFSTR("This is the 3rd password")); - is_status(SecItemUpdate(query, attributes), errSecItemNotFound, "update internet password port 82 (after corrupting item)"); - - CFDictionarySetValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "re-adding internet password port 82 (after corrupting item)"); - CFReleaseNull(pwdata); - CFReleaseNull(attributes); - CFReleaseNull(query); - CFReleaseNull(eighty); - CFReleaseNull(eighty_one); - CFReleaseNull(eighty_two); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-05-corrupted-items.m b/OSX/sec/securityd/Regressions/secd-05-corrupted-items.m deleted file mode 100644 index 756ddb70..00000000 --- a/OSX/sec/securityd/Regressions/secd-05-corrupted-items.m +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - - -#import "secd_regressions.h" - -#import -#import -#import -#import -#import -#import - -#import - -#import - -#import - -#import -#import -#import -#import - -#import "SecdTestKeychainUtilities.h" - -#define N_ITEMS (100) -#define N_THREADS (10) -#define N_ADDS (20) - -static void *do_add(void *arg) -{ - int tid=(int)(arg); - - for(int i=0;i -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include -#include - -#include "secd_regressions.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static void tests(void) -{ - - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFSetRef initialSyncViews = SOSViewCopyViewSet(kViewSetInitial); - CFMutableSetRef alwaysOnViews = SOSViewCopyViewSet(kViewSetAlwaysOn); - CFSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault); - int initialSyncViewCount = (int) CFSetGetCount(initialSyncViews); - CFReleaseNull(initialSyncViews); - CFSetRef backupSyncViews = SOSViewCopyViewSet(kViewSetRequiredForBackup); - int backupSyncViewCount = (int) CFSetGetCount(backupSyncViews); - CFReleaseNull(backupSyncViews); - int expectedStartupViewCount; - - if(initialSyncViewCount == 0) { - CFSetUnion(alwaysOnViews, defaultViews); - expectedStartupViewCount = (int) CFSetGetCount(alwaysOnViews); - } else { - CFMutableSetRef isViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, initialSyncViews); - CFSetUnion(isViews, backupSyncViews); - expectedStartupViewCount = (int) CFSetGetCount(isViews); - CFReleaseNull(isViews); - } - CFReleaseNull(alwaysOnViews); - CFReleaseNull(defaultViews); - - - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("AliceAccount"),CFSTR("TestType") ); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("BobAccount"),CFSTR("TestType") ); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Join circle: %@", error); - ok(SOSAccountCheckHasBeenInSync_wTxn(alice_account), "Alice account initial sync done"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - if(initialSyncViewCount > 0) { - ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); - } - CFSetRef bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); - is(CFSetGetCount(bob_viewSet), expectedStartupViewCount, "bob's initial view set should be just the initial sync and backup views"); - CFReleaseNull(bob_viewSet); - - if(initialSyncViewCount > 0) { - ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); - } - - SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); - - if(initialSyncViewCount > 0) { - bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); - is(CFSetGetCount(bob_viewSet), backupSyncViewCount, "bob's initial view set should be just the back up"); - CFReleaseNull(bob_viewSet); - } else { - ok(true, "don't mess with the total test count"); - } - bob_account = nil; - alice_account = nil; - - SOSDataSourceFactoryRelease(test_factory); - - SOSTestCleanup(); -} - -int secd_100_initialsync(int argc, char *const *argv) -{ - plan_tests(33); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m b/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m deleted file mode 100644 index 8fe1cb2c..00000000 --- a/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m +++ /dev/null @@ -1,178 +0,0 @@ -// -// secd-130-other-peer-views.m -// sec -// -// Created by Mitch Adler on 7/9/16. -// -// - -#include -#include - -#include "secd_regressions.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include "SecdTestKeychainUtilities.h" - -#include "SOSAccountTesting.h" - -#include "keychain/SecureObjectSync/SOSAccount.h" - -#define kAccountPasswordString ((uint8_t*) "FooFooFoo") -#define kAccountPasswordStringLen 10 - -static void tests(void) { - CFErrorRef error = NULL; - - // Unretained aliases. - CFDataRef cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFMutableDictionaryRef cfchanges = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetRef initialSyncViews = SOSViewCopyViewSet(kViewSetInitial); - int initialSyncViewCount = (int) CFSetGetCount(initialSyncViews); - CFReleaseNull(initialSyncViews); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); - - CFArrayRef aView = CFArrayCreateForCFTypes(kCFAllocatorDefault, - kSOSViewPCSMasterKey, - NULL); - - CFArrayRef wifiView = CFArrayCreateForCFTypes(kCFAllocatorDefault, - kSOSViewWiFi, - NULL); - - CFArrayRef otherView = CFArrayCreateForCFTypes(kCFAllocatorDefault, - kSOSViewOtherSyncable, - NULL); - - CFArrayRef otherAndWifiViews = CFArrayCreateForCFTypes(kCFAllocatorDefault, - kSOSViewWiFi, - kSOSViewOtherSyncable, - NULL); - - is(SOSAccountPeersHaveViewsEnabled(carole_account, aView, &error), NULL, "Peer views empty (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, aView, &error), kCFBooleanFalse, "Peer views empty (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies too (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(david_account, &error), "David Applies too (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); - - is(SOSAccountPeersHaveViewsEnabled(carole_account, aView, &error), NULL, "Peer views empty (%@)", error); - CFReleaseNull(error); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 3, "See three applicants %@ (%@)", applicants, error); - CFReleaseNull(error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 5, "updates"); - - // Make all views work buy finishing initial sync. - SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); - SOSAccountPeerGotInSync_wTxn(carole_account, alice_account.peerInfo); - SOSAccountPeerGotInSync_wTxn(david_account, alice_account.peerInfo); - - int changeCount = (initialSyncViewCount) ? 4 : 1; - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), changeCount, "updates"); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, aView, &error), kCFBooleanTrue, "Peer views empty (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, wifiView, &error), kCFBooleanFalse, "Peer views empty (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountUpdateView_wTxn(alice_account, kSOSViewWiFi, kSOSCCViewEnable, &error), "Enable view (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountUpdateView_wTxn(bob_account, kSOSViewOtherSyncable, kSOSCCViewEnable, &error), "Enable view (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, wifiView, &error), kCFBooleanFalse, "Wifi view for Alice (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, otherView, &error), kCFBooleanTrue, "other view for Alice (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(alice_account, otherAndWifiViews, &error), kCFBooleanFalse, "both for Alice (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(bob_account, wifiView, &error), kCFBooleanTrue, "Wifi view for Bob (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(bob_account, otherView, &error), kCFBooleanFalse, "other view for Bob (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(bob_account, otherAndWifiViews, &error), kCFBooleanFalse, "both for Bob (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(carole_account, wifiView, &error), kCFBooleanTrue, "Wifi view for Carole (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(carole_account, otherView, &error), kCFBooleanTrue, "other view for Carole (%@)", error); - CFReleaseNull(error); - - is(SOSAccountPeersHaveViewsEnabled(carole_account, otherAndWifiViews, &error), kCFBooleanTrue, "both for Carole (%@)", error); - CFReleaseNull(error); - - CFReleaseNull(aView); - CFReleaseNull(wifiView); - CFReleaseNull(otherView); - CFReleaseNull(otherAndWifiViews); - - SOSTestCleanup(); -} - -int secd_130_other_peer_views(int argc, char *const *argv) -{ - plan_tests(72); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - secd_test_clear_testviews(); - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-154-engine-backoff.m b/OSX/sec/securityd/Regressions/secd-154-engine-backoff.m deleted file mode 100644 index e75660d4..00000000 --- a/OSX/sec/securityd/Regressions/secd-154-engine-backoff.m +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" - -static int kTestTestCount = 10; -static int MAX_PENALTY_TIME = 32; - -struct monitor_traffic { - CFStringRef key; - int penalty_box; - int total_consecutive_attempts; - int last_write_timestamp; -}; - -static void clear_penalty(struct monitor_traffic *monitor){ - monitor->penalty_box = 0; - monitor->total_consecutive_attempts = 0; - monitor->last_write_timestamp = 0; -} -static int increase_penalty(int time){ - if(time == 32) - return time; - else if(time == 0) - return 1; - else - return (time * 2); -} - -static int decrease_penalty(int time){ - if(time == 0) - return time; - else if(time == 1) - return 0; - else - return (time/2); -} - -//calculate new penalty time based off time passed -static void calculate_new_penalty(struct monitor_traffic *monitor, int current_time){ - int difference = current_time - monitor->last_write_timestamp; - - while(difference){ - if(difference >= monitor->penalty_box * 2){ - monitor->penalty_box = decrease_penalty(monitor->penalty_box); - difference =- monitor->penalty_box *2; - } - else - break; - } -} - -static void keychain_changed_notification(struct monitor_traffic *monitor){ - clear_penalty(monitor); -} - -static void initialize_monitor(struct monitor_traffic *monitor){ - monitor->key = CFSTR("ak|alskdfj:a;lskdjf"); - monitor->penalty_box = 0; - monitor->total_consecutive_attempts = 0; - monitor->last_write_timestamp = 0; -} - -static int backoff_algorithm(CFArrayRef timestamps, struct monitor_traffic *monitor) -{ - __block int successful_writes = 0; - CFNumberRef timestamp; - - CFArrayForEachC(timestamps, timestamp) { - int current_time; - if(!CFNumberGetValue(timestamp, kCFNumberSInt32Type, ¤t_time)) - return successful_writes; - - if(monitor->last_write_timestamp == 0){ //successful default case, initially sending to another peer - successful_writes++; - } - else if(current_time == 0){ //keychain changed notification fired - keychain_changed_notification(monitor); - - } - else{ - if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts >= 4){ - monitor->penalty_box= increase_penalty(monitor->penalty_box); - monitor->total_consecutive_attempts++; - } - else if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts < 4 ){ - monitor->total_consecutive_attempts++; - if(monitor->penalty_box == 0) - successful_writes++; - } - else if((current_time - monitor->last_write_timestamp) >= (2*monitor->penalty_box)){ //we haven't written consecutively for 2* the penalty time - monitor->total_consecutive_attempts = 0; - calculate_new_penalty(monitor, current_time); - successful_writes++; - } - else if((current_time - monitor->last_write_timestamp) <= (2*monitor->penalty_box)){ //nonconsecutive write came in within the penalty time - monitor->penalty_box= increase_penalty(monitor->penalty_box); - if(monitor->last_write_timestamp != (current_time-1)) - monitor->total_consecutive_attempts = 0; - else - monitor->total_consecutive_attempts++; - } - } - if(current_time != 0) - monitor->last_write_timestamp = current_time; - } - - return successful_writes; -} - -static void tests(void) -{ - struct monitor_traffic *monitor = (struct monitor_traffic*)malloc(sizeof(struct monitor_traffic)); - initialize_monitor(monitor); - CFMutableArrayRef write_attempts = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFNumberRef timestamp = NULL; - int time; - -/* - * first test: peer continuously writes for 12 minutes - */ - for(int i = 1; i< 13; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - int successful_writes = backoff_algorithm(write_attempts, monitor); - ok(successful_writes == 5, "successfull writes should have only reached 5 minutes"); - ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should have maxed out to 32 minutes"); - - //reset monitor - initialize_monitor(monitor); - CFArrayRemoveAllValues(write_attempts); - -/* - * first test: peer continuously writes for 12 minutes, then backs off 2*(max penalty timeout) - */ - for(int i = 1; i< 13; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - time = 77; - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 109; - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - successful_writes = backoff_algorithm(write_attempts, monitor); - ok(successful_writes == 7, "successfull writes should have only reached 6"); //5 initial writes, then 1 write after enough time passes - ok(monitor->penalty_box == (MAX_PENALTY_TIME/4), "penalty box should have maxed out to 16 minutes"); - - //reset - initialize_monitor(monitor); - CFArrayRemoveAllValues(write_attempts); - -/* - * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets - */ - - for(int i = 1; i< 13; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - time = 76; //+ 32*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 108; //+ 16*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 124; //+ 8*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 132; //+ 4*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 136; //+ 2*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - time = 138; //+ 1*2 - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - - successful_writes = backoff_algorithm(write_attempts, monitor); - ok(successful_writes == 11, "successfull writes should have only reached 11"); - ok(monitor->penalty_box == 0, "penalty box should reset back to 0"); - - //reset - initialize_monitor(monitor); - CFArrayRemoveAllValues(write_attempts); - -/* - * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets - */ - - for(int i = 1; i< 13; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - time = 0; //flag that keychain changed notification fired - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - - for(int i = 1; i< 13; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - - successful_writes = backoff_algorithm(write_attempts, monitor); - ok(successful_writes == 10, "successfull writes should have only reached 10"); - ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should reset back to 0"); - - //reset - initialize_monitor(monitor); - CFArrayRemoveAllValues(write_attempts); - -/* - * first test: peer continuously writes for 5 minutes, then attempts to write again for another 5 minutes, the once much later - */ - for(int i = 1; i< 6; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - time = 40; - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - - for(int i = 100; i< 106; i++){ - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); - CFArrayAppendValue(write_attempts, timestamp); - CFReleaseNull(timestamp); - } - time = 250; - timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); - CFArrayAppendValue(write_attempts, timestamp); - - successful_writes = backoff_algorithm(write_attempts, monitor); - ok(successful_writes == 12, "successfull writes should have only reached 10"); - ok(monitor->penalty_box == 0, "penalty box should reset back to 0"); -} - -int secd_154_engine_backoff(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m b/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m deleted file mode 100644 index 17404974..00000000 --- a/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m +++ /dev/null @@ -1,171 +0,0 @@ -// -// secd-155-otrnegotiationmonitor.m -// secdtests_ios -// -// Created by Michelle Auricchio on 6/5/17. -// - -#import -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" -#include "keychain/SecureObjectSync/SOSTransportMessage.h" -#include "keychain/SecureObjectSync/SOSPeerOTRTimer.h" - -#import "SOSAccountTesting.h" -#import "SOSTransportTestTransports.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include - -#include -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" -#import "SOSTransportTestTransports.h" -#include "SOSTestDevice.h" -#include "SOSTestDataSource.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - - -static void tests(void) -{ - CFErrorRef error = NULL; - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(NULL != alice_account, "Alice Created"); - ok(NULL != bob_account, "Bob Created"); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL); - SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL; - - ok(false == SOSEngineHandleCodedMessage(alice_account, alice_engine, (__bridge CFStringRef)bob_account.peerID, NULL, NULL)); - - SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL); - SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL; - - ok(false == SOSEngineHandleCodedMessage(bob_account, bob_engine, (__bridge CFStringRef)alice_account.peerID, NULL, NULL)); - - /* new routines to test */ - __block NSString *bobID = bob_account.peerID; - __block NSString *aliceID = alice_account.peerID; - - SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { - ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID)); - ok(false == SOSPeerTimerForPeerExist(alice_peer)); - ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID)); - }); - - SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { - ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); - ok(false == SOSPeerTimerForPeerExist(bob_peer)); - ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); - }); - - //creating test devices - CFIndex version = 0; - - // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); - CFSetRef views = SOSViewsCopyTestV2Default(); - CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef deviceID; - CFArrayForEachC(deviceIDs, deviceID) { - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); - CFArrayAppendValue(peerMetas, peerMeta); - CFReleaseNull(peerMeta); - } - - CFReleaseNull(views); - CFArrayForEachC(deviceIDs, deviceID) { - SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); - SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - - if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ - alice_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); - } - else{ - bob_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); - } - - CFReleaseNull(device); - } - CFReleaseNull(deviceIDs); - CFReleaseNull(peerMetas); - - SOSUnregisterAllTransportMessages(); - CFArrayRemoveAllValues(message_transports); - - ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); - - ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); - - // ids_test_sync(alice_account, bob_account); -} - -int secd_155_otr_negotiation_monitor(int argc, char *const *argv) -{ - plan_tests(44); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-156-timers.m b/OSX/sec/securityd/Regressions/secd-156-timers.m deleted file mode 100644 index e5c49050..00000000 --- a/OSX/sec/securityd/Regressions/secd-156-timers.m +++ /dev/null @@ -1,100 +0,0 @@ -// -// secd-156-timers.m -// secdRegressions -// - -#import - -#include -#include - -#include -#include -#include - -#include "secd_regressions.h" -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 3; - - -static void testPeerRateLimiterSendNextMessageWithRetain(CFStringRef peerid, CFStringRef accessGroup) -{ - ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); -} - -static void testOTRTimer() -{ - dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); - - CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); - dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-otrtimer2", DISPATCH_QUEUE_SERIAL); - __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); - - dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); - dispatch_source_set_event_handler(timer2, ^{ - testPeerRateLimiterSendNextMessageWithRetain(peeridRetained, CFSTR("NoAttribute")); - dispatch_semaphore_signal(sema2); - }); - dispatch_resume(timer2); - dispatch_source_set_cancel_handler(timer2, ^{ - CFReleaseSafe(peeridRetained); - }); - - CFReleaseNull(peeridRetained); - dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); - -} - -static void testOTRTimerWithRetain(CFStringRef peerid) -{ - ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); -} - -static void testRateLimitingTimer() - -{ - dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); - - CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); - - dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-ratelimit12", DISPATCH_QUEUE_SERIAL); - __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); - - dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); - dispatch_source_set_event_handler(timer2, ^{ - testOTRTimerWithRetain(peeridRetained); - dispatch_semaphore_signal(sema2); - }); - dispatch_resume(timer2); - - dispatch_source_set_cancel_handler(timer2, ^{ - CFReleaseSafe(peeridRetained); - }); - - CFReleaseNull(peeridRetained); - dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); - -} -static void tests(){ - - testOTRTimer(); - testRateLimitingTimer(); -} - -int secd_156_timers(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m b/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m deleted file mode 100644 index 8987682f..00000000 --- a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - - -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import - -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" -#include "server_security_helpers.h" - -static int ckmirror_row_exists = 0; -static int ckmirror_row_callback(void* unused, int count, char **data, char **columns) -{ - ckmirror_row_exists = 1; - for (int i = 0; i < count; i++) { - if(strcmp(columns[i], "ckzone") == 0) { - is(strcmp(data[i], "ckzone"), 0, "Data is expected 'ckzone'"); - } - } - - return 0; -} - -static void -keychain_upgrade(bool musr, const char *dbname) -{ - OSStatus res; - - secd_test_setup_temp_keychain(dbname, NULL); - -#if TARGET_OS_IOS - if (musr) - SecSecuritySetMusrMode(true, 502, 502); -#endif - -#if TARGET_OS_IPHONE - /* - * Check system keychain migration - */ - - res = SecItemAdd((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"system-label-me", - (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, - (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], - }, NULL); - is(res, 0, "SecItemAdd(system)"); -#endif - - /* - * Check user keychain - */ - - res = SecItemAdd((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"user-label-me", - (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], - }, NULL); - is(res, 0, "SecItemAdd(user)"); - - NSString *keychain_path = CFBridgingRelease(__SecKeychainCopyPath()); - - // Add a row to a non-item table - /* Create a new keychain sqlite db */ - sqlite3 *db = NULL; - - is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); - is(sqlite3_exec(db, "INSERT into ckmirror VALUES(\"ckzone\", \"importantuuid\", \"keyuuid\", 0, \"asdf\", \"qwer\", \"ckrecord\", 0, 0, NULL, NULL, NULL);", NULL, NULL, NULL), SQLITE_OK, "row added to ckmirror table"); - is(sqlite3_close(db), SQLITE_OK, "close db"); - - SecKeychainDbReset(^{ - - /* Create a new keychain sqlite db */ - sqlite3 *db; - - is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "create keychain"); - is(sqlite3_exec(db, "UPDATE tversion SET minor = minor - 1", NULL, NULL, NULL), SQLITE_OK, - "\"downgrade\" keychain"); - is(sqlite3_close(db), SQLITE_OK, "close db"); - }); - -#if TARGET_OS_IPHONE - res = SecItemCopyMatching((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"system-label-me", - (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, - }, NULL); - is(res, 0, "SecItemCopyMatching(system)"); -#endif - - res = SecItemCopyMatching((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"user-label-me", - }, NULL); - is(res, 0, "SecItemCopyMatching(user)"); - - char* err = NULL; - - is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); - is(sqlite3_exec(db, "select * from ckmirror;", ckmirror_row_callback, NULL, &err), SQLITE_OK, "row added to ckmirror table"); - is(sqlite3_close(db), SQLITE_OK, "close db"); - is(ckmirror_row_exists, 1, "SQLite found a row in the ckmirror table"); - -#if TARGET_OS_IOS - if (musr) - SecSecuritySetMusrMode(false, 501, -1); -#endif -} - -int -secd_20_keychain_upgrade(int argc, char *const *argv) -{ -#if TARGET_OS_IPHONE -#define have_system_keychain_tests 2 -#else -#define have_system_keychain_tests 0 -#endif - - plan_tests((kSecdTestSetupTestCount + 5 + have_system_keychain_tests + 8) * 2); - - CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); - - NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; - [newACL addObjectsFromArray:@[ - @"com.apple.private.system-keychain", - @"com.apple.private.syncbubble-keychain", - @"com.apple.private.migrate-musr-system-keychain", - ]]; - - SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); - - keychain_upgrade(false, "secd_20_keychain_upgrade"); - keychain_upgrade(true, "secd_20_keychain_upgrade-musr"); - - SecAccessGroupsSetCurrent(currentACL); - CFReleaseNull(currentACL); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-200-logstate.m b/OSX/sec/securityd/Regressions/secd-200-logstate.m deleted file mode 100644 index 4fe18f6b..00000000 --- a/OSX/sec/securityd/Regressions/secd-200-logstate.m +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -// -// secd-200-logstate.c -// sec -// - -#include - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -#define HOW_MANY_MINIONS 4 - -static bool SOSArrayForEachAccount(CFArrayRef accounts, bool (^operation)(SOSAccount* account)) { - __block bool retval = true; - CFArrayForEach(accounts, ^(const void *value) { - SOSAccount* account = (__bridge SOSAccount*) value; - retval &= operation(account); - }); - return retval; -} - - -static inline void FeedChangesToMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { - FeedChangesTo(changes, master_account); - SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { - FeedChangesTo(changes, account); - return true; - }); - FeedChangesTo(changes, master_account); - -} - - -static inline bool ProcessChangesOnceMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { - bool result = FillAllChanges(changes); - FeedChangesToMasterMinions(changes, master_account, minion_accounts); - return result; -} - -static inline int ProcessChangesForMasterAndMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { - int result = 0; - bool new_data = false; - do { - new_data = ProcessChangesOnceMasterMinions(changes, master_account, minion_accounts); - ++result; - } while (new_data); - return result; -} - -static bool MakeTheBigCircle(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFErrorRef *error) { - bool retval = SOSAccountResetToOffering_wTxn(master_account, error); - if(!retval) - return retval; - ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); - retval = SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { - bool localret = SOSAccountJoinCircles_wTxn(account, error); - ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); - return localret; - }); - require_quiet(retval, errOut); - CFArrayRef applicants = SOSAccountCopyApplicants(master_account, error); - retval = SOSAccountAcceptApplicants(master_account , applicants, error); - CFReleaseNull(applicants); - ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); -errOut: - return retval; -} - - -static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef namefmt, CFStringRef data_source_name, size_t howmany) - CF_FORMAT_FUNCTION(1, 0); - -static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef name, CFStringRef data_source_name, size_t howmany) { - CFMutableArrayRef accounts = CFArrayCreateMutable(kCFAllocatorDefault, howmany, &kCFTypeArrayCallBacks); - - for(size_t i = 0; i < howmany; i++) { - CFStringRef tmpname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%ld"), name, (long)i); - SOSAccount* tmp = CreateAccountForLocalChanges(tmpname, CFSTR("TestSource")); - CFArraySetValueAtIndex(accounts, i, (__bridge const void *)(tmp)); - CFReleaseNull(tmpname); - } - return accounts; -} - -static bool AssertAllCredentialsAndUpdate(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error) { - __block bool retval = SOSAccountAssertUserCredentialsAndUpdate(master_account, user_account, user_password, error); - ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); - retval &= SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { - CFReleaseNull(*error); - return SOSAccountAssertUserCredentialsAndUpdate(account, user_account, user_password, error); - }); - CFReleaseNull(*error); - - return retval; -} - -static void timeval_delta(struct timeval *delta, struct timeval *start, struct timeval *end) { - if(end->tv_usec >= start->tv_usec) { - delta->tv_usec = end->tv_usec - start->tv_usec; - } else { - end->tv_sec--; - end->tv_usec += 1000000; - delta->tv_usec = end->tv_usec - start->tv_usec; - } - delta->tv_sec = end->tv_sec - start->tv_sec; -} - -static void reportTime(int peers, void(^action)(void)) { - struct rusage start_rusage; - struct rusage end_rusage; - struct timeval delta_utime; - struct timeval delta_stime; - - getrusage(RUSAGE_SELF, &start_rusage); - action(); - getrusage(RUSAGE_SELF, &end_rusage); - timeval_delta(&delta_utime, &start_rusage.ru_utime, &end_rusage.ru_utime); - timeval_delta(&delta_stime, &start_rusage.ru_stime, &end_rusage.ru_stime); - - diag("AccountLogState for %d peers: %ld.%06d user %ld.%06d system", peers, - delta_utime.tv_sec, delta_utime.tv_usec, - delta_stime.tv_sec, delta_stime.tv_usec); -} - -static void tests(void) -{ - NSError* ns_error = nil; - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* master_account = CreateAccountForLocalChanges(CFSTR("master"), CFSTR("TestSource")); - CFArrayRef minion_accounts = CreateManyAccountsForLocalChanges(CFSTR("minion"), CFSTR("TestSource"), HOW_MANY_MINIONS); - - ok(AssertAllCredentialsAndUpdate(changes, master_account, minion_accounts, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - - secLogEnable(); - reportTime(1, ^{ - SOSAccountLogState(master_account); - }); - secLogDisable(); - - ok(MakeTheBigCircle(changes, master_account, minion_accounts, &error), "Get Everyone into the circle %@", error); - - diag("WHAT?"); - secLogEnable(); - reportTime(HOW_MANY_MINIONS+1, ^{ - SOSAccountLogState(master_account); - }); - SOSAccountLogViewState(master_account); - secLogDisable(); - - NSData* acctData = [master_account encodedData:&ns_error]; - diag("Account DER Size is %lu for %d peers", (unsigned long)[acctData length], HOW_MANY_MINIONS+1); - ns_error = nil; - - SOSAccountTrustClassic* trust = master_account.trust; - CFDataRef circleData = SOSCircleCopyEncodedData(trust.trustedCircle, kCFAllocatorDefault, &error); - diag("Circle DER Size is %ld for %d peers", CFDataGetLength(circleData), HOW_MANY_MINIONS+1); - CFReleaseNull(circleData); - CFReleaseNull(error); - - CFDataRef peerData = SOSPeerInfoCopyEncodedData(master_account.peerInfo, kCFAllocatorDefault, &error); - diag("Peer DER Size is %ld", CFDataGetLength(peerData)); - CFReleaseNull(peerData); - CFReleaseNull(error); - - CFReleaseNull(error); - CFReleaseNull(minion_accounts); - - SOSTestCleanup(); - -} - -int secd_200_logstate(int argc, char *const *argv) -{ - plan_tests(((HOW_MANY_MINIONS+1)*10 + 1)); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-201-coders.m b/OSX/sec/securityd/Regressions/secd-201-coders.m deleted file mode 100644 index 692150be..00000000 --- a/OSX/sec/securityd/Regressions/secd-201-coders.m +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -// -// secd_201_coders -// sec -// - -#include - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSEngine.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" -#include "SOSTestDevice.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static void tests(void) -{ - - __block CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); - CFReleaseNull(cfpassword); - - CFReleaseNull(error); - ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); - CFReleaseNull(cfwrong_password); - is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountHasCompletedInitialSync(alice_account), "Alice thinks she's completed initial sync"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - //creating test devices - CFIndex version = 0; - - // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); - CFSetRef views = SOSViewsCopyTestV2Default(); - CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef deviceID; - CFArrayForEachC(deviceIDs, deviceID) { - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); - CFArrayAppendValue(peerMetas, peerMeta); - CFReleaseNull(peerMeta); - } - - CFReleaseNull(views); - CFArrayForEachC(deviceIDs, deviceID) { - SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); - SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - - if([alice_account.peerID isEqual: (__bridge id) deviceID]){ - alice_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); - } - else{ - bob_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); - } - - CFReleaseNull(device); - } - CFReleaseNull(deviceIDs); - CFReleaseNull(peerMetas); - - SOSUnregisterAllTransportMessages(); - CFArrayRemoveAllValues(message_transports); - - - ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); - ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); - - alice_account = nil; - bob_account = nil; - - SOSTestCleanup(); - - - CFReleaseNull(changes); -} - -int secd_201_coders(int argc, char *const *argv) -{ - plan_tests(38); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-202-recoverykey.m b/OSX/sec/securityd/Regressions/secd-202-recoverykey.m deleted file mode 100644 index e00d57af..00000000 --- a/OSX/sec/securityd/Regressions/secd-202-recoverykey.m +++ /dev/null @@ -1,67 +0,0 @@ -// -// secd-202-recoverykey.c -// sec -// - -#import -#import - -#import - -#import - -#import -#import -#import - -#import "secd_regressions.h" -#import "SOSTestDataSource.h" -#import "SOSTestDevice.h" - -#import "SOSRegressionUtilities.h" -#import - -#import "SecdTestKeychainUtilities.h" - - -const int kTestRecoveryKeyCount = 3; - -static void testRecoveryKey(void) -{ - SecRecoveryKey *recoveryKey = NULL; - - recoveryKey = SecRKCreateRecoveryKeyWithError(@"AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW", NULL); - ok(recoveryKey, "got recovery key"); - - NSData *publicKey = SecRKCopyBackupPublicKey(recoveryKey); - ok(publicKey, "got publicKey"); -} - -const int kTestRecoveryKeyBasicNumberIterations = 100; -const int kTestRecoveryKeyBasicCount = 1 * kTestRecoveryKeyBasicNumberIterations; - -static void testRecoveryKeyBasic(void) -{ - NSString *recoveryKey = NULL; - NSError *error = NULL; - int n; - - for (n = 0; n < kTestRecoveryKeyBasicNumberIterations; n++) { - recoveryKey = SecRKCreateRecoveryKeyString(&error); - ok(recoveryKey, "SecRKCreateRecoveryKeyString: %@", error); - } -} - - -int secd_202_recoverykey(int argc, char *const *argv) -{ - plan_tests(kTestRecoveryKeyCount + kTestRecoveryKeyBasicCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - testRecoveryKeyBasic(); - - testRecoveryKey(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-21-transmogrify.m b/OSX/sec/securityd/Regressions/secd-21-transmogrify.m deleted file mode 100644 index a62a93c5..00000000 --- a/OSX/sec/securityd/Regressions/secd-21-transmogrify.m +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - - -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import - -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" -#include "server_security_helpers.h" - -int -secd_21_transmogrify(int argc, char *const *argv) -{ - plan_tests(kSecdTestSetupTestCount + 14); - -#if TARGET_OS_IOS - CFErrorRef error = NULL; - CFDictionaryRef result = NULL; - OSStatus res; - - CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); - - NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; - [newACL addObjectsFromArray:@[ - @"com.apple.private.system-keychain", - @"com.apple.private.syncbubble-keychain", - @"com.apple.private.migrate-musr-system-keychain", - @"com.apple.ProtectedCloudStorage", - ]]; - - SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); - - - secd_test_setup_temp_keychain("secd_21_transmogrify", NULL); - - /* - * Add to user keychain - */ - - res = SecItemAdd((CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"user-label-me", - (id)kSecValueData : [NSData dataWithBytes:"password" length:8] - }, NULL); - is(res, 0, "SecItemAdd(user)"); - - SecurityClient client = { - .task = NULL, - .accessGroups = (__bridge CFArrayRef)@[ - @"com.apple.ProtectedCloudStorage" - ], - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = true, - .uid = 502, - .inMultiUser = false, - .activeUser = 502, - }; - - is(_SecServerTransmogrifyToSystemKeychain(&client, &error), true, "_SecServerTransmogrifyToSystemKeychain: %@", error); - - CFDataRef musr = SecMUSRCreateActiveUserUUID(502); - - client.inMultiUser = true; - client.musr = musr; - - SecSecuritySetMusrMode(true, 502, 502); - - res = SecItemCopyMatching((CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"user-label-me", - (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, - (id)kSecReturnAttributes : (id)kCFBooleanTrue, - (id)kSecReturnData : @(YES) - }, (CFTypeRef *)&result); - is(res, 0, "SecItemCopyMatching(system)"); - - ok(isDictionary(result), "found item"); - if (isDictionary(result)) { - NSData *data = ((__bridge NSDictionary *)result)[@"musr"]; - ok([data isEqual:(__bridge id)SecMUSRGetSystemKeychainUUID()], "item is system keychain"); - - NSData* passwordData = [(__bridge NSDictionary*)result valueForKey:(id)kSecValueData]; - ok([passwordData isEqual:[NSData dataWithBytes:"password" length:8]], "no data found in transmogrified item"); - } else { - ok(0, "returned item is: %@", result); - } - CFReleaseNull(result); - - /* - * Check sync bubble - */ - - res = _SecItemAdd((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", - (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, - (id)kSecAttrAccount : @"pcs-label-me", - (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], - }, &client, NULL, NULL); - is(res, true, "SecItemAdd(user)"); - - res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"pcs-label-me", - (id)kSecReturnAttributes : (id)kCFBooleanTrue, - (id)kSecReturnData : @(YES), - }, &client, (CFTypeRef *)&result, &error); - is(res, true, "SecItemCopyMatching(system): %@", error); - - ok(isDictionary(result), "result is dictionary"); - ok([[(__bridge NSDictionary*)result valueForKey:(__bridge id)kSecValueData] isEqual:[NSData dataWithBytes:"some data" length:9]], "retrieved data matches stored data"); - - /* Check that data are in 502 active user keychain */ - ok (CFEqualSafe(((__bridge CFDataRef)((__bridge NSDictionary *)result)[@"musr"]), musr), "not in msr 502"); - - CFReleaseNull(result); - - - ok(_SecServerTransmogrifyToSyncBubble((__bridge CFArrayRef)@[@"com.apple.mailq.sync.xpc" ], client.uid, &client, &error), - "_SecServerTransmogrifyToSyncBubble: %@", error); - - CFReleaseNull(error); - - /* - * first check normal keychain - */ - - res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"pcs-label-me", - (id)kSecReturnAttributes : (id)kCFBooleanTrue, - }, &client, (CFTypeRef *)&result, &error); - is(res, true, "SecItemCopyMatching(active): %@", error); - - ok(isDictionary(result), "result is dictionary"); - CFReleaseNull(result); - - SecSecuritySetMusrMode(true, 503, 503); - - /* - * then syncbubble keychain - */ - - res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ - (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrAccount : @"pcs-label-me", - (id)kSecReturnAttributes : (id)kCFBooleanTrue, - (id)kSecUseSyncBubbleKeychain : @502, - }, &client, (CFTypeRef *)&result, &error); - is(res, true, "SecItemCopyMatching(syncbubble): %@", error); - ok(isDictionary(result), "result is dictionary"); - - CFReleaseNull(result); - - SecSecuritySetMusrMode(false, 501, -1); - - SecAccessGroupsSetCurrent(currentACL); - CFReleaseNull(currentACL); - - CFRelease(musr); -#else - plan_skip_all("not support on non TARGET_OS_IOS"); -#endif - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-210-keyinterest.m b/OSX/sec/securityd/Regressions/secd-210-keyinterest.m deleted file mode 100644 index 82e7c890..00000000 --- a/OSX/sec/securityd/Regressions/secd-210-keyinterest.m +++ /dev/null @@ -1,200 +0,0 @@ -// -// secd-210-keyinterest.m -// Security -// -// Created by Mitch Adler on 10/31/16. -// -// - -#import - -#include "secd_regressions.h" - -#import "CKDStore.h" -#import "CKDKVSProxy.h" -#import "CKDSimulatedStore.h" -#import "CKDSimulatedAccount.h" -#import "CKDAKSLockMonitor.h" - -#include "SOSCloudKeychainConstants.h" - -@interface CKDSimulatedLockMonitor : NSObject - -@property (readwrite) BOOL unlockedSinceBoot; -@property (readwrite) BOOL locked; - -@property (weak) NSObject* listener; - -+ (instancetype) monitor; - -- (instancetype) init; - -- (void) recheck; - -- (void) notifyListener; -- (void) connectTo: (NSObject*) listener; - -- (void) lock; -- (void) unlock; - -@end - - -@implementation CKDSimulatedLockMonitor - -+ (instancetype) monitor { - return [[CKDSimulatedLockMonitor alloc] init]; -} - -- (instancetype) init { - self = [super init]; - if (self) { - _locked = true; - _unlockedSinceBoot = false; - } - - [self notifyListener]; - - return self; -} - -- (void) recheck { -} - -- (void) notifyListener { - // Take a strong reference: - __strong __typeof(self.listener) listener = self.listener; - - if (listener) { - if (self.locked) { - [listener locked]; - } else { - [listener unlocked]; - } - } -} - -- (void) connectTo: (NSObject*) listener { - self.listener = listener; - [self notifyListener]; -} - -- (void) lock { - self.locked = true; - [self notifyListener]; -} -- (void) unlock { - self.locked = false; - self.unlockedSinceBoot = true; - [self notifyListener]; -} - - -@end - -@interface UbiqitousKVSProxy (Testing) -- (void) flush; -@end - -@implementation UbiqitousKVSProxy (Testing) -- (void) flush { - dispatch_semaphore_t sema = dispatch_semaphore_create(0); - - [self doAfterFlush:^{ - dispatch_semaphore_signal(sema); - }]; - - dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); -} -@end - -static void tests(void) { - CKDSimulatedStore* store = [CKDSimulatedStore simulatedInterface]; - CKDSimulatedAccount* account = [[CKDSimulatedAccount alloc] init]; - CKDSimulatedLockMonitor* monitor = [CKDSimulatedLockMonitor monitor]; - - NSString * testKey = @"TestKey"; - - UbiqitousKVSProxy * proxy = [UbiqitousKVSProxy withAccount:account - store:store - lockMonitor:monitor - persistence:[NSURL fileURLWithPath:@"/tmp/kvsPersistenceTestFile"]]; - - NSDictionary* interests = @{ [NSString stringWithUTF8String:kMessageKeyParameter]:@{ @"UnlockedKeys":@[ testKey ] } }; - NSString* accountID = @"Account1"; - - dispatch_sync([proxy ckdkvsproxy_queue], ^{ - [proxy registerKeys:interests forAccount:accountID]; - }); - - is([[account extractKeyChanges] count], (NSUInteger)0, "No changes yet"); - - [store remoteSetObject:@1 forKey:testKey]; - [proxy flush]; - - is([[account extractKeyChanges] count], (NSUInteger)0, "Still none while locked"); - - [monitor unlock]; - [proxy flush]; - - is([[account extractKeyChanges] count], (NSUInteger)1, "Notified after unlock"); - - [monitor lock]; - [monitor unlock]; - [proxy flush]; - - is([[account extractKeyChanges] count], (NSUInteger)0, "lock unlock and nothing changes"); - - [store remoteSetObject:@2 forKey:testKey]; - [proxy flush]; - - { - NSDictionary *changes = [account extractKeyChanges]; - is([changes count], (NSUInteger)1, "lock, nothing changes"); - is(changes[testKey], @2, "Sent second value"); - } - - [monitor lock]; - [store remoteSetObject:@3 forKey:testKey]; - [proxy flush]; - - is([[account extractKeyChanges] count], (NSUInteger)0, "Changes to Unlocked not when locked"); - - [monitor unlock]; - [proxy flush]; - - { - NSDictionary *changes = [account extractKeyChanges]; - is([changes count], (NSUInteger)1, "Change defered to after unlock"); - is(changes[testKey], @3, "Correct value"); - } - - dispatch_sync([proxy ckdkvsproxy_queue], ^{ - [proxy registerKeys:interests forAccount:accountID]; - }); - [proxy flush]; - - is([[account extractKeyChanges] count], (NSUInteger)0, "Same interests, no new data"); - - dispatch_sync([proxy ckdkvsproxy_queue], ^{ - [proxy registerKeys:interests forAccount:@"different"]; - }); - [proxy flush]; - - { - NSDictionary *changes = [account extractKeyChanges]; - is([changes count], (NSUInteger)1, "New account, same interests, new data"); - is(changes[testKey], @3, "Latest value for new data"); - } - -} - - -int secd_210_keyinterest(int argc, char *const *argv) -{ - plan_tests(12); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-230-keybagtable.m b/OSX/sec/securityd/Regressions/secd-230-keybagtable.m deleted file mode 100644 index 0803a8d9..00000000 --- a/OSX/sec/securityd/Regressions/secd-230-keybagtable.m +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "secd_regressions.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#import "SecBackupKeybagEntry.h" - -#if 0 - - Add test for keybag table add SPI - Create an SPI to add a keybag to the keychain database (Keybag Table) - -// original secd_35_keychain_migrate_inet - -sudo defaults write /Library/Preferences/com.apple.security V10SchemaUpgradeTest -bool true -sudo defaults read /Library/Preferences/com.apple.security V10SchemaUpgradeTest - -#endif - -#if USE_KEYSTORE -#include "OSX/utilities/SecAKSWrappers.h" - -#include "SecdTestKeychainUtilities.h" - -static const bool kTestCustomKeybag = false; -static const bool kTestLocalKeybag = false; - -void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); -CFArrayRef SecAccessGroupsGetCurrent(void); - -#define kSecdTestCreateCustomKeybagTestCount 6 -#define kSecdTestLocalKeybagTestCount 1 -#define kSecdTestKeybagtableTestCount 5 -#define kSecdTestAddItemTestCount 2 - -#define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 - -// copied from si-33-keychain-backup.c -static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) -{ - keybag_handle_t handle = bad_keybag_handle; - - if (aks_create_bag(DATA_ARG(password), bag_type, &handle) == 0) { - void * keybag = NULL; - int keybag_size = 0; - if (aks_save_bag(handle, &keybag, &keybag_size) == 0) { - return CFDataCreate(kCFAllocatorDefault, keybag, keybag_size); - } - } - - return CFDataCreate(kCFAllocatorDefault, NULL, 0); -} - -static bool createCustomKeybag() { - /* custom keybag */ - keybag_handle_t keybag; - keybag_state_t state; - char *passcode="password"; - int passcode_len=(int)strlen(passcode); - const bool kTestLockedKeybag = false; - - ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(keybag); - - if (kTestLockedKeybag) { - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - } - - return true; -} - -static int keychainTestEnvironment(const char *environmentName, dispatch_block_t do_in_reset, dispatch_block_t do_in_environment) { - // - // Setup phase - // - CFArrayRef old_ag = SecAccessGroupsGetCurrent(); - CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); - CFArrayAppendValue(test_ag, CFSTR("test")); - SecAccessGroupsSetCurrent(test_ag); - - secd_test_setup_temp_keychain(environmentName, do_in_reset); - bool haveCustomKeybag = kTestCustomKeybag && createCustomKeybag(); - - // Perform tasks in the test keychain environment - if (do_in_environment) - do_in_environment(); - - // - // Cleanup phase - // - - // Reset keybag - if (haveCustomKeybag) - SecItemServerResetKeychainKeybag(); - - // Reset server accessgroups - SecAccessGroupsSetCurrent(old_ag); - CFReleaseSafe(test_ag); - // Reset custom $HOME - SetCustomHomePath(NULL); - SecKeychainDbReset(NULL); - return 0; -} - -static int addOneItemTest(NSString *account) { - /* Creating a password */ - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - - NSDictionary *item = @{ - (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassInternetPassword, - (__bridge NSString *)kSecAttrServer : @"members.spamcop.net", - (__bridge NSString *)kSecAttrAccount : account, // e.g. @"smith", - (__bridge NSString *)kSecAttrPort : @80, - (__bridge NSString *)kSecAttrProtocol : @"http", - (__bridge NSString *)kSecAttrAuthenticationType : @"dflt", - (__bridge NSString *)kSecValueData : (__bridge NSData *)pwdata - }; - - ok_status(SecItemAdd((CFDictionaryRef)item, NULL), "add internet password, while unlocked"); - CFReleaseSafe(pwdata); - return 0; -} - -static int localKeybagTest() { - const char *pass = "sup3rsekretpassc0de"; - CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); - CFDataRef keybag = create_keybag(kAppleKeyStoreAsymmetricBackupBag, password); - ok(keybag != NULL); - CFReleaseNull(keybag); - CFReleaseNull(password); - return 0; -} - -static int test_keybagtable() { - CFErrorRef error = NULL; - const char *pass = "sup3rsekretpassc0de"; - CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); - CFDataRef identifier = NULL; - CFURLRef pathinfo = NULL; - - ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); - CFReleaseNull(error); - - NSDictionary *deleteQuery = @{(__bridge NSString *)kSecAttrPublicKeyHash:(__bridge NSData *)identifier}; - ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteQuery, &error)); - - ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); - CFReleaseNull(error); - - ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); - CFReleaseNull(error); - - NSDictionary *deleteAllQuery = @{(id)kSecMatchLimit: (id)kSecMatchLimitAll}; - ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteAllQuery, &error)); - - CFReleaseNull(identifier); - CFReleaseNull(pathinfo); - CFReleaseNull(password); - CFReleaseNull(error); - return 0; -} - -static void showHomeURL() { -#if DEBUG - CFURLRef homeURL = SecCopyHomeURL(); - NSLog(@"Home URL for test : %@", homeURL); - CFReleaseSafe(homeURL); -#endif -} - -int secd_230_keybagtable(int argc, char *const *argv) -{ - int testcount = kSecdTestSetupTestCount + kSecdTestKeybagtableTestCount + kSecdTestAddItemTestCount; - if (kTestLocalKeybag) - testcount += kSecdTestLocalKeybagTestCount; - if (kTestCustomKeybag) - testcount += kSecdTestCreateCustomKeybagTestCount; - plan_tests(testcount); - - dispatch_block_t run_tests = ^{ - showHomeURL(); - if (kTestLocalKeybag) - localKeybagTest(); - addOneItemTest(@"smith"); - test_keybagtable(); - addOneItemTest(@"jones"); - }; - - dispatch_block_t do_in_reset = NULL; - dispatch_block_t do_in_environment = run_tests; - - keychainTestEnvironment("secd_230_keybagtable", do_in_reset, do_in_environment); - - return 0; -} - -#else - -int secd_230_keybagtable(int argc, char *const *argv) -{ - plan_tests(1); - secLogDisable(); - - todo("Not yet working in simulator"); - - TODO: { - ok(false); - } - /* not implemented in simulator (no keybag) */ - return 0; -} -#endif diff --git a/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m b/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m deleted file mode 100644 index bdf2dcc9..00000000 --- a/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2008,2010,2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "secd_regressions.h" - -/* TODO: This test needs to be updated. It was originally created to test upgrades from DB prior to the introduction of versionning, circa 2008. - We don't support upgrading from that old of keychain, but this test should be upgraded to test upgrades from v5 to v6 keychain, or more current - */ - -const char *create_db_sql = -"BEGIN TRANSACTION;" -"CREATE TABLE genp(cdat REAL,mdat REAL,desc BLOB,icmt BLOB,crtr INTEGER,type INTEGER,scrp INTEGER,labl BLOB,alis BLOB,invi INTEGER,nega INTEGER,cusi INTEGER,prot BLOB,acct BLOB NOT NULL DEFAULT '',svce BLOB NOT NULL DEFAULT '',gena BLOB,data BLOB,PRIMARY KEY(acct,svce));" -"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'4087574952','EnhancedVoicemail',NULL,X'34F32095A0ED6F32637629114439CE38E6FF39ADB591E761D20ED23F9FACF639258DA4F12454FD4D0189C0D39AAA9227');" -"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'TlalocNet','AirPort',NULL,X'52E24441994D93D18F344DDF6A7F1F6EC43A63BCEB5F89B02FEBEEAAE108BB4933EAE73A0FB615F693C70BCFBCF034BE74BDF0280ECBEB357EEFA3B7EF03060B');" -"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'weasels','AirPort',NULL,X'3FAD49851913382FBC92C9EB90D90D82A74B1DABB5F726648898B2FA2FBA405AA0B9D95D9837BBFF0F9B7C29954973249AA066F9F8AA68D79552970C687A7DA6');" -"CREATE TABLE inet(cdat REAL,mdat REAL,desc BLOB,icmt BLOB,crtr INTEGER,type INTEGER,scrp INTEGER,labl BLOB,alis BLOB,invi INTEGER,nega INTEGER,cusi INTEGER,prot BLOB,acct BLOB NOT NULL DEFAULT '',sdmn BLOB NOT NULL DEFAULT '',srvr BLOB NOT NULL DEFAULT '',ptcl INTEGER NOT NULL DEFAULT 0,atyp BLOB NOT NULL DEFAULT '',port INTEGER NOT NULL DEFAULT 0,path BLOB NOT NULL DEFAULT '',data BLOB,PRIMARY KEY(acct,sdmn,srvr,ptcl,atyp,port,path));" -"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'mb.7766@gmail.com','','imap.gmail.com','imap','',143,'',X'0029D7AFBF0000E0E386C8654070569B2DF1D7DC2D641AA29223297EC9E8AD86ED91CA6DEE3D2DA0FABD8F05DE5A7AD4CC46B134A211472B6DE50595EACAC149');" -"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'brouwer','','phonehome.apple.com','imap','',143,'',X'BB373BAE840427C5E1247540ADA559AB14DF3788906B786498A8E1CFF4B4C596634E4A4C7F9C55EA1B646163AFCDADA8');" -"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'mb.7766@gmail.com','','smtp.gmail.com','smtp','',25,'',X'042C08A4AECD3957822F531A602734F07B89DABA3BA6629ECEFE10E264C12635F83EFBB1707C6B39FB20CCE0200D8997B690FBB0B92911BFE9B2D1E05B1CD5F5');" -"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'brouwer','','phonehome.apple.com','smtp','',25,'',X'25B0775265ADC808B8AFB2F2602C44B13F5ECC1F04B1D5E6EAE1B803446F3A817CCF8401416FE673CE366E25FACF5C55');" -"CREATE TABLE cert(ctyp INTEGER NOT NULL DEFAULT 0,cenc INTEGER,labl BLOB,alis BLOB,subj BLOB,issr BLOB NOT NULL DEFAULT '',slnr BLOB NOT NULL DEFAULT '',skid BLOB,pkhh BLOB,data BLOB,PRIMARY KEY(ctyp,issr,slnr));" -"CREATE TABLE keys(kcls INTEGER NOT NULL DEFAULT 0,labl BLOB,alis BLOB,perm INTEGER,priv INTEGER,modi INTEGER,klbl BLOB NOT NULL DEFAULT '',atag BLOB NOT NULL DEFAULT '',crtr INTEGER NOT NULL DEFAULT 0,type INTEGER NOT NULL DEFAULT 0,bsiz INTEGER NOT NULL DEFAULT 0,esiz INTEGER NOT NULL DEFAULT 0,sdat REAL NOT NULL DEFAULT 0,edat REAL NOT NULL DEFAULT 0,sens INTEGER,asen INTEGER,extr INTEGER,next INTEGER,encr INTEGER,decr INTEGER,drve INTEGER,sign INTEGER,vrfy INTEGER,snrc INTEGER,vyrc INTEGER,wrap INTEGER,unwp INTEGER,data BLOB,PRIMARY KEY(kcls,klbl,atag,crtr,type,bsiz,esiz,sdat,edat));" -"CREATE INDEX ialis ON cert(alis);" -"CREATE INDEX isubj ON cert(subj);" -"CREATE INDEX iskid ON cert(skid);" -"CREATE INDEX ipkhh ON cert(pkhh);" -"CREATE INDEX ikcls ON keys(kcls);" -"CREATE INDEX iklbl ON keys(klbl);" -"CREATE INDEX iencr ON keys(encr);" -"CREATE INDEX idecr ON keys(decr);" -"CREATE INDEX idrve ON keys(drve);" -"CREATE INDEX isign ON keys(sign);" -"CREATE INDEX ivrfy ON keys(vrfy);" -"CREATE INDEX iwrap ON keys(wrap);" -"CREATE INDEX iunwp ON keys(unwp);" -"COMMIT;"; - -#include "SecdTestKeychainUtilities.h" - -#include -#include - -/* Test basic add delete update copy matching stuff. */ -static void tests(void) -{ - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_30_keychain_upgrade", ^{ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - /* Create a new keychain sqlite db */ - sqlite3 *db; - is(sqlite3_open(keychain_path, &db), SQLITE_OK, "create keychain"); - is(sqlite3_exec(db, create_db_sql, NULL, NULL, NULL), SQLITE_OK, - "populate keychain"); - - }); - - CFReleaseSafe(keychain_path_cf); - }); - - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); - CFDictionaryAddValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "add internet password"); - is_status(SecItemAdd(query, NULL), errSecDuplicateItem, - "add internet password again"); - - ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); - - ok_status(SecItemDelete(query), "Deleted the item we added"); - - CFReleaseSafe(eighty); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); - - - -} - -int secd_30_keychain_upgrade(int argc, char *const *argv) -{ - plan_tests(6 + kSecdTestSetupTestCount); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m b/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m deleted file mode 100644 index 3ff7543a..00000000 --- a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008-2010,2013-2014,2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "secd_regressions.h" - -#include - -#include "SecdTestKeychainUtilities.h" - - -#if !(TARGET_OS_IOS && TARGET_OS_SIMULATOR) -static void setKeychainPermissions(int perm) { - CFStringRef kc_path_cf = __SecKeychainCopyPath(); - CFStringPerformWithCString(kc_path_cf, ^(const char *path) { - ok_unix(chmod(path, perm), "chmod keychain file %s to be %d", path, perm); - }); -} -#endif - -int secd_31_keychain_unreadable(int argc, char *const *argv) -{ -#if TARGET_OS_IOS && TARGET_OS_SIMULATOR - // When running on iOS device in debugger, the target usually runs - // as root, which means it has access to the file even after setting 000. - return 0; -#else - plan_tests(10 + kSecdTestSetupTestCount); - secd_test_setup_temp_keychain("secd_31_keychain_unreadable", ^{ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - int fd; - ok_unix(fd = open(keychain_path, O_RDWR | O_CREAT | O_TRUNC, 0644), - "create keychain file '%s'", keychain_path); - SKIP: { - skip("Cannot fchmod keychain file with invalid fd", 2, fd > -1); - ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_path); - ok_unix(close(fd), "close keychain file '%s'", keychain_path); - } - }); - - CFReleaseSafe(keychain_path_cf); - }); - - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); - CFDictionaryAddValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); - CFDictionaryAddValue(query, kSecValueData, pwdata); - - is_status(SecItemAdd(query, NULL), errSecNotAvailable, "Cannot add items to unreadable keychain"); - is_status(SecItemCopyMatching(query, NULL), errSecNotAvailable, "Cannot read items in unreadable keychain"); - - setKeychainPermissions(0644); - - ok_status(SecItemAdd(query, NULL), "Add internet password"); - is_status(SecItemAdd(query, NULL), errSecDuplicateItem, - "Add internet password again"); - ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); - - // For commented tests need to convince secd to let go of connections. - // Without intervention it keeps them and accesses continue to succeed. - /* - setKeychainPermissions(0); - is_status(SecItemCopyMatching(query, NULL), errSecNotAvailable, "Still cannot read items in unreadable keychain"); - - setKeychainPermissions(0644); - ok_status(SecItemCopyMatching(query, NULL), "Found the item again"); - */ - ok_status(SecItemDelete(query),"Deleted the item we added"); - - CFReleaseNull(eighty); - CFReleaseNull(pwdata); - CFReleaseNull(query); -#endif // !(TARGET_OS_IOS && TARGET_OS_SIMULATOR) - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m b/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m deleted file mode 100644 index b3b547ea..00000000 --- a/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2008-2010,2013 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "secd_regressions.h" - -#include - -#include "SecdTestKeychainUtilities.h" - -/* Keybag and exported plist data. */ -static const unsigned char keybag_data[] = { - 0x56, 0x45, 0x52, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, - 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x12, 0x3a, 0xf9, 0xcb, - 0xd8, 0x76, 0x47, 0x01, 0xaa, 0xc5, 0xcf, 0xe5, 0x14, 0xf4, 0xf2, 0x98, - 0x48, 0x4d, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x41, 0x4c, 0x54, 0x00, 0x00, 0x00, 0x14, 0xbb, 0xfd, 0xa3, 0x3e, - 0x32, 0xa7, 0x80, 0x48, 0xd1, 0x2a, 0x39, 0x4b, 0x78, 0x6b, 0x35, 0x11, - 0x27, 0x62, 0x38, 0xe4, 0x49, 0x54, 0x45, 0x52, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x27, 0x10, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0xba, 0x4e, 0xed, 0x78, 0x38, 0x4a, 0x41, 0x4c, 0x8a, 0x2f, 0x6d, 0x1c, - 0x3a, 0xc9, 0xc8, 0xad, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0b, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x75, 0x88, 0x12, 0x0f, 0xbf, 0x21, 0x6b, 0x65, 0x85, 0xd0, 0x67, 0xdf, - 0x9b, 0xd1, 0xb3, 0x40, 0x53, 0x03, 0xaf, 0xb8, 0x8f, 0xe3, 0x5c, 0x97, - 0x43, 0xdd, 0x71, 0x65, 0x27, 0xd3, 0x73, 0xeb, 0x37, 0x5b, 0x29, 0xe8, - 0xd1, 0x14, 0xfe, 0xa3, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x2b, 0x76, 0x49, 0x3c, 0xc2, 0x5c, 0x4e, 0xc8, 0x8d, 0xea, 0x9a, 0x59, - 0x11, 0x98, 0xdd, 0x40, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0a, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xee, 0x8f, 0x46, 0xd8, 0x10, 0x17, 0x6e, 0x6c, 0x63, 0xee, 0x04, 0x22, - 0xd4, 0xec, 0x7c, 0x53, 0x8f, 0x2c, 0x18, 0x8d, 0xf3, 0x86, 0xdb, 0xd6, - 0x19, 0xae, 0x1e, 0xe0, 0x45, 0xc7, 0x75, 0x13, 0x8c, 0xb3, 0x95, 0x6f, - 0x21, 0x60, 0xd2, 0x9e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x3e, 0x91, 0xc1, 0x5d, 0xb9, 0x64, 0x44, 0xb4, 0x81, 0x0f, 0xe5, 0x12, - 0xae, 0x89, 0xb5, 0x73, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x09, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xc1, 0x22, 0x1e, 0x92, 0x54, 0xc3, 0xd6, 0x04, 0xdc, 0x45, 0x3e, 0x24, - 0xf9, 0x0c, 0xbe, 0x46, 0x8a, 0x02, 0xf7, 0xfc, 0x32, 0x24, 0x6d, 0x21, - 0x57, 0x1a, 0x43, 0xd5, 0x5f, 0xda, 0x8a, 0x5a, 0x33, 0xc0, 0xc8, 0x67, - 0x37, 0x79, 0xfe, 0x57, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x4a, 0xb0, 0xd7, 0xc0, 0xfe, 0xf7, 0x42, 0x4f, 0xb2, 0xd9, 0xd8, 0x85, - 0x70, 0xea, 0x97, 0x74, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x08, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x45, 0x26, 0xb9, 0xce, 0x3f, 0x7c, 0xd9, 0xbf, 0x92, 0xb0, 0x2e, 0x93, - 0xbc, 0x85, 0xf9, 0xd8, 0xec, 0x30, 0xd2, 0x42, 0x4c, 0x9d, 0x89, 0x77, - 0xbc, 0xe3, 0x66, 0xf2, 0x23, 0x61, 0xad, 0xc7, 0xc7, 0x02, 0xb9, 0x44, - 0x3d, 0x66, 0xd1, 0x6f, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x63, 0xdc, 0x85, 0xdd, 0x5b, 0xcb, 0x49, 0x43, 0xa2, 0x23, 0x93, 0xe7, - 0xbc, 0x88, 0x67, 0x2c, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x07, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x2d, 0x80, 0xa8, 0xe6, 0x01, 0x32, 0x90, 0x06, 0x63, 0xb2, 0xaf, 0x23, - 0x29, 0xbb, 0x85, 0x2b, 0x8f, 0x03, 0x3c, 0x07, 0xf2, 0xc3, 0xff, 0x8c, - 0xe5, 0x61, 0xa0, 0xec, 0xc3, 0x53, 0x28, 0xd4, 0x98, 0x92, 0x30, 0x41, - 0xab, 0x2b, 0x7a, 0xc9, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x22, 0x05, 0x3e, 0xc4, 0x9c, 0x32, 0x48, 0x8e, 0xad, 0x25, 0xe5, 0xe1, - 0x1d, 0x05, 0xbf, 0x1c, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x06, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x2a, 0x51, 0x5a, 0x8b, 0x5c, 0x2d, 0x67, 0x49, 0x59, 0xce, 0xf6, 0x77, - 0xb0, 0x22, 0x8b, 0x53, 0x22, 0xfd, 0x5d, 0x1b, 0x6e, 0x97, 0x0c, 0xed, - 0x3a, 0xb5, 0x52, 0xe7, 0x04, 0x31, 0xf6, 0x97, 0x5c, 0x55, 0xf5, 0xcc, - 0xa9, 0xce, 0x37, 0x8c, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0xb8, 0x54, 0xc8, 0xe5, 0x40, 0xc3, 0x4f, 0x15, 0x8d, 0xda, 0xfb, 0x82, - 0x24, 0xe4, 0x84, 0xf3, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x05, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x97, 0x9d, 0xac, 0x94, 0xdc, 0x34, 0xbc, 0xea, 0x47, 0x1e, 0xf8, 0x9a, - 0x2e, 0xb9, 0x51, 0x60, 0xc7, 0xf3, 0x5f, 0x79, 0x43, 0x9e, 0xc8, 0x80, - 0xad, 0xdd, 0x86, 0x61, 0x73, 0xd1, 0xad, 0xd2, 0xc6, 0x39, 0xa6, 0x94, - 0x5f, 0x3d, 0x8e, 0x0e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x60, 0x85, 0x58, 0x0e, 0xbb, 0x91, 0x4b, 0x47, 0x84, 0xdc, 0x5a, 0x81, - 0x75, 0x9a, 0xcd, 0x99, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xba, 0x30, 0x0f, 0x71, 0x33, 0x72, 0x12, 0xeb, 0x2f, 0x30, 0x51, 0xd0, - 0x24, 0xfb, 0xba, 0x9b, 0xeb, 0x9b, 0x13, 0x22, 0xbe, 0x20, 0x1f, 0xe2, - 0xaa, 0xfe, 0x46, 0x6f, 0xe9, 0x24, 0x98, 0x74, 0x75, 0xe1, 0xe8, 0x78, - 0xe2, 0xdf, 0x1d, 0x79, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0xba, 0x02, 0xb1, 0xbf, 0x5a, 0x19, 0x47, 0xf9, 0x8e, 0x63, 0x61, 0xbb, - 0x29, 0x1b, 0x11, 0xd3, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xaa, 0x5d, 0xb4, 0x84, 0x93, 0xe9, 0x58, 0xf9, 0xe1, 0xb2, 0xcc, 0xbd, - 0xb0, 0xb5, 0xa5, 0x17, 0xe1, 0x00, 0x86, 0xbc, 0x8c, 0x66, 0x68, 0x6e, - 0x70, 0x4d, 0x65, 0xda, 0x06, 0xb6, 0x1a, 0xc1, 0x63, 0x1d, 0x72, 0xcd, - 0x86, 0x73, 0xd2, 0x94, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x3b, 0x0e, 0x79, 0xc8, 0xc9, 0xbc, 0x4b, 0x75, 0x88, 0x16, 0x89, 0xb8, - 0x69, 0x9b, 0x5e, 0xce, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xb3, 0x0a, 0x5d, 0xb2, 0x3e, 0x63, 0xb1, 0xc5, 0x02, 0xf2, 0x38, 0xbe, - 0x8b, 0xb9, 0xfa, 0x06, 0xcb, 0x41, 0x6f, 0x99, 0xe7, 0x69, 0x12, 0x5f, - 0x6e, 0xef, 0x17, 0x67, 0xe6, 0xf6, 0xe4, 0x61, 0x2b, 0x1d, 0xe7, 0x18, - 0x8a, 0x5d, 0x5f, 0x66, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x45, 0xc1, 0x1e, 0x42, 0x2f, 0xd4, 0x47, 0x56, 0xa6, 0x88, 0x3a, 0x38, - 0x07, 0x86, 0x74, 0xcd, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x92, 0xf6, 0xf2, 0xd3, 0x54, 0x02, 0xa9, 0xb3, 0x15, 0x19, 0x2a, 0x12, - 0x99, 0xb3, 0x81, 0xbc, 0x92, 0x7e, 0x5c, 0x47, 0xd3, 0x56, 0x92, 0x04, - 0xed, 0xbc, 0x5e, 0x22, 0x36, 0x6e, 0x51, 0xd4, 0xbb, 0xad, 0xaa, 0xa3, - 0xbd, 0x28, 0x90, 0x64 -}; - -static const char export_plist[] = "\ -\ -\ -\ -\ -genp\ -\ -\ -v_Data\ -\ -AwAAAAgAAAAoAAAAPjxrzgnoJYiuTfNV0OAii8Jgl8Zegkk93Dwm\ -dJo27hIyxqzTT+twzAHn0qbb+uq7IIDFbLZt9ThLJmpGuwMzXKl0\ -91YCqoT6d3zPAkSPhPwS29/LFE3hqeGsUyV9CSye3fW9A51b/+uA\ -XVD7LQdM9Xv7Def8JO9abBKW42X+l38SW0sOq34/243Hyp3q0VWT\ -XN+UojOkzAgsBxPsuHEOre0+9aOe+RzIO2R+s54YG3QaxSwhUOu/\ -DcN6raIA37BF0eOFHOlP6ZUH+NzwTWi5ycRyX833b0bMhU4M24yx\ -5Z88ysOPWZuD6oqycfo=\ -\ -v_PersistentRef\ -\ -Z2VucAAAAAAAAAA1\ -\ -\ -\ -\ -\ -"; - -/* Test backup-restore case, when item had inconsistently set pdmn attribute (due to another bug), - and mobile restore restored item with inconsistent attributes and afterwards tried SecItemUpdate() - on it, which failed, leading to the failure of the whole restore operation. - */ -static void tests(void) -{ - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_32_restore_bad_backup", ^{}); - - /* Restore keychain from plist. */ - CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, keybag_data, sizeof(keybag_data)); - CFDataRef backup = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)export_plist, sizeof(export_plist)); - ok_status(_SecKeychainRestoreBackup(backup, keybag, NULL)); - CFRelease(keybag); - CFRelease(backup); - - /* The restored item is kind of malformed (pdmn and accc attributes are inconsistent). Currently adopted way - of handling of this item is to try to handle it gracefully, this is what this test does (i.e. it checks that - it is possible to update such item). Another possibility which might be adopted in the future is dropping such - item during backup decoding. In this case, the test should be modified to check that the item does not exist - in the keychain at all. */ - - /* Try to update item with inconsistent accc and pdmn attributes. */ - CFDictionaryRef query = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), - kSecAttrService, CFSTR("test"), - NULL); - CFDictionaryRef update = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrService, CFSTR("updated-test"), - NULL); - - ok_status(SecItemUpdate(query, update)); - diag("This still fails - don't be alarmed"); - CFRelease(update); - CFRelease(query); -} - -int secd_32_restore_bad_backup(int argc, char *const *argv) -{ - plan_tests(2 + kSecdTestSetupTestCount); - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-33-keychain-backup.m b/OSX/sec/securityd/Regressions/secd-33-keychain-backup.m deleted file mode 100644 index 30146b07..00000000 --- a/OSX/sec/securityd/Regressions/secd-33-keychain-backup.m +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Copyright (c) 2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include - -#include "securityd/SecKeybagSupport.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include "OSX/utilities/SecAKSWrappers.h" - -#include -#include -#include -#include -#include - -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" -#include "server_security_helpers.h" - -struct test_persistent_s { - CFTypeRef persist[2]; - CFDictionaryRef query; - CFDictionaryRef query1; - CFDictionaryRef query2; - CFMutableDictionaryRef query3; - CFMutableDictionaryRef query4; -}; - -static void test_persistent(struct test_persistent_s *p) -{ - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - const void *keys[] = { - kSecClass, - kSecAttrServer, - kSecAttrAccount, - kSecAttrPort, - kSecAttrProtocol, - kSecAttrAuthenticationType, - kSecReturnPersistentRef, - kSecValueData - }; - const void *values[] = { - kSecClassInternetPassword, - CFSTR("zuigt.nl"), - CFSTR("frtnbf"), - eighty, - CFSTR("http"), - CFSTR("dflt"), - kCFBooleanTrue, - pwdata - }; - CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, - array_size(keys), &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - p->persist[0] = NULL; - // NUKE anything we might have left around from a previous test run so we don't crash. - SecItemDelete(item); - ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); - CFTypeRef results = NULL; - CFTypeRef results2 = NULL; -SKIP: { - skip("no persistent ref", 6, ok(p->persist[0], "got back persistent ref")); - - /* Create a dict with all attrs except the data. */ - keys[(array_size(keys)) - 2] = kSecReturnAttributes; - p->query = CFDictionaryCreate(NULL, keys, values, - (array_size(keys)) - 1, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - ok_status(SecItemCopyMatching(p->query, &results), "find internet password by attr"); - - const void *keys_persist[] = { - kSecReturnAttributes, - kSecValuePersistentRef - }; - const void *values_persist[] = { - kCFBooleanTrue, - p->persist[0] - }; - p->query2 = CFDictionaryCreate(NULL, keys_persist, values_persist, - (array_size(keys_persist)), &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - ok_status(SecItemCopyMatching(p->query2, &results2), "find internet password by persistent ref"); - ok(CFEqual(results, results2 ? results2 : CFSTR("")), "same item (attributes)"); - - CFReleaseNull(results); - CFReleaseNull(results2); - - ok_status(SecItemDelete(p->query), "delete internet password"); - - ok_status(!SecItemCopyMatching(p->query, &results), - "don't find internet password by attributes"); - ok(!results, "no results"); -} - - /* clean up left over from aborted run */ - if (results) { - CFDictionaryRef cleanup = CFDictionaryCreate(NULL, (const void **)&kSecValuePersistentRef, - &results, 1, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - SecItemDelete(cleanup); - CFRelease(results); - CFRelease(cleanup); - } - - ok_status(!SecItemCopyMatching(p->query2, &results2), - "don't find internet password by persistent ref anymore"); - ok(!results2, "no results"); - - CFReleaseNull(p->persist[0]); - - /* Add a new item and get it's persitant ref. */ - ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); - p->persist[1] = NULL; - CFMutableDictionaryRef item2 = CFDictionaryCreateMutableCopy(NULL, 0, item); - CFDictionarySetValue(item2, kSecAttrAccount, CFSTR("johndoe-bu")); - // NUKE anything we might have left around from a previous test run so we don't crash. - SecItemDelete(item2); - ok_status(SecItemAdd(item2, &p->persist[1]), "add second internet password"); - CFMutableDictionaryRef update = NULL; - CFStringRef server = NULL; -SKIP: { - skip("no persistent ref", 3, ok(p->persist[0], "got back persistent ref from first internet password")); - - is(CFGetTypeID(p->persist[0]), CFDataGetTypeID(), "result is a CFData"); - p->query3 = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(p->query3, kSecValuePersistentRef, p->persist[0]); - update = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(update, kSecAttrServer, CFSTR("zuigt.com")); - ok_status(SecItemUpdate(p->query3, update), "update via persitant ref"); - - /* Verify that the update really worked. */ - CFDictionaryAddValue(p->query3, kSecReturnAttributes, kCFBooleanTrue); - ok_status(SecItemCopyMatching(p->query3, &results2), "find updated internet password by persistent ref"); - server = CFDictionaryGetValue(results2, kSecAttrServer); - ok(CFEqual(server, CFSTR("zuigt.com")), "verify attribute was modified by update"); - CFReleaseNull(results2); - CFDictionaryRemoveValue(p->query3, kSecReturnAttributes); -} - -SKIP: { - skip("no persistent ref", 2, ok(p->persist[1], "got back persistent ref")); - - /* Verify that item2 wasn't affected by the update. */ - p->query4 = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(p->query4, kSecValuePersistentRef, p->persist[1]); - CFDictionaryAddValue(p->query4, kSecReturnAttributes, kCFBooleanTrue); - ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); - server = CFDictionaryGetValue(results2, kSecAttrServer); - ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); - CFReleaseNull(results2); -} - - /* Delete the item via persitant ref. */ - ok_status(SecItemDelete(p->query3), "delete via persitant ref"); - is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, - "don't find deleted internet password by persistent ref"); - CFReleaseNull(results2); - ok_status(SecItemCopyMatching(p->query4, &results2), - "find non deleted internet password by persistent ref"); - CFReleaseNull(results2); - - CFReleaseNull(update); - CFReleaseNull(item); - CFReleaseNull(item2); - CFReleaseNull(eighty); - CFReleaseNull(pwdata); -} - -static void test_persistent2(struct test_persistent_s *p) -{ - CFTypeRef results = NULL; - CFTypeRef results2 = NULL; - - ok_status(!SecItemCopyMatching(p->query, &results), - "don't find internet password by attributes"); - ok(!results, "no results"); - - ok_status(!SecItemCopyMatching(p->query2, &results2), - "don't find internet password by persistent ref anymore"); - ok(!results2, "no results"); - -SKIP:{ - ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); - skip("non updated internet password by persistent ref NOT FOUND!", 2, results2); - ok(results2, "non updated internet password not found"); - CFStringRef server = CFDictionaryGetValue(results2, kSecAttrServer); - ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); - CFReleaseNull(results2); -} - - is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, - "don't find deleted internet password by persistent ref"); - CFReleaseNull(results2); - ok_status(SecItemCopyMatching(p->query4, &results2), - "find non deleted internet password by persistent ref"); - CFReleaseNull(results2); - - ok_status(SecItemDelete(p->query4),"Deleted internet password by persistent ref"); - - CFRelease(p->query); - CFRelease(p->query2); - CFRelease(p->query3); - CFRelease(p->query4); - CFReleaseNull(p->persist[0]); - CFReleaseNull(p->persist[1]); -} - -static CFMutableDictionaryRef test_create_lockdown_identity_query(void) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("test-delete-me")); - CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("lockdown-identities")); - return query; -} - -static CFMutableDictionaryRef test_create_managedconfiguration_query(void) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); - CFDictionaryAddValue(query, kSecAttrService, CFSTR("com.apple.managedconfiguration")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("Public")); - CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); - return query; -} - -static CFMutableDictionaryRef test_create_accounts_query(void) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); - CFDictionaryAddValue(query, kSecAttrService, CFSTR("com.apple.account.CloudKit.token")); - CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); - return query; -} - -static void test_add_lockdown_identity_items(void) { - CFMutableDictionaryRef query = test_create_lockdown_identity_query(); - const char *v_data = "lockdown identity data (which should be a cert + key)"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_lockdown_identity_items"); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); -} - -static void test_remove_lockdown_identity_items(void) { - CFMutableDictionaryRef query = test_create_lockdown_identity_query(); - ok_status(SecItemDelete(query), "test_remove_lockdown_identity_items"); - CFReleaseSafe(query); -} - -static void test_no_find_lockdown_identity_item(void) { - CFMutableDictionaryRef query = test_create_lockdown_identity_query(); - is_status(SecItemCopyMatching(query, NULL), errSecItemNotFound, - "test_no_find_lockdown_identity_item"); - CFReleaseSafe(query); -} - -static CFMutableDictionaryRef test_create_sysbound_query(void) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("sysbound")); - CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); - return query; -} - -static void test_add_sysbound_item(void) { - CFMutableDictionaryRef query = test_create_sysbound_query(); - int32_t val = kSecSecAttrSysBoundPreserveDuringRestore; - CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &val); - CFDictionaryAddValue(query, kSecAttrSysBound, num); - CFReleaseNull(num); - - const char *v_data = "sysbound identity data"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_sysbound_item"); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); -} - -static void test_remove_sysbound_item(void) { - CFMutableDictionaryRef query = test_create_sysbound_query(); - ok_status(SecItemDelete(query), "test_remove_sysbound_item"); - CFReleaseSafe(query); -} - -static void test_find_sysbound_item(OSStatus expectedCode) { - CFMutableDictionaryRef query = test_create_sysbound_query(); - is_status(SecItemCopyMatching(query, NULL), expectedCode, - "test_find_sysbound_item"); - CFReleaseSafe(query); -} - -/* - * BT - */ - -static CFMutableDictionaryRef test_create_bt_query(bool sync) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); - CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("com.apple.bluetooth")); - CFDictionaryAddValue(query, kSecAttrSynchronizable, sync ? kCFBooleanTrue : kCFBooleanFalse); - CFDictionarySetValue(query, kSecAttrAccount, sync ? CFSTR("sync") : CFSTR("non-sync")); - return query; -} - -static void test_add_bt_items(const char *data) { - CFMutableDictionaryRef query = NULL; - - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)data, strlen(data)); - - query = test_create_bt_query(false); - (void)SecItemDelete(query); - CFDictionarySetValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_bt_item(nonsync)"); - CFReleaseSafe(query); - - query = test_create_bt_query(true); - (void)SecItemDelete(query); - CFDictionarySetValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_bt_item(sync)"); - CFReleaseSafe(query); - - CFReleaseSafe(pwdata); -} - -static void test_find_bt_item(OSStatus expectedCode, bool sync, const char *data) { - CFMutableDictionaryRef query = test_create_bt_query(sync); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - CFDataRef pwdata = NULL; - is_status(SecItemCopyMatching(query, (CFTypeRef *)&pwdata), expectedCode, - "test_find_bt_item: %s", data); - CFIndex len = strlen(data); - is(len, CFDataGetLength(pwdata), "length wrong(%s)", data); - ok(memcmp(data, CFDataGetBytePtr(pwdata), len) == 0, "length wrong(%s)", data); - CFReleaseSafe(query); -} - -/* - * MC - */ - -static void test_add_managedconfiguration_item(void) { - CFMutableDictionaryRef query = test_create_managedconfiguration_query(); - const char *v_data = "public managedconfiguration password history data"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_managedconfiguration_item"); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); -} - -static void test_find_managedconfiguration_item(void) { - CFMutableDictionaryRef query = test_create_managedconfiguration_query(); - ok_status(SecItemCopyMatching(query, NULL), "test_find_managedconfiguration_item"); - ok_status(SecItemDelete(query), "test_find_managedconfiguration_item (deleted)"); - CFReleaseSafe(query); -} - -/* - * Accounts - */ - -static void test_add_accounts_item(const char *string) { - CFMutableDictionaryRef query = test_create_accounts_query(); - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)string, strlen(string)); - CFDictionaryAddValue(query, kSecValueData, pwdata); - ok_status(SecItemAdd(query, NULL), "test_add_accounts_item"); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); -} - -static char *test_find_accounts_item(void) { - CFMutableDictionaryRef query = test_create_accounts_query(); - CFDataRef data = NULL; - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, (CFTypeRef *)&data), "test_find_accounts_item"); - if (data == NULL) - return NULL; - ok(isData(data), "data"); - size_t len = CFDataGetLength(data); - char *str = malloc(len + 1); - memcpy(str, CFDataGetBytePtr(data), len); - str[len] = '\0'; - CFReleaseSafe(query); - CFReleaseSafe(data); - return str; -} - -static void test_delete_accounts_item(void) { - CFMutableDictionaryRef query = test_create_accounts_query(); - ok_status(SecItemDelete(query), "test_delete_accounts_item"); - CFReleaseSafe(query); -} - - - -#if USE_KEYSTORE -#define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 -static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) -{ - CFDataRef result = NULL; - void *bag = NULL; - int bagLen = 0; - - keybag_handle_t handle = bad_keybag_handle; - require_noerr(aks_create_bag(DATA_ARG(password), bag_type, &handle), out); - require_noerr(aks_save_bag(handle, &bag, &bagLen), out); - - result = CFDataCreate(kCFAllocatorDefault, bag, bagLen); - out: - return result; -} -#endif - -/* Test low level keychain migration from device to device interface. */ -static void tests(void) -{ - { - CFMutableDictionaryRef lock_down_query = test_create_lockdown_identity_query(); - (void)SecItemDelete(lock_down_query); - CFReleaseNull(lock_down_query); - } - - int v_eighty = 80; - CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); - const char *v_data = "test"; - CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); - CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); - CFDictionaryAddValue(query, kSecAttrPort, eighty); - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); - CFDictionaryAddValue(query, kSecValueData, pwdata); - // NUKE anything we might have left around from a previous test run so we don't crash. - (void)SecItemDelete(query); - - ok_status(SecItemAdd(query, NULL), "add internet password"); - is_status(SecItemAdd(query, NULL), errSecDuplicateItem, - "add internet password again"); - - ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); - - struct test_persistent_s p = {}; - test_persistent(&p); - - CFDataRef backup = NULL, keybag = NULL, password = NULL; - - test_add_lockdown_identity_items(); - test_add_sysbound_item(); - test_add_accounts_item("1"); - test_add_bt_items("kaka1"); - -#if USE_KEYSTORE - keybag = create_keybag(kAppleKeyStoreBackupBag, password); -#else - keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0); -#endif - - ok(backup = _SecKeychainCopyBackup(keybag, password), - "_SecKeychainCopyBackup"); - - test_add_managedconfiguration_item(); - test_delete_accounts_item(); - test_add_accounts_item("2"); - test_remove_lockdown_identity_items(); - test_remove_sysbound_item(); - - test_add_bt_items("kaka2"); - - ok_status(_SecKeychainRestoreBackup(backup, keybag, password), - "_SecKeychainRestoreBackup"); - CFReleaseSafe(backup); - - test_no_find_lockdown_identity_item(); - test_find_sysbound_item(errSecItemNotFound); - test_find_managedconfiguration_item(); - char *val = test_find_accounts_item(); - eq_string(val, "2", "string not 2 as expected: %s", val); - test_delete_accounts_item(); - - /* - * Check that the kaka1 entry was "overwritten" - */ - test_find_bt_item(errSecSuccess, true, "kaka2"); - test_find_bt_item(errSecSuccess, false, "kaka1"); - - ok_status(SecItemCopyMatching(query, NULL), - "Found the item we added after restore"); - - test_persistent2(&p); - -#if USE_KEYSTORE - CFReleaseNull(keybag); - keybag = create_keybag(kAppleKeyStoreOTABackupBag, password); -#endif - - ok(backup = _SecKeychainCopyBackup(keybag, password), - "_SecKeychainCopyBackup"); - ok_status(_SecKeychainRestoreBackup(backup, keybag, password), - "_SecKeychainRestoreBackup"); - ok_status(SecItemCopyMatching(query, NULL), - "Found the item we added after restore"); - CFReleaseNull(backup); - - // force tombstone to be added, since it's not the default behavior per rdar://14680869 - CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue); - - ok_status(SecItemDelete(query), "Deleted item we added"); - -#if USE_KEYSTORE - CFReleaseNull(keybag); - keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password); -#endif - - // add syncable item - CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue); - ok_status(SecItemAdd(query, NULL), "add internet password"); - - // and non-syncable item - test_add_managedconfiguration_item(); - - CFDictionaryRef syncableBackup = NULL; - - CFErrorRef error = NULL; - CFDictionaryRef scratch = NULL; -SKIP: { - skip("skipping syncable backup tests", 7, - ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items")); - - // TODO: add item, call SecServerCopyTruthInTheCloud again - - // CFShow(syncableBackup); - - // find and delete - skip("skipping syncable backup tests", 6, - ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy")); - - skip("skipping syncable backup tests", 5, - ok_status(SecItemDelete(query), "delete item we backed up")); - - // ensure we added a tombstone - CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue); - skip("skipping syncable backup tests", 4, - ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted")); - CFDictionaryRemoveValue(query, kSecAttrTombstone); - - test_find_managedconfiguration_item(); // <- 2 tests here - - // TODO: add a different new item - delete what's not in the syncableBackup? - - // Do another backup after some changes - skip("skipping syncable backup tests", 1, - ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes")); - - skip("skipping syncable backup tests", 0, - ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items")); -} - CFReleaseNull(scratch); - CFReleaseNull(error); - - // non-syncable item should (still) be gone -> add should work - test_add_managedconfiguration_item(); - test_find_managedconfiguration_item(); - - // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail - is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL), - "find restored item"); - is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item"); - - CFReleaseSafe(syncableBackup); - CFReleaseSafe(keybag); - CFReleaseSafe(eighty); - CFReleaseSafe(pwdata); - CFReleaseSafe(query); -} - -int secd_33_keychain_backup(int argc, char *const *argv) -{ - plan_tests(85); - - CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); - - NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; - [newACL addObjectsFromArray:@[ - @"com.apple.bluetooth", - @"lockdown-identities", - @"apple", - ]]; - - SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); - - - secd_test_setup_temp_keychain("secd_33_keychain_backup", NULL); - - tests(); - - SecAccessGroupsSetCurrent(currentACL); - CFReleaseNull(currentACL); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m b/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m deleted file mode 100644 index 4aa765e0..00000000 --- a/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m +++ /dev/null @@ -1,1172 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "secd_regressions.h" - -#include "SecdTestKeychainUtilities.h" -#include "SecKeybagSupport.h" - -const char *cert1 = "MIIFQzCCBCugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN8DrET5AAQ4dVIP+RD3XATFaBYpG9b2H0tV82gVGOv/t5cxOszAMxzsw7xlY/tMRrx5yz7IUUvueylHl98e7yMefP69vwqwSc4DWSELSqHOLMHd/uPLYLINIFqEW8Nq4Q02V2IxqBbiwtZeeSOqY3gQ2kiCd4cF8Itlr3UePJrlAgMBAAGjggKzMIICrzAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQg5YNVxRTOC13qs9cVUuvDIp6AH+jitdjhWJfai2bfP3QwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCGCGSAFlAwYIMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDETCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMDIGA1UdEQQrMCmgJwYIYIZIAWUDBgagGwQZ1Oc52nOc7TnOc52haFoIySreCmGE5znD4jAQBglghkgBZQMGCQEEAwEBADANBgkqhkiG9w0BAQsFAAOCAQEAVVGMeep+1wpVFdXFIXUTkxy9RjdOO3SmMGVomfVXofVOBfVzooaI+RV5UCURnoqoHYziBidxc9YKW6n9mX6p27KfrC1roHg6wu5xVEHJ93hju35g3WAXTnqNFiQpB+GU7UvJJEhkcTU2rChuYNS5SeFZ0pv1Gyzw7WjLfh9rdAPBfRg4gxpho9SMCUnI+p5KbEiptmimtPfsVq6htT3P+m2V4UXIT6sr7T6IpnPteMppsH43NKXNM6iPCkRCUPQ0d+lpfXAYGSFIzx2WesjSmrs/CHXfwmhnbrJNPCx9zlcCMmmfGcZGyufF+10wF9gv9qx+PUwi2xMKhwuKR1LoCg=="; -const char *cert2 = -"MIIFCTCCA/GgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKij0LIQlW0VKahBGF4tu/xdwGWN+KTLLGyMQmuuG+NNG+vQMSsdXD1pd00YMBiGn3sC5b+G7lQLZ85mDQfO+eI8GDjG+Sh8W8Cghku20sxZnQ+kZOLOr//R2/ZXonVaxoBR/9tBPh0MIEIVzRS8JmltZVfhkbIR6Wiox3jVEAsPAgMBAAGjggJ5MIICdTAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQga85kaqoMEaV+E04P1gZ2OUlbCbvr623fC30WhBZn3bMwDgYDVR0PAQH/BAQDAgbAMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDDTCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMCIGA1UdEQQbMBmBF2NvbW1vbl9uYW1lQHBpdmRlbW8ub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQANg1tGsgO32fVXDyRPHFeqDa0QmQ4itHrh6BAK6n94QL8383wuPDFkPy1TfVYVdYm0Gne6hyH/Z13ycw1XXNddooT7+OiYK5F1TEhfQNiRhzTqblB/yc2lv6Ho0EsOrwPhaBRaO3EFUyjeNMxsvG8Dr9Y5u2B38ESB4OsLKHq0eD/WZjEAlyGx16Qi7YlLiHGfLMorgkg9Mbp73guNO1PItDTAnqHUUOlQ01ThNug0sR5ua1zlNFx6AIPoX4yAPrtlEMZtbsevsXlgDpO1zc26p5icBmQHYT7uzdTEEN4tmcxXg6Z/dGB63GCluf+Pc+ovRt/MMt2EbcIuwJ9C516H"; -const char *cert3 = -"MIICETCCAbigAwIBAgIJANiM7uTufLiKMAkGByqGSM49BAEwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MxGjAYBgNVBAMTEUFwcGxlIFRlc3QgQ0EyIEVDMSAwHgYJKoZIhvcNAQkBFhF2a3V6ZWxhQGFwcGxlLmNvbTAeFw0xNjA1MTIxMTMyMzlaFw0yNjA1MTAxMTMyMzlaMGYxEDAOBgNVBAMTB3NldG9rZW4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQHKxfYgbqRHmThPnO9yQX5KrL/EPa6dZU52Wys5gC3/Mk0dNt9dLhpWblAVaeBzkos4juN3cxbnoB9MsC4bvoLoyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAJBgcqhkjOPQQBA0gAMEUCIQClcoYLhEA/xIGU94ZBcup26Pb7pXaWaaOM3+9z510TRwIgV/iprC051SuQzkqXA5weVliJOohFYjO+gUoH/6MJpDg="; - -extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); - -static void test_item_add(void) { - - static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; - CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); - __block NSUInteger objIDIdx = 0; - - CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrTokenID, CFSTR("tokenid"), - kSecAttrService, CFSTR("ctktest-service"), - kSecValueData, valueData, - kSecReturnAttributes, kCFBooleanTrue, - NULL); - // Setup token hook. - __block int phase = 0; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); - - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - phase++; - is(objectID, NULL); - eq_cf(CFDictionaryGetValue(at, kSecClass), kSecClassGenericPassword); - eq_cf(CFDictionaryGetValue(at, kSecAttrService), CFDictionaryGetValue(attrs, kSecAttrService)); - eq_cf(CFDictionaryGetValue(at, kSecAttrTokenID), CFSTR("tokenid")); - eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData); - CFDictionaryRemoveValue(at, kSecValueData); - ++objIDIdx; - return (__bridge_retained CFDataRef)[NSData dataWithBytes:&objIDIdx length:sizeof(objIDIdx)]; - }; - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase++; - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - phase++; - return CFRetain(valueData); - }; - }); - - CFTypeRef result = NULL; - ok_status(SecItemAdd(attrs, &result)); - eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service")); - eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid")); - is(CFDictionaryGetValue(result, kSecValueData), NULL); - CFReleaseNull(result); - - is(phase, 3); - - phase = 0; - CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue); - CFDictionarySetValue(attrs, kSecAttrService, CFSTR("ctktest-service1")); - ok_status(SecItemAdd(attrs, &result)); - eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service1")); - eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid")); - eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData); - CFReleaseNull(result); - - is(phase, 4); - - phase = 0; - CFDictionaryRemoveValue(attrs, kSecReturnAttributes); - CFDictionarySetValue(attrs, kSecAttrAccount, CFSTR("2nd")); - ok_status(SecItemAdd(attrs, &result)); - eq_cf(result, valueData); - CFReleaseNull(result); - is(phase, 4); - - CFRelease(attrs); - CFRelease(valueData); -} - -static void test_item_query() { - static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; - CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); - CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1); - - __block int phase = 0; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - phase++; - return CFRetain(valueData); - }; - }); - - // Add non-token item with the same service, to test queries returning mixed results. - CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrService, CFSTR("ctktest-service"), - kSecValueData, valueData2, - NULL); - ok_status(SecItemAdd(attrs, NULL)); - CFRelease(attrs); - - // Query with service. - CFMutableDictionaryRef query; - query = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrService, CFSTR("ctktest-service"), - kSecReturnAttributes, kCFBooleanTrue, - kSecReturnData, kCFBooleanTrue, - NULL); - - phase = 0; - CFTypeRef result = NULL; - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 2); - is(CFGetTypeID(result), CFDictionaryGetTypeID()); - eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData); - is(CFGetTypeID(CFDictionaryGetValue(result, kSecAttrAccessControl)), SecAccessControlGetTypeID()); - eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service")); - CFReleaseSafe(result); - - phase = 0; - CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 2); - is(CFGetTypeID(result), CFArrayGetTypeID()); - is(CFArrayGetCount(result), 2); - CFReleaseSafe(result); - - phase = 0; - CFDictionaryRemoveValue(query, kSecMatchLimit); - CFDictionaryRemoveValue(query, kSecReturnData); - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 0); - is(CFGetTypeID(result), CFDictionaryGetTypeID()); - is(CFDictionaryGetValue(result, kSecValueData), NULL); - CFReleaseSafe(result); - - phase = 0; - CFDictionaryRemoveValue(query, kSecReturnAttributes); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - CFDictionarySetValue(query, kSecAttrTokenID, CFSTR("tokenid")); - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 2); - eq_cf(result, valueData); - CFReleaseSafe(result); - - static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'}; - NSData *persistentRefId = [NSData dataWithBytes:tk_persistent_ref_id length:sizeof(tk_persistent_ref_id)]; - phase = 0; - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrService : @"ctktest-service", - (id)kSecReturnPersistentRef : @YES }, &result)); - is(phase, 0); - NSData *persistentRef = (__bridge NSData *)result; - is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); - CFReleaseSafe(result); - - phase = 0; - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrService : @"ctktest-service", - (id)kSecReturnData : @YES, - (id)kSecReturnPersistentRef : @YES }, &result)); - is(phase, 2); - persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; - is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); - CFReleaseSafe(result); - - phase = 0; - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrService : @"ctktest-service", - (id)kSecReturnAttributes : @YES, - (id)kSecReturnPersistentRef : @YES }, &result)); - is(phase, 0); - persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; - is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); - CFReleaseSafe(result); - - phase = 0; - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecAttrService : @"ctktest-service", - (id)kSecReturnData : @YES, - (id)kSecReturnAttributes : @YES, - (id)kSecReturnPersistentRef : @YES }, &result)); - is(phase, 2); - persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; - is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); - CFReleaseSafe(result); - - CFRelease(query); - CFRelease(valueData); - CFRelease(valueData2); -} - -static void test_item_update() { - static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; - CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1); - CFTypeRef result = NULL; - - CFMutableDictionaryRef query, attrs; - - // Setup token hook. - __block int phase = 0; - __block bool store_value = false; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); - - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - phase++; - eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData2); - if (!store_value) { - CFDictionaryRemoveValue(at, kSecValueData); - } - return CFRetainSafe(objectID); - }; - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase++; - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - phase++; - return CFRetain(valueData2); - }; - }); - - query = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrTokenID, CFSTR("tokenid"), - kSecAttrService, CFSTR("ctktest-service"), - NULL); - - attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecValueData, valueData2, - NULL); - - ok_status(SecItemUpdate(query, attrs)); - is(phase, 3); - - phase = 0; - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &result)); - eq_cf(valueData2, result); - CFRelease(result); - is(phase, 2); - - phase = 0; - store_value = true; - CFDictionaryRemoveValue(query, kSecReturnData); - ok_status(SecItemUpdate(query, attrs)); - is(phase, 3); - - phase = 0; - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &result)); - eq_cf(valueData2, result); - CFRelease(result); - is(phase, 0); - - phase = 0; - CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1")); - CFDictionaryRemoveValue(query, kSecReturnData); - ok_status(SecItemUpdate(query, attrs)); - is(phase, 5); - - phase = 0; - CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 0); - is(CFGetTypeID(result), CFArrayGetTypeID()); - is(CFArrayGetCount(result), 2); - eq_cf(CFArrayGetValueAtIndex(result, 0), valueData2); - eq_cf(CFArrayGetValueAtIndex(result, 1), valueData2); - - CFRelease(query); - CFRelease(attrs); - CFRelease(valueData2); -} - -static void test_item_delete(void) { - - CFMutableDictionaryRef query; - CFTypeRef result; - - __block int phase = 0; - __block CFErrorRef deleteError = NULL; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase++; - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->deleteObject = ^bool(CFDataRef objectID, CFErrorRef *error) { - phase++; - if (deleteError != NULL) { - CFAssignRetained(*error, deleteError); - deleteError = NULL; - return false; - } - return true; - }; - }); - - query = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrTokenID, CFSTR("tokenid"), - kSecAttrService, CFSTR("ctktest-service"), - NULL); - - phase = 0; - ok_status(SecItemDelete(query)); - is(phase, 2); - - phase = 0; - is_status(SecItemCopyMatching(query, &result), errSecItemNotFound); - is(phase, 0); - - phase = 0; - CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1")); - ok_status(SecItemCopyMatching(query, &result)); - is(phase, 0); - - phase = 0; -#if LA_CONTEXT_IMPLEMENTED - LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; }); - deleteError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL); - ok_status(SecItemDelete(query), "delete multiple token items"); - is(phase, 6, "connect + delete-auth-fail + copyAccess + connect + delete + delete-2nd"); -#else - ok_status(SecItemDelete(query), "delete multiple token items"); - is(phase, 3, "connect + delete + delete"); -#endif - - phase = 0; - is_status(SecItemCopyMatching(query, &result), errSecItemNotFound); - is(phase, 0); - - is_status(SecItemDelete(query), errSecItemNotFound); - - CFRelease(query); - CFReleaseSafe(deleteError); -} - -static void test_key_generate(int globalPersistence, int privatePersistence, int publicPersistence, - bool privateIsPersistent, bool publicIsPersistent) { - __block int phase = 0; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase |= 0x01; - - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - id privateKey; - CFTypeRef keyClass = CFDictionaryGetValue(at, kSecAttrKeyClass) ?: kSecAttrKeyClassPrivate; - eq_cf(keyClass, kSecAttrKeyClassPrivate, "only private keys can be created on token"); - NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate }; - if (objectID != NULL) { - phase |= 0x20; - privateKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)objectID, (CFDictionaryRef)params, NULL)); - } else { - phase |= 0x02; - privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, error)); - } - NSDictionary *privKeyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); - CFDictionarySetValue(at, kSecClass, kSecClassKey); - CFDictionarySetValue(at, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); - CFDictionarySetValue(at, kSecAttrKeySizeInBits, CFSTR("256")); - CFDictionarySetValue(at, kSecAttrKeyClass, kSecAttrKeyClassPrivate); - return CFBridgingRetain(privKeyAttrs[(id)kSecValueData]); - }; - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase |= 0x04; - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { - phase |= 0x08; - SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes); - CFDataRef publicData; - SecKeyCopyPublicBytes(privKey, &publicData); - CFRelease(privKey); - return publicData; - }; - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - phase |= 0x10; - return kCFNull; - }; - }); - - NSMutableDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC, - (id)kSecAttrKeySizeInBits: @"256", - (id)kSecAttrTokenID: @"tokenid", - }.mutableCopy; - if (globalPersistence >= 0) { - params[(id)kSecAttrIsPermanent] = globalPersistence ? @YES : @NO; - } - if (publicPersistence >= 0) { - params[(id)kSecPublicKeyAttrs] = @{ (id)kSecAttrIsPermanent: publicPersistence ? @YES : @NO }; - } - if (privatePersistence >= 0) { - params[(id)kSecPrivateKeyAttrs] = @{ (id)kSecAttrIsPermanent: privatePersistence ? @YES : @NO }; - } - - NSError *error; - phase = 0; - id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error)); - isnt(privateKey, nil, "failed to generate token key, error %@", error); - is(phase, privateIsPersistent ? 0x3f : 0x1f); - id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); - isnt(publicKey, nil, "failed to get public key from private key"); - - NSDictionary *query = @{ (id)kSecValueRef: privateKey, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnRef: @YES, - (id)kSecReturnData: @YES }; - phase = 0; - NSDictionary *result; - if (privateIsPersistent) { - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent private key not found in kc"); - is(phase, 0x19); - is(result[(id)kSecValueData], nil); - eq_cf((__bridge CFTypeRef)result[(id)kSecAttrTokenID], @"tokenid"); - NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)result[(id)kSecValueRef])); - eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); - keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); - eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); - } else { - is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral private key found in kc"); - is(phase, 0x08); - - // Balancing test count from the branch above - ok(true); - ok(true); - ok(true); - ok(true); - } - - query = @{ (id)kSecValueRef: publicKey, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnRef: @YES, - (id)kSecReturnData: @YES }; - phase = 0; - result = nil; - if (publicIsPersistent) { - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent public key not found in kc"); - NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); - eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); - } else { - is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral public key found in kc"); - - // Balancing test count from the branch above - ok(true); - } - - // Get OID from the private key and try to create duplicate of the key using its OID and attributes. - NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); - NSData *oid = attrs[(id)kSecAttrTokenOID]; - ok(oid != nil, "private key attributes need OID"); - phase = 0; - id copyKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)[NSData data], - (CFDictionaryRef)@{ (id)kSecAttrTokenID: @"tokenid", (id)kSecAttrTokenOID: oid }, - (void *)&error)); - ok(copyKey != nil, "copied key is created"); - is(phase, 0x21); - attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyKey)); - is(phase, 0x29); - phase = 0; - eq_cf((__bridge CFTypeRef)attrs[(id)kSecClass], kSecClassKey); - eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyClass], kSecAttrKeyClassPrivate); - eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyType], kSecAttrKeyTypeECSECPrimeRandom); - eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeySizeInBits], CFSTR("256")); - eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], CFSTR("tokenid")); - id copyPublicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)copyKey)); - ok(copyPublicKey != nil); - is(phase, 0x08); - NSDictionary *pubAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyPublicKey)); - eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)pubAttrs[(id)kSecAttrApplicationLabel]); -} - -static void test_key_sign(void) { - - static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; - CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); - - __block int phase = 0; - __block CFErrorRef cryptoError = NULL; - __block SecKeyOperationType cryptoOperation = -1; - __block SecKeyAlgorithm cryptoAlgorithm = NULL; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - - blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { - phase++; - SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes); - CFDataRef publicData; - ok_status(SecKeyCopyPublicBytes(privKey, &publicData)); - CFRelease(privKey); - return publicData; - }; - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase++; - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { - SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1); - phase++; - cryptoOperation = operation; - cryptoAlgorithm = algorithm; - if (cryptoError != NULL) { - CFAssignRetained(*error, cryptoError); - cryptoError = NULL; - return NULL; - } - return CFRetainSafe(valueData); - }; - - blocks->copyObjectData = ^CFTypeRef(CFDataRef objectID, CFErrorRef *error) { - phase++; - return kCFNull; - }; - }); - - NSDictionary *query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecReturnRef: @YES }; - - phase = 0; - SecKeyRef privateKey = NULL; - ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey)); - is(phase, 2); - - phase = 0; - CFMutableDataRef sig = CFDataCreateMutable(NULL, 0); - CFDataSetLength(sig, 256); - size_t sigLen = CFDataGetLength(sig); - ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen)); - is(phase, 1); - is(cryptoAlgorithm, kSecKeyAlgorithmECDSASignatureDigestX962); - is(cryptoOperation, kSecKeyOperationTypeSign); - CFDataSetLength(sig, sigLen); - is(CFDataGetLength(sig), CFDataGetLength(valueData)); - eq_cf(valueData, sig); - -#if LA_CONTEXT_IMPLEMENTED - phase = 0; - CFDataSetLength(sig, 256); - sigLen = CFDataGetLength(sig); - LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; }); - cryptoError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL); - ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen)); - is(phase, 4); - is(cryptoError, NULL); - CFDataSetLength(sig, sigLen); - is(CFDataGetLength(sig), CFDataGetLength(valueData)); - eq_cf(valueData, sig); -#endif - - NSError *error; - NSData *result; - result = CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionRaw, - valueData, (void *)&error)); - eq_cf((__bridge CFDataRef)result, valueData); - is(cryptoAlgorithm, kSecKeyAlgorithmRSAEncryptionRaw); - is(cryptoOperation, kSecKeyOperationTypeDecrypt); - - NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256 }; - SecKeyRef otherPrivKey = NULL, otherPubKey = NULL; - ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)params, &otherPubKey, &otherPrivKey)); - - error = nil; - result = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privateKey, kSecKeyAlgorithmECDHKeyExchangeCofactor, - otherPubKey, (CFDictionaryRef)@{}, (void *)&error)); - eq_cf((__bridge CFDataRef)result, valueData); - is(cryptoAlgorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor); - is(cryptoOperation, kSecKeyOperationTypeKeyExchange); - - CFReleaseSafe(otherPrivKey); - CFReleaseSafe(otherPubKey); - CFReleaseSafe(cryptoError); - CFRelease(sig); - CFRelease(privateKey); -} - -static void test_key_generate_with_params(void) { - - const UInt8 data[] = "foo"; - CFDataRef cred_ref = CFDataCreate(NULL, data, 4); - __block int phase = 0; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; - eq_cf(CFDictionaryGetValue(attributes, kSecUseOperationPrompt), CFSTR("prompt")); - is(CFDictionaryGetValue(attributes, kSecUseAuthenticationUI), NULL); - eq_cf(CFDictionaryGetValue(attributes, kSecUseCredentialReference), cred_ref); - - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - phase++; - SecCFCreateError(-4 /* kTKErrorCodeCanceledByUser */, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error); - return NULL; - }; - }); - - CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL, - kSecAttrIsPermanent, kCFBooleanTrue, - NULL); - - CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecAttrKeyType, kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits, CFSTR("256"), - kSecAttrTokenID, CFSTR("tokenid"), - kSecPrivateKeyAttrs, prk_params, - kSecUseOperationPrompt, CFSTR("prompt"), - kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow, - kSecUseCredentialReference, cred_ref, - NULL); - CFRelease(prk_params); - - SecKeyRef publicKey = NULL, privateKey = NULL; - phase = 0; - is_status(SecKeyGeneratePair(params, &publicKey, &privateKey), errSecUserCanceled); - is(phase, 2); - - CFReleaseSafe(publicKey); - CFReleaseSafe(privateKey); - CFRelease(params); - CFRelease(cred_ref); -} - -static void test_error_codes(void) { - - CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecClass, kSecClassGenericPassword, - kSecAttrTokenID, CFSTR("tokenid"), - NULL); - // Setup token hook. - __block OSStatus ctk_error = 0; - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - SecCFCreateError(ctk_error, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error); - return NULL; - }; - }); - - ctk_error = kTKErrorCodeBadParameter; - is_status(SecItemAdd(attrs, NULL), errSecParam); - - ctk_error = kTKErrorCodeNotImplemented; - is_status(SecItemAdd(attrs, NULL), errSecUnimplemented); - - ctk_error = kTKErrorCodeCanceledByUser; - is_status(SecItemAdd(attrs, NULL), errSecUserCanceled); - - CFRelease(attrs); -} - -static CFDataRef copy_certificate_data(const char *base64Cert) -{ - size_t size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), NULL, 0); - ok(size); - CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, size); - CFDataSetLength(data, size); - size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), (char*)CFDataGetMutableBytePtr(data), CFDataGetLength(data)); - ok(size); - CFDataSetLength(data, size); - - return data; -} - -static CFMutableDictionaryRef copy_certificate_attributes(const char *base64Cert) -{ - CFDataRef data = copy_certificate_data(base64Cert); - - SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, data); - ok(cert); - CFDictionaryRef certAttributes = SecCertificateCopyAttributeDictionary(cert); - ok(certAttributes); - CFMutableDictionaryRef result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, certAttributes); - ok(result); - - if (certAttributes) - CFRelease(certAttributes); - if (data) - CFRelease(data); - if (cert) - CFRelease(cert); - - return result; -} - -static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFStringRef oid, CFStringRef tokenID) -{ - CFMutableDictionaryRef certAttributes = copy_certificate_attributes(base64cert); - - CFDictionarySetValue(certAttributes, kSecAttrLabel, label); - CFDictionarySetValue(certAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); - CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid); - CFDictionaryRemoveValue(certAttributes, kSecValueData); - - SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(acl); - CFTypeRef key[] = { kSecAttrTokenID }; - CFTypeRef value[] = { tokenID }; - CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - ok(SecAccessControlSetProtection(acl, protection, NULL)); - CFRelease(protection); - ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef aclData = SecAccessControlCopyData(acl); - ok(aclData); - if (aclData) { - CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData); - CFRelease(aclData); - } - - if (acl) - CFRelease(acl); - - return certAttributes; -} - -static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFStringRef oid, CFStringRef tokenID) -{ - CFMutableDictionaryRef keyAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ; - - CFDictionarySetValue(keyAttributes, kSecClass, kSecClassKey); - CFDictionarySetValue(keyAttributes, kSecAttrKeyClass, kSecAttrKeyClassPrivate); - CFDictionarySetValue(keyAttributes, kSecAttrKeyType, kSecAttrKeyTypeRSA); - CFNumberRef keySize = CFNumberCreateWithCFIndex(kCFAllocatorDefault, 2048); - CFDictionarySetValue(keyAttributes, kSecAttrKeySizeInBits, keySize); - CFRelease(keySize); - - CFDictionarySetValue(keyAttributes, kSecAttrCanDecrypt, kCFBooleanTrue); - CFDictionarySetValue(keyAttributes, kSecAttrCanSign, kCFBooleanTrue); - CFDictionarySetValue(keyAttributes, kSecAttrCanUnwrap, kCFBooleanTrue); - CFDictionarySetValue(keyAttributes, kSecAttrCanDerive, kCFBooleanFalse); - CFDictionarySetValue(keyAttributes, kSecAttrIsPrivate, kCFBooleanTrue); - - CFDictionarySetValue(keyAttributes, kSecAttrLabel, label); - CFDictionarySetValue(keyAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); - CFDictionarySetValue(keyAttributes, kSecAttrTokenOID, oid); - CFDictionarySetValue(keyAttributes, kSecAttrApplicationLabel, CFDictionaryGetValue(certAttributes, kSecAttrPublicKeyHash)); - - SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(acl); - CFTypeRef key[] = { kSecAttrTokenID }; - CFTypeRef value[] = { tokenID }; - CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - ok(SecAccessControlSetProtection(acl, protection, NULL)); - CFRelease(protection); - ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef aclData = SecAccessControlCopyData(acl); - ok(aclData); - if (aclData) { - CFDictionarySetValue(keyAttributes, kSecAttrAccessControl, aclData); - CFRelease(aclData); - } - - if (acl) - CFRelease(acl); - - return keyAttributes; -} - -static void check_array_for_type_id(CFArrayRef array, CFTypeID typeID) -{ - if (array && CFGetTypeID(array) == CFArrayGetTypeID()) { - for (CFIndex i = 0; i < CFArrayGetCount(array); ++i) { - ok(CFGetTypeID(CFArrayGetValueAtIndex(array, i)) == typeID); - } - } -} - -static void test_propagate_token_items() -{ - CFStringRef cert1OID = CFSTR("oid1"); - CFStringRef cert2OID = CFSTR("oid2"); - CFStringRef key1OID = CFSTR("oid3"); - CFStringRef key2OID = CFSTR("oid4"); - - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - if (CFEqual(oid, cert1OID)) { - return copy_certificate_data(cert1); - } - else if (CFEqual(oid, cert2OID)) { - return copy_certificate_data(cert2); - } - else if (CFEqual(oid, key1OID) || CFEqual(oid, key2OID)) { - return kCFNull; - } - else { - return NULL; - } - }; - }); - - CFStringRef tokenID = CFSTR("com.apple.secdtest:propagate_test_token"); - - CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - - CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), cert1OID, tokenID); - ok(certQuery); - CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), key1OID, tokenID); - ok(keyQuery); - - CFArrayAppendValue(items, certQuery); - CFArrayAppendValue(items, keyQuery); - CFReleaseSafe(certQuery); - CFReleaseSafe(keyQuery); - - certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), cert2OID, tokenID); - ok(certQuery); - keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), key2OID, tokenID); - ok(keyQuery); - - CFArrayAppendValue(items, certQuery); - CFArrayAppendValue(items, keyQuery); - CFReleaseSafe(certQuery); - CFReleaseSafe(keyQuery); - - OSStatus result; - ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items."); - - ok_status(result = SecItemUpdateTokenItems(tokenID, items), "Failed to propagate items."); - CFRelease(items); - - CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(query, kSecClass, kSecClassCertificate); - CFDictionarySetValue(query, kSecAttrAccessGroup, CFSTR("com.apple.token")); - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); - CFTypeRef queryResult; - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs"); - check_array_for_type_id(queryResult, SecCertificateGetTypeID()); - CFReleaseNull(queryResult); - - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs"); - check_array_for_type_id(queryResult, CFDataGetTypeID()); - CFReleaseNull(queryResult); - - CFDictionarySetValue(query, kSecClass, kSecClassKey); - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two keys"); - check_array_for_type_id(queryResult, SecKeyGetTypeID()); - CFReleaseNull(queryResult); - - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array"); - CFReleaseNull(queryResult); - - CFDictionarySetValue(query, kSecClass, kSecClassIdentity); - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two identities"); - check_array_for_type_id(queryResult, SecIdentityGetTypeID()); - CFReleaseNull(queryResult); - - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); - ok_status(SecItemCopyMatching(query, &queryResult)); - ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array"); - CFReleaseNull(queryResult); - - ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items."); - - CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); - is_status(SecItemCopyMatching(query, &queryResult), errSecItemNotFound); - CFReleaseNull(queryResult); - CFRelease(query); -} - -static void test_identity_on_two_tokens() { - CFStringRef cert3OID = CFSTR("oid1"); - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - if (CFEqual(oid, cert3OID)) - return copy_certificate_data(cert3); - else - return kCFNull; - }; - - }); - - @autoreleasepool { - NSString *tokenID1 = @"com.apple.secdtest:identity_test_token1"; - NSString *tokenID2 = @"com.apple.secdtest:identity_test_token2"; - - NSError *error; - NSData *privKeyData = [[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters]; - id privKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)privKeyData, (CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate}, (void *)&error)); - id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)privKey)); - NSData *pubKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash((__bridge SecKeyRef)publicKey)); - - id ac = CFBridgingRelease(SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL)); - id acData = CFBridgingRelease(SecAccessControlCopyData((__bridge SecAccessControlRef)ac)); - NSDictionary *keyQuery = @{ (id)kSecClass: (id)kSecClassKey, - (id)kSecAttrTokenID: tokenID1, - (id)kSecAttrKeyType : (id)kSecAttrKeyTypeECSECPrimeRandom, - (id)kSecAttrKeySizeInBits : @"256", - (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, - (id)kSecAttrIsPrivate: @YES, - (id)kSecAttrAccessControl: acData, - (id)kSecAttrTokenOID : privKeyData, - (id)kSecAttrApplicationLabel : pubKeyHash, - }; - OSStatus result; - ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[keyQuery]), "Failed to propagate key item."); - - id privateKey; - ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)@{(id)kSecClass: (id)kSecClassKey, (id)kSecAttrTokenID: tokenID1, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecReturnRef: @YES}, (void *)&privateKey)); - - NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), cert3OID, (__bridge CFStringRef)tokenID2)); - ok(certQuery); - - ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[certQuery]), "Failed to propagate cert item."); - - CFTypeRef resultRef; - NSDictionary *query = @{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; - ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); - CFReleaseNull(resultRef); - - query = @{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; - ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); - CFReleaseNull(resultRef); - - query = @{ (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; - ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); - CFReleaseNull(resultRef); - } -} - -static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) { - TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - - blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - return CFBridgingRetain([@"oid" dataUsingEncoding:NSUTF8StringEncoding]); - }; - - blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { - SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey); - CFDataRef data = SecKeyCopyExternalRepresentation(publicKey, error); - CFReleaseNull(publicKey); - return data; - }; - - blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - return kCFNull; - }; - - blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); - SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); - CFDataRef acData = SecAccessControlCopyData(ac); - CFRelease(ac); - return acData; - }; - - blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { - CFTypeRef result = kCFNull; - CFTypeRef algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1); - switch (operation) { - case kSecKeyOperationTypeKeyExchange: { - if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) || - CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) { - NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes(privateKey)); - NSDictionary *params = @{ - (id)kSecAttrKeyType: attrs[(id)kSecAttrKeyType], - (id)kSecAttrKeySizeInBits: attrs[(id)kSecAttrKeySizeInBits], - (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic, - }; - SecKeyRef pubKey = SecKeyCreateWithData(in1, (CFDictionaryRef)params, error); - if (pubKey == NULL) { - return NULL; - } - result = SecKeyCopyKeyExchangeResult(privateKey, algorithm, pubKey, in2, error); - CFReleaseSafe(pubKey); - } - break; - } - case kSecKeyOperationTypeDecrypt: { - if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { - result = SecKeyCreateDecryptedData(privateKey, algorithm, in1, error); - } - break; - } - default: - break; - } - return result; - }; - }); - - NSDictionary *privateParams = CFBridgingRelease(SecKeyCopyAttributes(privateKey)); - NSDictionary *params = @{ (id)kSecAttrKeyType : privateParams[(id)kSecAttrKeyType], - (id)kSecAttrKeySizeInBits : privateParams[(id)kSecAttrKeySizeInBits], - (id)kSecAttrTokenID : @"tid-ies", - (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @YES } - }; - NSError *error; - SecKeyRef tokenKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error); - ok(tokenKey != NULL, "create token-based key (err %@)", error); - SecKeyRef tokenPublicKey = SecKeyCopyPublicKey(tokenKey); - - NSData *plaintext = [@"plaintext" dataUsingEncoding:NSUTF8StringEncoding]; - - error = nil; - NSData *ciphertext = CFBridgingRelease(SecKeyCreateEncryptedData(tokenPublicKey, algorithm, (CFDataRef)plaintext, (void *)&error)); - ok(ciphertext, "failed to encrypt IES, err %@", error); - - NSData *decrypted = CFBridgingRelease(SecKeyCreateDecryptedData(tokenKey, algorithm, (CFDataRef)ciphertext, (void *)&error)); - ok(decrypted, "failed to decrypt IES, err %@", error); - - eq_cf((__bridge CFDataRef)plaintext, (__bridge CFDataRef)decrypted, "decrypted(%@) != plaintext(%@)", decrypted, plaintext); - - CFReleaseNull(tokenKey); - CFReleaseNull(tokenPublicKey); -} - -static void test_ecies() { - NSError *error; - SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error); - ok(privateKey != NULL, "failed to generate CPU EC key: %@", error); - - test_ies(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); - - CFReleaseNull(privateKey); -} - -static void test_rsawrap() { - NSError *error; - SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048}, (void *)&error); - ok(privateKey != NULL, "failed to generate CPU RSA key: %@", error); - - test_ies(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM); - - CFReleaseNull(privateKey); -} - -static void tests(void) { - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_33_keychain_ctk", NULL); - - test_item_add(); - test_item_query(); - test_item_update(); - test_item_delete(); - - // params: int globalPersistence, int privatePersistence, int publicPersistence, bool privateIsPersistent, bool publicIsPersistent - test_key_generate(-1, -1, -1, true, false); - test_key_generate(0, -1, -1, false, false); - test_key_generate(1, -1, -1, true, true); - test_key_generate(-1, 0, 0, false, false); - test_key_generate(-1, 1, 0, true, false); - test_key_generate(-1, 0, 1, false, true); - test_key_generate(-1, 1, 1, true, true); - test_key_generate(0, 1, 1, true, true); - test_key_generate(1, 1, 1, true, true); - - test_key_sign(); - test_key_generate_with_params(); - test_error_codes(); - test_propagate_token_items(); - test_identity_on_two_tokens(); - test_rsawrap(); - test_ecies(); -} - -int secd_33_keychain_ctk(int argc, char *const *argv) { - plan_tests(491); - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m b/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m deleted file mode 100644 index e860ca41..00000000 --- a/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (c) 2008-2010,2013 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "secd_regressions.h" - -#include - -#include "SecdTestKeychainUtilities.h" - -/* Keybag and exported plist data. */ -static const unsigned char backup_data[] = { - 0x30, 0x82, 0x06, 0xf4, 0x04, 0x82, 0x06, 0xf0, 0x56, 0x45, 0x52, 0x53, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x54, 0x59, 0x50, 0x45, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x55, 0x55, 0x49, 0x44, - 0x00, 0x00, 0x00, 0x10, 0x60, 0x5e, 0x34, 0x57, 0xbe, 0xa0, 0x48, 0xd6, - 0x9b, 0x22, 0xfa, 0x80, 0xff, 0x3a, 0xe9, 0x9b, 0x48, 0x4d, 0x43, 0x4b, - 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x52, 0x41, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x53, 0x41, 0x4c, 0x54, - 0x00, 0x00, 0x00, 0x14, 0x50, 0x2e, 0x97, 0xc6, 0xfa, 0xed, 0x9b, 0xc0, - 0x6f, 0x09, 0x2a, 0xca, 0x29, 0x38, 0x47, 0x34, 0x9f, 0xc0, 0x29, 0x7e, - 0x49, 0x54, 0x45, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x27, 0x10, - 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x6f, 0x6a, 0x84, 0xd0, - 0x73, 0x27, 0x4a, 0xbc, 0xb3, 0x28, 0xb4, 0xa4, 0xc5, 0x36, 0x4a, 0xdf, - 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0b, - 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, - 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x69, 0xa7, 0xb1, 0xcd, - 0x86, 0x2c, 0xc4, 0xc4, 0x81, 0x52, 0xb3, 0xe7, 0xf9, 0x78, 0xad, 0xec, - 0xaf, 0xc4, 0xe1, 0x71, 0xc9, 0x98, 0xca, 0xb4, 0xa8, 0x86, 0xdc, 0xe9, - 0xcf, 0x48, 0xce, 0x82, 0xa4, 0xeb, 0xf4, 0x43, 0x6d, 0xb0, 0xee, 0x05, - 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xcf, 0x0b, 0x7c, 0x16, - 0xa1, 0x69, 0x16, 0x1f, 0x52, 0x5a, 0xb5, 0x16, 0xa2, 0x75, 0xe0, 0x5f, - 0xb2, 0x55, 0x53, 0xed, 0x10, 0xc6, 0xd1, 0x4d, 0x47, 0x65, 0xe6, 0xcb, - 0xd0, 0x77, 0x12, 0x56, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x5c, 0x1d, 0x0e, 0xde, 0x90, 0xac, 0x45, 0x1f, 0xa1, 0x10, 0x75, 0x84, - 0xf4, 0x9c, 0xe9, 0x65, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0a, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xdd, 0xd8, 0xfa, 0x79, 0x6a, 0x6a, 0x63, 0xfc, 0x40, 0xf2, 0xa9, 0x1d, - 0xe9, 0xf1, 0xf6, 0xdb, 0x14, 0xc4, 0x55, 0x52, 0x80, 0x2e, 0xe3, 0x48, - 0x91, 0x53, 0x17, 0xd9, 0xb6, 0x91, 0x05, 0x42, 0x25, 0xa3, 0xb8, 0xc7, - 0x95, 0x21, 0x14, 0xb7, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, - 0x48, 0xb5, 0xd3, 0xe5, 0xdb, 0xc5, 0x3b, 0x20, 0x23, 0x35, 0x4f, 0xd4, - 0x28, 0xe5, 0x43, 0x59, 0xaf, 0x74, 0xd3, 0x40, 0xd3, 0x24, 0x7c, 0x0a, - 0xe7, 0x86, 0x9e, 0xde, 0x96, 0x6d, 0xdb, 0x3a, 0x55, 0x55, 0x49, 0x44, - 0x00, 0x00, 0x00, 0x10, 0xc7, 0x1f, 0xde, 0xb6, 0xb0, 0x49, 0x42, 0x90, - 0x90, 0x32, 0xbf, 0x39, 0x84, 0x9d, 0xb3, 0xa1, 0x43, 0x4c, 0x41, 0x53, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x57, 0x52, 0x41, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x28, 0xc7, 0xbd, 0xb5, 0x0a, 0x70, 0x1a, 0xe6, 0xfb, - 0x39, 0x0a, 0x4a, 0x2d, 0x45, 0xf9, 0x5f, 0xb1, 0xc8, 0xdc, 0x88, 0x1a, - 0x26, 0xf1, 0xaa, 0x1a, 0xb5, 0xd9, 0xbf, 0xce, 0x1f, 0x7e, 0x69, 0xb2, - 0xdc, 0xbe, 0x48, 0x59, 0xea, 0xf0, 0x04, 0xba, 0x50, 0x42, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x20, 0x93, 0x26, 0xff, 0x91, 0xd0, 0x28, 0x45, 0x27, - 0x4c, 0xf0, 0x83, 0xa4, 0x39, 0x38, 0x30, 0xb5, 0x62, 0x18, 0xdc, 0xe2, - 0x9a, 0x50, 0xf7, 0xd4, 0x01, 0x38, 0xa0, 0x61, 0x69, 0x2b, 0x38, 0x6c, - 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0xdc, 0x23, 0x9d, 0x5c, - 0xdd, 0xf6, 0x4c, 0xa0, 0xbf, 0x63, 0x6e, 0xe8, 0x40, 0xaa, 0x43, 0xbf, - 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, - 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, - 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x68, 0xf5, 0x29, 0x43, - 0x1c, 0x42, 0x59, 0x83, 0xb8, 0x0d, 0x12, 0xf6, 0x7f, 0x6d, 0x66, 0xbe, - 0xdd, 0xaf, 0x05, 0x90, 0x52, 0xe7, 0x03, 0xea, 0x8a, 0x03, 0xc2, 0x6f, - 0x9c, 0x47, 0xb1, 0xea, 0x88, 0x08, 0x19, 0x2d, 0x00, 0x3b, 0x5b, 0x79, - 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xb4, 0x25, 0xc5, 0xa3, - 0x85, 0xe4, 0x62, 0x53, 0x62, 0xd7, 0x0c, 0x69, 0xb9, 0x6d, 0x04, 0xe0, - 0x5a, 0xbf, 0x1a, 0x79, 0xa5, 0x48, 0x26, 0x67, 0x9e, 0x3a, 0xc8, 0x42, - 0x18, 0xca, 0x75, 0x0c, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0xb5, 0xc8, 0x18, 0xb8, 0x8f, 0xea, 0x40, 0xe7, 0x88, 0xcd, 0xf4, 0xc5, - 0x96, 0xb8, 0x92, 0xf1, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x07, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xaa, 0x8a, 0x3c, 0x92, 0xea, 0x65, 0xa9, 0xdb, 0x3a, 0x36, 0x01, 0x54, - 0x2e, 0x62, 0xc6, 0xd2, 0x46, 0x75, 0x61, 0xac, 0x5d, 0xbb, 0x62, 0xaa, - 0xc3, 0xed, 0xbf, 0x14, 0x35, 0x13, 0x21, 0x2f, 0x47, 0x7d, 0x57, 0x07, - 0xf1, 0x80, 0xa4, 0xcc, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, - 0x3e, 0xb4, 0x78, 0x54, 0xd2, 0x19, 0xaf, 0xe4, 0x4c, 0x84, 0x02, 0xd0, - 0xf4, 0x50, 0xde, 0xd6, 0x44, 0xc9, 0xdf, 0x4b, 0x8d, 0x81, 0x2a, 0x2d, - 0xbb, 0xf1, 0x94, 0xd0, 0x4e, 0x57, 0xfa, 0x4e, 0x55, 0x55, 0x49, 0x44, - 0x00, 0x00, 0x00, 0x10, 0x59, 0x3c, 0xc5, 0xc5, 0xf2, 0x39, 0x4a, 0x44, - 0x90, 0xd4, 0xb1, 0x07, 0x17, 0x00, 0x64, 0x34, 0x43, 0x4c, 0x41, 0x53, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x57, 0x52, 0x41, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x28, 0x79, 0xdd, 0x59, 0x01, 0x1f, 0x45, 0xe4, 0x01, - 0x32, 0xb5, 0xae, 0x5e, 0x17, 0xd7, 0x6c, 0xc6, 0x1d, 0x28, 0xf0, 0x32, - 0x4a, 0x18, 0xff, 0x30, 0x2c, 0xe4, 0xcb, 0x7c, 0x58, 0x53, 0x00, 0x8b, - 0xb9, 0xdd, 0x71, 0x5f, 0xbc, 0x66, 0x9b, 0x4c, 0x50, 0x42, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x20, 0xc3, 0x2d, 0xc7, 0x4f, 0xb1, 0x7b, 0x3c, 0x9d, - 0xcb, 0xf4, 0xd6, 0x45, 0x20, 0x35, 0xbc, 0x3a, 0x6c, 0x13, 0x1d, 0x7c, - 0x63, 0x53, 0x17, 0xc9, 0x84, 0x86, 0xbd, 0x96, 0xb0, 0xa4, 0x39, 0x03, - 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0xcb, 0x2c, 0x33, 0x2e, - 0x69, 0x39, 0x43, 0xe5, 0x87, 0xbb, 0xbc, 0xd4, 0x47, 0xa4, 0x86, 0x7b, - 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, - 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, - 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x6f, 0x62, 0x11, 0xb0, - 0xdf, 0x5a, 0x39, 0x43, 0xe9, 0xc3, 0xc5, 0x0b, 0x1c, 0x57, 0x6f, 0x79, - 0x0d, 0x44, 0x9f, 0x44, 0xf2, 0x51, 0x1e, 0x68, 0xb8, 0xcf, 0x5c, 0x6d, - 0x94, 0x86, 0x86, 0x70, 0x12, 0xc1, 0x76, 0xc0, 0x18, 0xe4, 0x58, 0x1a, - 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0x6f, 0xba, 0xbd, 0x37, - 0x58, 0x5f, 0x96, 0x4d, 0x4c, 0x92, 0xbb, 0xf0, 0x43, 0xec, 0x84, 0xc3, - 0x68, 0x75, 0xf1, 0xd2, 0x04, 0x0d, 0xda, 0x8a, 0xec, 0xac, 0x02, 0xf7, - 0xf7, 0x4d, 0xf4, 0x0e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0x8d, 0xa4, 0xb5, 0x6b, 0x95, 0x12, 0x46, 0xff, 0x9e, 0x1f, 0xdd, 0x2f, - 0xc0, 0x60, 0xc6, 0xd6, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0xa8, 0xa2, 0x8d, 0xe2, 0x16, 0xd8, 0xce, 0x18, 0x2c, 0x8e, 0xa4, 0x8d, - 0x32, 0xba, 0x83, 0xdb, 0x5e, 0xc8, 0x04, 0x59, 0x72, 0xca, 0x72, 0xe5, - 0x6f, 0xcd, 0x06, 0x98, 0xde, 0x4b, 0xcf, 0xa6, 0xd1, 0xe3, 0xba, 0x9b, - 0x68, 0xa6, 0xe5, 0xa2, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, - 0x46, 0x45, 0x3a, 0xc1, 0x62, 0x14, 0xd7, 0x3f, 0x8c, 0x7a, 0x66, 0x1d, - 0x4b, 0x5c, 0x86, 0x43, 0x75, 0xe6, 0x93, 0xf1, 0x31, 0x6b, 0x20, 0x8b, - 0x18, 0x87, 0x84, 0xcc, 0x92, 0xfc, 0xb3, 0x32, 0x55, 0x55, 0x49, 0x44, - 0x00, 0x00, 0x00, 0x10, 0xd8, 0x36, 0xc5, 0xf9, 0x76, 0x4b, 0x4c, 0x2c, - 0x8c, 0xaa, 0xf4, 0x62, 0xab, 0x14, 0xd5, 0x08, 0x43, 0x4c, 0x41, 0x53, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x57, 0x52, 0x41, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x28, 0x0c, 0xe1, 0xb2, 0xee, 0x08, 0xdb, 0xe4, 0xee, - 0xb5, 0x49, 0xd5, 0x3a, 0xe7, 0xd9, 0xbd, 0xf6, 0xab, 0x0e, 0x1a, 0x2a, - 0x16, 0x6c, 0x82, 0x88, 0x5e, 0x39, 0xf6, 0x89, 0xcf, 0x5c, 0x69, 0x3c, - 0x67, 0x56, 0x16, 0xa1, 0x2c, 0xf4, 0x7d, 0xb9, 0x50, 0x42, 0x4b, 0x59, - 0x00, 0x00, 0x00, 0x20, 0xc1, 0x54, 0xd5, 0xb9, 0xf1, 0x16, 0xe9, 0xb2, - 0x9b, 0x79, 0x73, 0x7a, 0xb7, 0x95, 0x0a, 0xdb, 0x15, 0x20, 0x4d, 0xa7, - 0x0f, 0x5d, 0xed, 0x1c, 0x95, 0x63, 0xec, 0xf8, 0xf0, 0xf2, 0x30, 0x75, - 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x48, 0xf3, 0x98, 0x06, - 0xfe, 0xb8, 0x4e, 0xd6, 0xa9, 0xb3, 0xe1, 0xa2, 0x1f, 0xb0, 0x7b, 0xcd, - 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, - 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, - 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x01, 0x8a, 0x2c, 0x90, - 0x67, 0x3f, 0xe0, 0xf8, 0xb1, 0xbb, 0x86, 0x7f, 0xdc, 0xcd, 0xfd, 0x22, - 0x98, 0x54, 0x30, 0x75, 0x49, 0xd1, 0xe8, 0xc2, 0x85, 0x51, 0x5b, 0xae, - 0xfa, 0x3f, 0xf8, 0xfc, 0xf8, 0xa6, 0xf9, 0xa0, 0x80, 0xa5, 0x3b, 0x87, - 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xa6, 0x4f, 0x13, 0x8a, - 0x52, 0xe5, 0x5a, 0x65, 0x69, 0xd4, 0x70, 0xc8, 0xc7, 0xec, 0xbd, 0x27, - 0x3a, 0xcd, 0xd0, 0xb4, 0x61, 0x5d, 0xf4, 0x81, 0x67, 0xe5, 0x63, 0x77, - 0xbd, 0x4d, 0xb5, 0x0f, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, - 0xa9, 0x3b, 0xd2, 0x02, 0x4f, 0x72, 0x46, 0x32, 0x99, 0xa6, 0x7b, 0x62, - 0xaa, 0x11, 0xf4, 0x67, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, - 0x8d, 0xae, 0x30, 0xf1, 0x0f, 0x88, 0x7a, 0x8a, 0xb7, 0x34, 0xc9, 0x50, - 0x02, 0x20, 0x40, 0x3c, 0xce, 0xd2, 0xa9, 0xe7, 0x5a, 0x3a, 0xad, 0xad, - 0xac, 0xdc, 0x3a, 0xc2, 0x92, 0x9d, 0x33, 0x7a, 0x73, 0x78, 0x8a, 0x37, - 0x04, 0x2b, 0xbd, 0xf2, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, - 0x72, 0x9c, 0x52, 0x44, 0xf0, 0xdd, 0xe1, 0x4a, 0x9e, 0x7b, 0x99, 0xec, - 0x64, 0x66, 0x5d, 0xde, 0xe4, 0x8d, 0x72, 0x87, 0xee, 0xd8, 0x66, 0xad, - 0x7d, 0x06, 0x0c, 0x98, 0xc9, 0x2f, 0xfb, 0x19, 0x31, 0x82, 0x03, 0x14, - 0x30, 0x0d, 0x0c, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0c, 0x04, 0x67, - 0x65, 0x6e, 0x70, 0x30, 0x1c, 0x0c, 0x04, 0x68, 0x61, 0x73, 0x68, 0x04, - 0x14, 0xac, 0x28, 0x52, 0x3c, 0xba, 0x05, 0xe5, 0xbd, 0x68, 0x3d, 0xd2, - 0x4c, 0xfb, 0x66, 0x80, 0xb3, 0xdf, 0xdc, 0x1f, 0x0f, 0x30, 0x82, 0x02, - 0xe3, 0x0c, 0x04, 0x64, 0x61, 0x74, 0x61, 0x04, 0x82, 0x02, 0xd9, 0x03, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xf1, - 0xa8, 0xb7, 0x9d, 0x4b, 0xb4, 0x44, 0x5b, 0xb7, 0x75, 0x4e, 0x73, 0x60, - 0xd9, 0xa9, 0x40, 0x08, 0xb0, 0xd9, 0x40, 0xd2, 0x9a, 0x01, 0xf1, 0x58, - 0x87, 0x0d, 0xb2, 0x37, 0xee, 0x3a, 0x76, 0xbe, 0x3c, 0x31, 0x6c, 0x93, - 0xa2, 0xd0, 0x8e, 0xf7, 0x5c, 0x97, 0x25, 0x69, 0xbc, 0xd1, 0x52, 0x73, - 0x32, 0xf4, 0x38, 0x13, 0xda, 0x86, 0xab, 0x6f, 0xe9, 0x6c, 0x4a, 0xeb, - 0xc4, 0x7a, 0xd8, 0x53, 0x03, 0x86, 0x48, 0x4f, 0x11, 0x1a, 0x1b, 0xa9, - 0x17, 0x21, 0xc3, 0x97, 0x12, 0xb6, 0x77, 0x03, 0xba, 0x22, 0x96, 0x0a, - 0x90, 0x01, 0x84, 0xd6, 0x5e, 0x2e, 0x3e, 0x8e, 0x50, 0xb7, 0x48, 0x38, - 0xb6, 0x7f, 0x77, 0x08, 0xf1, 0x2e, 0x5f, 0x3e, 0xda, 0x67, 0xff, 0xa4, - 0x82, 0x89, 0xad, 0xfa, 0x46, 0x38, 0x23, 0x35, 0xb3, 0x8f, 0x5d, 0x31, - 0x2e, 0x39, 0x08, 0x0a, 0x90, 0xe5, 0x5b, 0xf0, 0xc6, 0xb2, 0xa9, 0x8a, - 0x6f, 0x31, 0x5a, 0xbd, 0x6f, 0x74, 0x17, 0x67, 0xb4, 0x0c, 0x4b, 0xd8, - 0xf6, 0x4d, 0x25, 0xca, 0x06, 0xc0, 0x95, 0xf5, 0x70, 0x16, 0xb9, 0x49, - 0xbd, 0xaa, 0x73, 0xb5, 0xed, 0x4d, 0xb1, 0x92, 0x78, 0x28, 0xf7, 0x0d, - 0xbb, 0x73, 0x3d, 0x24, 0x78, 0x19, 0x55, 0xbb, 0x9b, 0x4e, 0xe6, 0x3b, - 0x84, 0x69, 0xd5, 0xbd, 0x3a, 0xcb, 0x8c, 0x70, 0x28, 0x10, 0x8c, 0x5c, - 0xfe, 0xb1, 0x0a, 0x2a, 0x7f, 0xb9, 0xbb, 0x32, 0xab, 0xc5, 0xf6, 0xfd, - 0x66, 0xb7, 0xf7, 0xce, 0x63, 0xcc, 0x05, 0x25, 0xd0, 0x0b, 0x37, 0x94, - 0xbc, 0x1f, 0x0d, 0x80, 0x6b, 0x6c, 0xfd, 0x5a, 0x62, 0xd6, 0xca, 0x3e, - 0x9a, 0x5f, 0x23, 0xfd, 0xc6, 0x9b, 0x65, 0xd4, 0x2a, 0x80, 0x51, 0x45, - 0x08, 0xe6, 0xc8, 0x20, 0x16, 0xb0, 0xb8, 0xc6, 0xee, 0x17, 0xb5, 0x6f, - 0x6f, 0xb5, 0x75, 0xb3, 0x14, 0x03, 0x68, 0xab, 0x99, 0x69, 0xf8, 0x87, - 0x70, 0x5c, 0x6f, 0x45, 0x7b, 0x49, 0xee, 0xb6, 0xbb, 0x3c, 0x0c, 0x50, - 0x90, 0x7c, 0x4c, 0xab, 0xca, 0x81, 0x80, 0x48, 0x5d, 0x13, 0xa2, 0x9e, - 0xf6, 0xfd, 0x2d, 0x57, 0x1d, 0xf0, 0x01, 0xc0, 0x7e, 0x69, 0x69, 0x83, - 0x81, 0x25, 0x70, 0x81, 0x66, 0x26, 0xa3, 0x0f, 0xb7, 0x56, 0x27, 0xcd, - 0x3b, 0x30, 0x45, 0x97, 0x5c, 0x69, 0x56, 0xa1, 0x22, 0x94, 0x87, 0x4b, - 0xd2, 0xf3, 0xc3, 0x92, 0x6d, 0x7d, 0xe3, 0x04, 0x0b, 0xa7, 0x07, 0x42, - 0x9e, 0x58, 0xd0, 0xbf, 0xa2, 0xd2, 0x52, 0xf2, 0xc5, 0xdd, 0xe7, 0x1f, - 0x2e, 0x01, 0x8b, 0xd5, 0xb5, 0x48, 0xb0, 0x94, 0xfb, 0xc4, 0xf8, 0x44, - 0x6c, 0xde, 0xbb, 0x6a, 0xf7, 0xd7, 0x9f, 0x2f, 0x33, 0x07, 0xca, 0xa6, - 0x70, 0x76, 0x58, 0x33, 0x51, 0x6f, 0x34, 0xf8, 0x5e, 0xbf, 0x84, 0xb4, - 0x6e, 0x56, 0x47, 0x12, 0xa2, 0xd1, 0xa1, 0xbb, 0xf1, 0xed, 0x41, 0xd7, - 0x54, 0x49, 0xec, 0x0e, 0x5f, 0x65, 0x84, 0x8e, 0xbe, 0xa0, 0x2a, 0xaa, - 0xe7, 0xff, 0xf3, 0xc0, 0x9d, 0x07, 0xc9, 0xe4, 0xfd, 0x9c, 0x78, 0x6f, - 0x94, 0x9a, 0xab, 0xe5, 0x4b, 0x41, 0x0c, 0x5b, 0x18, 0x40, 0x2c, 0xca, - 0x45, 0xd0, 0x91, 0xc3, 0x99, 0xfa, 0xc1, 0x99, 0xf5, 0x37, 0xf6, 0x2f, - 0x7c, 0x46, 0x4b, 0xea, 0xb9, 0x13, 0xf7, 0x34, 0x31, 0x90, 0x68, 0xa0, - 0xa5, 0x41, 0xfe, 0x45, 0xcd, 0x47, 0x62, 0x9d, 0x92, 0x8a, 0xf6, 0x0b, - 0xdd, 0x26, 0x13, 0x98, 0x8e, 0x8b, 0x42, 0xd9, 0x6c, 0x72, 0x61, 0x07, - 0x05, 0xf0, 0x7f, 0xe0, 0x44, 0x44, 0x02, 0x23, 0xf0, 0x33, 0xc2, 0xe1, - 0x5c, 0x85, 0x57, 0xc8, 0x4a, 0x73, 0xf4, 0x09, 0xba, 0xbd, 0x6f, 0xd0, - 0x3f, 0x76, 0x23, 0xd6, 0x14, 0x81, 0x07, 0x05, 0x08, 0xdb, 0x73, 0x43, - 0x65, 0xfd, 0xcf, 0x4f, 0x93, 0xdd, 0xe6, 0x44, 0x5e, 0xed, 0x1b, 0xf5, - 0x5d, 0x9e, 0xc3, 0xc1, 0x4d, 0x6b, 0x5c, 0xa2, 0xf7, 0x60, 0xd8, 0xb6, - 0x6e, 0x3e, 0xe8, 0x32, 0xc6, 0x24, 0xbb, 0xae, 0xa6, 0x3b, 0x1d, 0x6a, - 0x06, 0x3c, 0x2c, 0x6b, 0x4a, 0x33, 0x4d, 0x6c, 0xd6, 0xc4, 0x1b, 0xb2, - 0x2e, 0xcc, 0x92, 0x1b, 0xc8, 0xd4, 0xdd, 0xd8, 0x18, 0x1a, 0x1b, 0x9b, - 0xb4, 0xc7, 0xf7, 0xcc, 0xbb, 0x67, 0x02, 0x40, 0x94, 0x82, 0x36, 0xa4, - 0x3c, 0x3d, 0x6a, 0xf2, 0xcf, 0x58, 0x67, 0x7d, 0x7f, 0xd0, 0x17, 0x01, - 0xdf, 0xe4, 0xc3, 0xf7, 0x2d, 0x9d, 0x69, 0x19, 0x36, 0x3a, 0x9f, 0xcb, - 0xd5, 0x09, 0xf7, 0x4c, 0x61, 0x06, 0x59, 0xf9, 0x0b, 0x89, 0x9e, 0x73, - 0x9f, 0x44, 0x4e, 0x2e, 0x3d, 0xc0, 0xdd, 0xae, 0x70, 0x36, 0x58, 0x11, - 0xab, 0x0d, 0x73, 0xc2, 0x24, 0x45, 0x7d, 0x5e, 0xd2, 0x6a, 0xc0, 0xa1, - 0x0e, 0x86, 0x52, 0x01, 0xe8, 0xea, 0xce, 0x80, 0x97, 0x9f, 0xfa, 0x69, - 0xb9, 0x2d, 0x9a, 0xd3, 0xd9, 0xee, 0xc4, 0x36, 0xc7, 0x61, 0xdd, 0xe0, - 0xe7, 0xb4, 0xbe, 0x81, 0x54, 0x92, 0x89, 0x44, 0x9f, 0x3b, 0x77, 0x9b, - 0xcd, 0x17, 0xf2, 0x48, 0xd7, 0x1a, 0x46, 0xaf, 0x88, 0x9c, 0x0f, 0xc1, - 0x2b, 0x1e, 0x3d, 0xe5, 0x8e, 0xb3, 0x9b, 0xa0, 0x4b, 0xe6, 0x3f, 0xf4, - 0x27, 0xc4, 0xc9, 0x2c, 0x23, 0xc0, 0x26, 0xf3, 0x02, 0x02, 0x03, 0xe7, - 0x31, 0x82, 0x03, 0x14, 0x30, 0x0d, 0x0c, 0x05, 0x63, 0x6c, 0x61, 0x73, - 0x73, 0x0c, 0x04, 0x67, 0x65, 0x6e, 0x70, 0x30, 0x1c, 0x0c, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x04, 0x14, 0x20, 0x5a, 0x6b, 0x14, 0x4b, 0x34, 0x12, - 0xc6, 0x71, 0x8c, 0xe4, 0xa8, 0x07, 0x83, 0x0e, 0xe0, 0x6f, 0x2d, 0xe6, - 0x13, 0x30, 0x82, 0x02, 0xe3, 0x0c, 0x04, 0x64, 0x61, 0x74, 0x61, 0x04, - 0x82, 0x02, 0xd9, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, - 0x00, 0x00, 0x00, 0x0d, 0x9c, 0x25, 0x6a, 0x30, 0x5b, 0x92, 0x39, 0xe8, - 0x4c, 0x61, 0x06, 0x44, 0x0f, 0xb1, 0x58, 0x6f, 0x0f, 0x5f, 0x4c, 0x8d, - 0xdb, 0x59, 0x69, 0x90, 0xd4, 0x2f, 0x4e, 0x78, 0xa9, 0x62, 0x1d, 0xbc, - 0xad, 0x25, 0x38, 0xb7, 0x05, 0xa3, 0x79, 0x94, 0xc7, 0x2c, 0x4f, 0x67, - 0xf3, 0x76, 0xf4, 0xf8, 0x58, 0x34, 0x85, 0x80, 0x2e, 0x3c, 0x90, 0xef, - 0xe7, 0xc2, 0x08, 0xd7, 0x6a, 0xdd, 0xba, 0xae, 0x55, 0x27, 0xd3, 0x42, - 0x27, 0x5d, 0x7e, 0x0e, 0xe5, 0x8e, 0xe9, 0xd5, 0x42, 0x3b, 0x48, 0x70, - 0x40, 0x25, 0xf5, 0xbe, 0xb6, 0x4e, 0x10, 0xf7, 0xe5, 0x60, 0x9d, 0xd7, - 0x8b, 0x63, 0x40, 0xf0, 0x8b, 0xa2, 0xf3, 0xd6, 0x04, 0xaf, 0x54, 0xa5, - 0xeb, 0x52, 0x80, 0x1a, 0xa8, 0xe0, 0xf7, 0x9b, 0x45, 0x94, 0x36, 0xee, - 0x40, 0xfd, 0xad, 0x2c, 0xf0, 0x92, 0x8e, 0x4a, 0x98, 0x80, 0xed, 0x43, - 0xd3, 0x17, 0xa6, 0xab, 0x96, 0xb4, 0x17, 0x1e, 0xab, 0xb4, 0x6b, 0x74, - 0x43, 0x7c, 0xd9, 0xe1, 0x66, 0x6f, 0x07, 0x20, 0x53, 0x66, 0xe6, 0x60, - 0xbf, 0x92, 0x73, 0x46, 0xfb, 0xb0, 0x81, 0xea, 0xf2, 0xac, 0x13, 0xf7, - 0xbb, 0xd4, 0x38, 0x1b, 0x64, 0xd3, 0xc3, 0x34, 0x37, 0x2c, 0xbc, 0x7d, - 0x36, 0x88, 0xb1, 0x90, 0xcd, 0x9e, 0xee, 0xaf, 0xcb, 0x63, 0x3f, 0x8a, - 0xf5, 0x1a, 0xfc, 0x21, 0xb2, 0xf0, 0xc0, 0x60, 0x72, 0xc7, 0xf0, 0x54, - 0x3e, 0x88, 0x4c, 0x69, 0x96, 0xc2, 0x2b, 0x25, 0x96, 0x41, 0x05, 0xd7, - 0xc6, 0x89, 0xe8, 0x33, 0x1c, 0x7a, 0x88, 0x81, 0xfe, 0xb2, 0x3d, 0x6f, - 0x60, 0x43, 0x1e, 0x62, 0x48, 0x76, 0xd2, 0xe6, 0xfb, 0x22, 0x8a, 0x5d, - 0xe6, 0xd8, 0xe2, 0x30, 0x51, 0x2f, 0xcc, 0xab, 0xb0, 0x31, 0x68, 0x43, - 0x51, 0x11, 0x67, 0x09, 0x3c, 0x34, 0x7e, 0x49, 0xe0, 0xe0, 0xd4, 0x74, - 0xe4, 0x17, 0x42, 0x32, 0x76, 0x3a, 0x2f, 0xc1, 0x8a, 0xb3, 0xfc, 0xdc, - 0x54, 0x00, 0x05, 0x00, 0x8b, 0x07, 0x70, 0xbb, 0xc1, 0x97, 0x33, 0x9f, - 0x93, 0x2c, 0xc1, 0xc8, 0x3b, 0xfb, 0x99, 0xe8, 0x3e, 0x60, 0x20, 0x7d, - 0xb7, 0x77, 0x20, 0x61, 0xda, 0xfb, 0x66, 0xa9, 0x0e, 0x5c, 0x65, 0x30, - 0x4d, 0x39, 0x6b, 0x39, 0xb6, 0xe3, 0x16, 0xc2, 0x01, 0x2b, 0x0d, 0x0b, - 0x95, 0xa7, 0x45, 0x40, 0xb8, 0x93, 0xaf, 0x97, 0x8c, 0x63, 0xab, 0x4f, - 0x9e, 0x90, 0x98, 0xda, 0xe7, 0x84, 0x41, 0xcc, 0xed, 0xb5, 0xc0, 0x35, - 0xa6, 0x1b, 0xe5, 0x51, 0x7f, 0xaa, 0x44, 0xd0, 0x32, 0x0c, 0x04, 0xfa, - 0x34, 0x4d, 0xb4, 0x3a, 0xd0, 0x4e, 0xc8, 0xcb, 0x6d, 0x98, 0x42, 0xad, - 0xc4, 0xe3, 0x38, 0x39, 0xc8, 0x21, 0x6a, 0xb5, 0x7f, 0x00, 0x99, 0x58, - 0x69, 0x5e, 0xd8, 0xe7, 0x43, 0x09, 0x7f, 0x7d, 0x65, 0xe9, 0xe1, 0x1e, - 0xa8, 0x60, 0x83, 0x5b, 0xa9, 0x87, 0xca, 0xe6, 0xf4, 0x27, 0xab, 0x93, - 0x8b, 0x43, 0x34, 0xdf, 0xd5, 0x3a, 0x36, 0x19, 0x19, 0x2f, 0x53, 0xef, - 0x8d, 0xa2, 0x4c, 0x29, 0x84, 0xe7, 0x0e, 0x52, 0xb4, 0x0c, 0x4c, 0xe1, - 0x90, 0xef, 0xd7, 0xd9, 0xb8, 0xb9, 0xd3, 0x46, 0xcf, 0x69, 0xd6, 0x35, - 0x59, 0xed, 0x0d, 0x02, 0xc7, 0xa7, 0xf2, 0x6b, 0x5e, 0xdd, 0x86, 0x52, - 0xc2, 0x85, 0xc2, 0x92, 0x69, 0x04, 0x51, 0x93, 0x7d, 0xa2, 0x22, 0x32, - 0x87, 0xa2, 0x9e, 0x76, 0x16, 0xc2, 0x01, 0x4c, 0x9a, 0x96, 0x82, 0xd1, - 0x98, 0xdc, 0xe0, 0xbe, 0x1a, 0xb0, 0x03, 0x1e, 0x2f, 0x44, 0x79, 0xc0, - 0x59, 0x95, 0x57, 0xa5, 0xc9, 0xcf, 0x55, 0x75, 0x78, 0x1d, 0xe2, 0x43, - 0x3a, 0x6b, 0x5f, 0xde, 0x5a, 0x32, 0x0f, 0x0e, 0x38, 0x36, 0xe4, 0x74, - 0x7a, 0x67, 0xd4, 0x88, 0x7e, 0x15, 0x7b, 0x32, 0xf8, 0x57, 0xd4, 0x27, - 0x38, 0xf4, 0x79, 0xf6, 0x7c, 0x0c, 0x6a, 0x1f, 0xbb, 0x22, 0x15, 0x46, - 0x4f, 0xec, 0x0b, 0xfc, 0xd8, 0x80, 0x87, 0xf4, 0x4c, 0x80, 0x9f, 0xa5, - 0x7a, 0xa5, 0x8f, 0x20, 0x22, 0x61, 0x53, 0xbf, 0xa5, 0x11, 0x87, 0x84, - 0x2b, 0xe3, 0x6d, 0x0d, 0x09, 0x00, 0x5f, 0x5f, 0x7f, 0xb6, 0x3c, 0x0c, - 0xc3, 0x0f, 0x93, 0xd5, 0x9c, 0xba, 0xb0, 0x7e, 0x4a, 0x37, 0xfa, 0xbf, - 0xe1, 0x22, 0x00, 0x49, 0xb6, 0x97, 0x08, 0x4e, 0x4e, 0x77, 0xd0, 0x36, - 0xa9, 0x6e, 0x3b, 0x07, 0x07, 0xe0, 0xab, 0x29, 0x6c, 0xc2, 0x2e, 0xf4, - 0x8e, 0x61, 0xe0, 0x36, 0x08, 0xd2, 0x01, 0x1a, 0x66, 0x99, 0x30, 0xbc, - 0xd9, 0x59, 0x41, 0x21, 0x58, 0x6f, 0xc5, 0xa3, 0xf3, 0x76, 0x1a, 0x75, - 0x60, 0xba, 0x28, 0x32, 0xdd, 0x38, 0x61, 0x45, 0x5d, 0x73, 0xc2, 0x36, - 0xb2, 0xf8, 0x2a, 0xb0, 0xa2, 0x3c, 0x40, 0x3d, 0x39, 0x7d, 0x1e, 0xe9, - 0x22, 0xa4, 0x7e, 0xc2, 0xd2, 0x80, 0x09, 0x3a, 0xd8, 0xe5, 0x73, 0x9e, - 0x46, 0x0b, 0x32, 0x74, 0x6d, 0x11, 0x96, 0xf2, 0x22, 0xc8, 0xd7, 0xbd, - 0x52, 0x92, 0x28, 0x59, 0x4a, 0xd7, 0x1e, 0x07, 0x2c, 0xc0, 0x13, 0x15, - 0xb3, 0x33, 0x9a, 0x76, 0xb2, 0x2b, 0x65, 0xe7, 0x4d, 0xc1, 0xf8, 0xa6, - 0x9c, 0xae, 0x70, 0x05, 0x98, 0x3f, 0xed, 0x56, 0xf2, 0xe2, 0x79, 0x40, - 0x02, 0x02, 0x03, 0xe7, 0x31, 0x82, 0x02, 0xf1, 0x30, 0x0d, 0x0c, 0x05, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0c, 0x04, 0x67, 0x65, 0x6e, 0x70, 0x30, - 0x1c, 0x0c, 0x04, 0x68, 0x61, 0x73, 0x68, 0x04, 0x14, 0xdb, 0xdd, 0x56, - 0xf1, 0xcb, 0x6a, 0xc9, 0x4a, 0xa8, 0x96, 0x8c, 0x91, 0xc1, 0x78, 0x69, - 0xe1, 0x42, 0x97, 0x32, 0x34, 0x30, 0x82, 0x02, 0xc0, 0x0c, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x04, 0x82, 0x02, 0xb6, 0x03, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x8f, 0xe0, 0xd5, 0xc6, 0x5f, - 0x89, 0xe9, 0x4c, 0x90, 0xda, 0xe0, 0xe9, 0xee, 0x3a, 0xdd, 0x7d, 0x61, - 0x54, 0x3e, 0xef, 0xa7, 0xea, 0x3a, 0x97, 0x2a, 0x9b, 0x56, 0x7c, 0x69, - 0xf9, 0x51, 0x2f, 0x40, 0x36, 0x16, 0xc0, 0xd6, 0x3f, 0xf9, 0x2e, 0xfe, - 0x44, 0x07, 0x8e, 0xc6, 0x71, 0x70, 0x86, 0x73, 0x52, 0xa8, 0x76, 0x37, - 0x42, 0x01, 0x93, 0xbe, 0x8c, 0x51, 0xd9, 0x4e, 0x45, 0xe8, 0xf9, 0x7c, - 0x4f, 0x16, 0x13, 0x80, 0x4d, 0x47, 0xd0, 0x59, 0x4e, 0xeb, 0x40, 0x2a, - 0x99, 0xa0, 0x7e, 0x77, 0x44, 0xf0, 0x62, 0xb8, 0x26, 0x39, 0x28, 0x18, - 0x88, 0xdb, 0x37, 0x0c, 0xf1, 0x37, 0x9b, 0x21, 0xbc, 0x50, 0xb7, 0x0f, - 0x9d, 0xa3, 0xcd, 0x36, 0x5d, 0x7d, 0xc7, 0x14, 0x20, 0x82, 0x66, 0x15, - 0x63, 0xce, 0x54, 0x04, 0x04, 0xbd, 0x85, 0x2b, 0xcc, 0xba, 0xdd, 0x65, - 0x7b, 0x8b, 0x6e, 0x0b, 0x8a, 0x51, 0x86, 0xdc, 0xaa, 0x14, 0xef, 0xcd, - 0x06, 0xaf, 0x7c, 0x28, 0xe3, 0x08, 0xc3, 0xaf, 0x87, 0x14, 0x51, 0x03, - 0x4c, 0xe8, 0x0f, 0x20, 0xd5, 0x2c, 0x81, 0x11, 0xce, 0x09, 0x26, 0x09, - 0x8a, 0x51, 0x28, 0x15, 0xef, 0xeb, 0x8c, 0x41, 0xbb, 0xa8, 0x6f, 0x2a, - 0x4c, 0x2d, 0x63, 0x6a, 0x9e, 0x5a, 0x3d, 0xcb, 0x16, 0x50, 0xc3, 0x4b, - 0xe5, 0x11, 0x8c, 0x7b, 0x2a, 0x63, 0x04, 0x42, 0xe0, 0x82, 0x76, 0x17, - 0x47, 0x0f, 0x36, 0x5d, 0x5e, 0x42, 0xa0, 0x86, 0x15, 0xe4, 0x8b, 0x2e, - 0x63, 0xa0, 0x5e, 0x14, 0x02, 0x73, 0x9b, 0x1c, 0x82, 0x5d, 0x02, 0x9f, - 0x99, 0x13, 0x59, 0x7b, 0x2a, 0xe8, 0xf6, 0xea, 0xb4, 0x15, 0x0e, 0xe2, - 0x27, 0x14, 0xdd, 0x45, 0xce, 0x84, 0x24, 0xb6, 0x46, 0x46, 0x48, 0x15, - 0xb6, 0x85, 0xa8, 0x38, 0xc9, 0x51, 0xe8, 0xae, 0x29, 0xfa, 0xbd, 0x1b, - 0x9e, 0x04, 0x5b, 0x5f, 0x35, 0x49, 0xc2, 0x12, 0xfb, 0x27, 0xa5, 0xac, - 0x5b, 0xac, 0x23, 0x00, 0x25, 0xfd, 0x45, 0x85, 0x0a, 0x70, 0x0e, 0xcc, - 0xa5, 0xc3, 0xce, 0x73, 0xe6, 0xe1, 0xd8, 0xb5, 0x28, 0x9c, 0x9c, 0x79, - 0x09, 0xc3, 0x40, 0xb5, 0x73, 0x8a, 0x75, 0x4f, 0xd5, 0x35, 0x90, 0xb2, - 0x2d, 0xdd, 0x5d, 0x89, 0xb9, 0x6d, 0xd8, 0x35, 0x26, 0x81, 0x7d, 0xa3, - 0xc1, 0x04, 0x95, 0xd1, 0xe4, 0x86, 0x5d, 0x9d, 0xef, 0xa9, 0x5c, 0x42, - 0x8e, 0x26, 0x18, 0x1e, 0x9a, 0xe4, 0x90, 0x8b, 0xff, 0x98, 0x19, 0x77, - 0x06, 0xb4, 0x79, 0xda, 0x1e, 0xfa, 0x83, 0xd1, 0x8c, 0x62, 0x1b, 0x17, - 0xe6, 0xce, 0xbd, 0x28, 0xe1, 0x73, 0x4c, 0x8d, 0xb1, 0x1b, 0x1b, 0xf6, - 0xa0, 0x7b, 0x98, 0xa7, 0xa2, 0xd3, 0xfd, 0x31, 0x70, 0x40, 0x25, 0x16, - 0xfa, 0xd7, 0x44, 0x0b, 0x68, 0xba, 0x09, 0xf9, 0x4e, 0xb7, 0xa6, 0xcd, - 0x9c, 0x0c, 0xd4, 0x98, 0xc4, 0xcc, 0x6b, 0x50, 0xeb, 0x23, 0xc2, 0x5a, - 0x33, 0xd9, 0x2f, 0x31, 0xfd, 0xba, 0xe5, 0x99, 0x5f, 0xdc, 0x21, 0x7c, - 0x47, 0x1e, 0x3a, 0xc2, 0x0b, 0xdd, 0xcf, 0xb4, 0x10, 0x15, 0xc4, 0xa0, - 0xeb, 0x85, 0xb6, 0x5f, 0x94, 0x03, 0x97, 0x67, 0xd8, 0x0d, 0xb7, 0xce, - 0xe7, 0x16, 0x15, 0x34, 0x92, 0xcf, 0x90, 0x50, 0xc5, 0xeb, 0x63, 0xc8, - 0xcd, 0xb4, 0x8d, 0xa1, 0x2f, 0xd1, 0x80, 0xcd, 0x36, 0xaa, 0x63, 0xb4, - 0xae, 0x7b, 0x0d, 0x07, 0x59, 0xc2, 0x54, 0x8f, 0xd7, 0x83, 0xd9, 0xd6, - 0xb3, 0xd3, 0x7e, 0x66, 0xc8, 0x0c, 0x57, 0x02, 0x6b, 0x4b, 0x8a, 0x74, - 0x47, 0x96, 0x39, 0x20, 0x0c, 0xad, 0xb8, 0xd1, 0x05, 0x92, 0xfe, 0x0d, - 0x1d, 0x4a, 0x65, 0x32, 0x53, 0x9b, 0x3d, 0xdb, 0x2d, 0x10, 0xd3, 0x0a, - 0x42, 0x79, 0xe0, 0x02, 0xc3, 0xe1, 0xec, 0x3d, 0xde, 0x57, 0x8d, 0x03, - 0x7e, 0x98, 0x62, 0x6c, 0x4a, 0x23, 0xa8, 0x3e, 0xd7, 0x11, 0x03, 0x0b, - 0x04, 0xae, 0x12, 0xb2, 0xde, 0xb5, 0x2b, 0x6c, 0x99, 0x9f, 0x0a, 0x42, - 0x20, 0x35, 0x2d, 0x0d, 0xfb, 0x9f, 0xdc, 0xfd, 0x31, 0x14, 0xbd, 0x07, - 0x94, 0x58, 0x7d, 0xd5, 0x9a, 0x3b, 0xe2, 0xf0, 0xd6, 0x50, 0xff, 0x5e, - 0x0a, 0xf0, 0xd6, 0x60, 0xb8, 0xa2, 0x71, 0x32, 0x11, 0xb7, 0x10, 0x08, - 0x70, 0xe7, 0x9d, 0xac, 0x5d, 0x14, 0x6e, 0xa0, 0x7d, 0x27, 0x2c, 0xd0, - 0xbd, 0xf1, 0x6e, 0x82, 0xdc, 0x6d, 0x57, 0x46, 0xf2, 0xe4, 0x96, 0x43, - 0x19, 0xc5, 0x9f, 0xe0, 0x8c, 0x6a, 0x0a, 0x55, 0x4a, 0xda, 0x3e, 0xdf, - 0x9c, 0x3b, 0xf1, 0x3e, 0x13, 0x3b, 0x7e, 0x9e, 0x76, 0xde, 0xeb, 0x3e, - 0x69, 0xd1, 0xa4, 0x47, 0x54, 0x30, 0xb8, 0x38, 0x15, 0x15, 0x27, 0x49, - 0x29, 0x93, 0xf0, 0xc6, 0x8a, 0xfa, 0xc0, 0xbb, 0xd4, 0xe3, 0x36, 0xcc, - 0xb8, 0x5e, 0x1a, 0x05, 0x57, 0xde, 0xa4, 0xbc, 0xbd, 0x21, 0x17, 0xda, - 0xd4, 0x96, 0x8d, 0x01, 0xa7, 0x79, 0xaa, 0x04, 0x43, 0xaf, 0x6a, 0xd2, - 0xb4, 0x2d, 0xc6, 0x15, 0x27, 0x02, 0x02, 0x03, 0xe7, 0x04, 0x14, 0x20, - 0x5a, 0x6b, 0x14, 0x4b, 0x34, 0x12, 0xc6, 0x71, 0x8c, 0xe4, 0xa8, 0x07, - 0x83, 0x0e, 0xe0, 0x6f, 0x2d, 0xe6, 0x13, 0x02, 0x02, 0x03, 0xe7 -}; - -/* Test backup-restore case, when item had inconsistently set pdmn attribute (due to another bug), - and mobile restore restored item with inconsistent attributes and afterwards tried SecItemUpdate() - on it, which failed, leading to the failure of the whole restore operation. - */ - -#if 0 -static bool SecKeychainWithBackupFile(CFStringRef backupName, CFErrorRef *error, void(^with)(FILE *bufile)) { - int fd = SecItemBackupHandoffFD(backupName, error); - if (fd < 0) - return false; - FILE *backup = fdopen(fd, "r"); - FILE *file = fopen_journal(fname, "w", error); - - if (!backup) { - close(fd); - return SecCheckErrno(!backup, error, CFSTR("fdopen")); - } - with(backup); - fclose(backup); - return true; -} - -static void secd_perform_with_data_in_file(const char* test_prefix, void(^with)(CFDataRef backupData)) -{ - CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random()); - - CFStringPerformWithCString(tmp_dir, ^(const char *tmp_dir_string) { - errno_t err = mkpath_np(tmp_dir_string, 0755); - ok(err == 0 || err == EEXIST, "Create temp dir %s (%d)", tmp_dir_string, err); - FILE *file = fopen(fname, "w", error); - - }); - - /* set custom keychain dir, reset db */ - SetCustomHomeURLString(tmp_dir); - - if(do_before_reset) - do_before_reset(); - - SecKeychainDbReset(NULL); - - CFReleaseNull(tmp_dir); - CFReleaseNull(keychain_dir); -} -#endif - - -static void tests(void) -{ - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_34_backup_der_parse", ^{}); - - (void)backup_data; - -#if 0 - FILE *backup = NULL; - CFErrorRef *error = NULL; - CFDataRef backupData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, backup_data, array_size(backup_data), kCFAllocatorNull); - - CFWriteStreamCreateWithBuffer(kCFAllocatorDefault, <#UInt8 *buffer#>, <#CFIndex bufferCapacity#>) - ok(SecKeychainWithBackupFileParse(backup, error, ^(SecBackupEventType et, CFTypeRef key, CFTypeRef item) { - diag("This still fails - don't be alarmed"); - })); - CFReleaseSafe(error); -#endif - -#if 0 - ok( SecKeychainWithBackupFileParse - (FILE *backup, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item))); - fclose(backup); - SecItemBackupWithChanges(CFSTR("SecureBackupService"), &error, ^(SecBackupEventType et, CFTypeRef key, CFTypeRef item) { - ; - }); - - CFStreamRef - /* Restore keychain from plist. */ - CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, keybag_data, sizeof(keybag_data)); - CFDataRef backup = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)export_plist, sizeof(export_plist)); - ok_status(_SecKeychainRestoreBackup(backup, keybag, NULL)); - CFRelease(keybag); - CFRelease(backup); - - /* The restored item is kind of malformed (pdmn and accc attributes are inconsistent). Currently adopted way - of handling of this item is to try to handle it gracefully, this is what this test does (i.e. it checks that - it is possible to update such item). Another possibility which might be adopted in the future is dropping such - item during backup decoding. In this case, the test should be modified to check that the item does not exist - in the keychain at all. */ - - /* Try to update item with inconsistent accc and pdmn attributes. */ - CFDictionaryRef query = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), - kSecAttrService, CFSTR("test"), - NULL); - CFDictionaryRef update = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrService, CFSTR("updated-test"), - NULL); - - ok_status(SecItemUpdate(query, update)); - diag("This still fails - don't be alarmed"); - CFRelease(update); - CFRelease(query); -#endif - -} - -int secd_32_restore_bad_backup(int argc, char *const *argv) -{ - plan_tests(2 + kSecdTestSetupTestCount); - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m b/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m deleted file mode 100644 index 56368e54..00000000 --- a/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "secd_regressions.h" - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#if TARGET_OS_IPHONE && USE_KEYSTORE -#include "OSX/utilities/SecAKSWrappers.h" - -#include "SecdTestKeychainUtilities.h" - -#include "ios8-inet-keychain-2.h" - -void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); -CFArrayRef SecAccessGroupsGetCurrent(void); - -int secd_35_keychain_migrate_inet(int argc, char *const *argv) -{ - plan_tests(11 + kSecdTestSetupTestCount); - - __block keybag_handle_t keybag; - __block keybag_state_t state; - char *passcode="password"; - int passcode_len=(int)strlen(passcode); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_35_keychain_migrate_inet", ^{ - CFStringRef keychain_path_cf = __SecKeychainCopyPath(); - - CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { - writeFile(keychain_path, ios8_inet_keychain_2_db, ios8_inet_keychain_2_db_len); - - /* custom notification */ - SecItemServerSetKeychainChangedNotification("com.apple.secdtests.keychainchanged"); - - /* Create and lock custom keybag */ - ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(keybag); - - /* lock */ - ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(state&keybag_state_locked, "keybag locked"); - }); - - CFReleaseSafe(keychain_path_cf); - }); - - CFArrayRef old_ag = CFRetainSafe(SecAccessGroupsGetCurrent()); - CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); - CFArrayAppendValue(test_ag, CFSTR("com.apple.cfnetwork")); - SecAccessGroupsSetCurrent(test_ag); - - /* querying a password */ - const void *keys[] = { - kSecClass, - kSecAttrAccessGroup, - kSecAttrSynchronizable, - kSecMatchLimit, - kSecReturnAttributes, - }; - const void *values[] = { - kSecClassInternetPassword, - CFSTR("com.apple.cfnetwork"), - kSecAttrSynchronizableAny, - kSecMatchLimitAll, - kCFBooleanTrue, - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - array_size(keys), NULL, NULL); - CFTypeRef results = NULL; - is_status(SecItemCopyMatching(query, &results), errSecInteractionNotAllowed); - - ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "lock keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - - // We should be able to query 2 inet items from the DB here. But the database is encrypted - // by keybag which we do not know, so no item can be actually retrieved. The test could be - // improved by crafting DB to update using keybag hardcoded in the test, that way it would be possible - // to check that 2 inet items are really retrieved here. - is_status(SecItemCopyMatching(query, &results), errSecItemNotFound); - - /* Reset keybag */ - SecItemServerResetKeychainKeybag(); - - // Reset server accessgroups. - SecAccessGroupsSetCurrent(old_ag); - CFReleaseNull(old_ag); - CFReleaseSafe(test_ag); - - CFReleaseSafe(results); - CFReleaseSafe(query); - return 0; -} - -#else - -int secd_35_keychain_migrate_inet(int argc, char *const *argv) -{ - plan_tests(1); - - todo("Not yet working in simulator"); - -TODO: { - ok(false); -} - /* not implemented in simulator (no keybag) */ - /* Not implemented in OSX (no upgrade scenario) */ - return 0; -} -#endif diff --git a/OSX/sec/securityd/Regressions/secd-36-ks-encrypt.m b/OSX/sec/securityd/Regressions/secd-36-ks-encrypt.m deleted file mode 100644 index ff85cb8f..00000000 --- a/OSX/sec/securityd/Regressions/secd-36-ks-encrypt.m +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "secd_regressions.h" - -#include - -#include -#include "SecDbKeychainItem.h" - -#include - -#if USE_KEYSTORE -#include "OSX/utilities/SecAKSWrappers.h" - -#include "SecdTestKeychainUtilities.h" - -int secd_36_ks_encrypt(int argc, char *const *argv) -{ - plan_tests(9); - - secd_test_setup_temp_keychain("secd_36_ks_encrypt", NULL); - - keybag_handle_t keybag; - keybag_state_t state; - CFDictionaryRef data = NULL; - CFDataRef enc = NULL; - CFErrorRef error = NULL; - SecAccessControlRef ac = NULL; - bool ret; - - char passcode[] = "password"; - int passcode_len = sizeof(passcode) - 1; - - - /* Create and lock custom keybag */ - is(kAKSReturnSuccess, aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); - is(kAKSReturnSuccess, aks_get_lock_state(keybag, &state), "get keybag state"); - is(0, (int)(state&keybag_state_locked), "keybag unlocked"); - - data = (__bridge CFDictionaryRef)@{ - (id)kSecValueData : @"secret here", - }; - - ok(ac = SecAccessControlCreate(NULL, &error), "SecAccessControlCreate: %@", error); - ok(SecAccessControlSetProtection(ac, kSecAttrAccessibleWhenUnlocked, &error), "SecAccessControlSetProtection: %@", error); - - ret = ks_encrypt_data(keybag, ac, NULL, data, (__bridge CFDictionaryRef)@{@"persistref" : @"aaa-bbb-ccc"}, NULL, &enc, true, &error); - is(true, ret); - - CFReleaseNull(ac); - - { - CFMutableDictionaryRef attributes = NULL; - uint32_t version = 0; - - ret = ks_decrypt_data(keybag, kAKSKeyOpDecrypt, &ac, NULL, enc, NULL, NULL, &attributes, &version, true, NULL, &error); - is(true, ret, "ks_decrypt_data: %@", error); - - CFTypeRef aclProtection = ac ? SecAccessControlGetProtection(ac) : NULL; - ok(aclProtection && CFEqual(aclProtection, kSecAttrAccessibleWhenUnlocked), "AccessControl protection is: %@", aclProtection); - - CFReleaseNull(ac); - } - - CFReleaseNull(error); - CFReleaseNull(enc); - - return 0; -} - -#else /* !USE_KEYSTORE */ - -int secd_36_ks_encrypt(int argc, char *const *argv) -{ - plan_tests(1); - ok(true); - return 0; -} -#endif /* USE_KEYSTORE */ diff --git a/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m b/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m deleted file mode 100644 index 7ac6d8ac..00000000 --- a/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "secd_regressions.h" - -#include - -#include "SecdTestKeychainUtilities.h" - -void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); -CFArrayRef SecAccessGroupsGetCurrent(void); - - -static void AddItem(NSDictionary *attr) -{ - NSMutableDictionary *mattr = [attr mutableCopy]; - mattr[(__bridge id)kSecValueData] = [NSData dataWithBytes:"foo" length:3]; - mattr[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; - ok_status(SecItemAdd((__bridge CFDictionaryRef)mattr, NULL)); -} - -int secd_37_pairing_initial_sync(int argc, char *const *argv) -{ - CFErrorRef error = NULL; - CFTypeRef stuff = NULL; - OSStatus res = 0; - - plan_tests(16); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_37_pairing_initial_sync", NULL); - - CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); - - NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; - [newACL addObjectsFromArray:@[ - @"com.apple.ProtectedCloudStorage", - ]]; - - SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); - - - NSDictionary *pcsinetattrs = @{ - (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, - (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", - (__bridge id)kSecAttrAccount : @"1", - (__bridge id)kSecAttrServer : @"current", - (__bridge id)kSecAttrType : @(0x10001), - (__bridge id)kSecAttrSynchronizable : @YES, - (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, - }; - NSDictionary *pcsinetattrsNotCurrent = @{ - (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, - (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", - (__bridge id)kSecAttrAccount : @"1", - (__bridge id)kSecAttrServer : @"noncurrent", - (__bridge id)kSecAttrType : @(0x00001), - (__bridge id)kSecAttrSynchronizable : @YES, - (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, - }; - NSDictionary *pcsgenpattrs = @{ - (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", - (__bridge id)kSecAttrAccount : @"2", - (__bridge id)kSecAttrSynchronizable : @YES, - (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, - }; - NSDictionary *ckksattrs = @{ - (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, - (__bridge id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (__bridge id)kSecAttrAccount : @"2", - (__bridge id)kSecAttrSynchronizable : @YES, - (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, - }; - AddItem(pcsinetattrs); - AddItem(pcsinetattrsNotCurrent); - AddItem(pcsgenpattrs); - AddItem(ckksattrs); - - CFArrayRef items = _SecServerCopyInitialSyncCredentials(SecServerInitialSyncCredentialFlagTLK | SecServerInitialSyncCredentialFlagPCS, &error); - ok(items, "_SecServerCopyInitialSyncCredentials: %@", error); - CFReleaseNull(error); - - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - - - ok(_SecItemDeleteAll(&error), "SecItemServerDeleteAll: %@", error); - CFReleaseNull(error); - - ok(_SecServerImportInitialSyncCredentials(items, &error), "_SecServerImportInitialSyncCredentials: %@", error); - CFReleaseNull(error); - CFReleaseNull(items); - - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - is_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), errSecItemNotFound, - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), - "SecItemCopyMatching: %d", (int)res); - CFReleaseNull(stuff); - - SecAccessGroupsSetCurrent(currentACL); - CFReleaseNull(currentACL); - - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m b/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m deleted file mode 100644 index 4b3d21d5..00000000 --- a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include -#include -#include "secd_regressions.h" - -static int kTestTestCount = 1; -static void tests(void) -{ - CFStringRef osVersion = SOSCCCopyOSVersion(); - - ok(osVersion != NULL, "OS Version Exists"); - - CFReleaseNull(osVersion); -} - -int secd_40_cc_gestalt(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-49-manifests.m b/OSX/sec/securityd/Regressions/secd-49-manifests.m deleted file mode 100644 index fe098739..00000000 --- a/OSX/sec/securityd/Regressions/secd-49-manifests.m +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "keychain/SecureObjectSync/SOSManifest.h" -#include "keychain/SecureObjectSync/SOSMessage.h" - -#include "secd_regressions.h" - -#include -#include -#include -#include "keychain/SecureObjectSync/SOSDigestVector.h" -#include -#include - -static int kTestTestCount = 68; - - -#define okmfcomplement(r, b, n, ...) test_okmfcomplement(r, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) -#define okmfdiff(a, b, eab,eba, ...) test_okmfdiff(a, b, eab, eba, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) -#define okmfintersection(a, b, n, ...) test_okmfintersection(a, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) -#define okmfpatch(b, r, a, n, ...) test_okmfpatch(b, r, a, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) -#define okmfunion(a, b, n, ...) test_okmfunion(a, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) - -static void appendManifestDescription(CFMutableStringRef string, CFStringRef prefix, SOSManifestRef mf) { - if (prefix) - CFStringAppend(string, prefix); - if (!mf) { - CFStringAppend(string, CFSTR("null")); - } else if (SOSManifestGetCount(mf) == 0) { - CFStringAppend(string, CFSTR("empty")); - } else { - char prefix = '{'; - const uint8_t *d = SOSManifestGetBytePtr(mf); - for (CFIndex endIX = SOSManifestGetCount(mf), curIX = 0; curIX < endIX; ++curIX, d += SOSDigestSize) { - CFStringAppendFormat(string, NULL, CFSTR("%c%c"), prefix, *d); - prefix = ' '; - } - CFStringAppend(string, CFSTR("}")); - } -} - -static int appendManifestComparison(CFMutableStringRef string, CFStringRef prefix, SOSManifestRef expected, SOSManifestRef computed) { - int passed = 0; - appendManifestDescription(string, prefix, computed); - if (CFEqualSafe(computed, expected)) { - // ok - passed = 1; - } else { - // wrong - appendManifestDescription(string, CFSTR("!="), expected); - } - return passed; -} - -static void test_okmfcomplement(SOSManifestRef r, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { - CFErrorRef error = NULL; - int passed = 0; - CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); - if (test_description && CFStringGetLength(test_description) != 0) - CFStringAppend(extendedDescription, CFSTR(" ")); - appendManifestDescription(extendedDescription, CFSTR("complement "), r); - appendManifestDescription(extendedDescription, CFSTR("->"), b); - SOSManifestRef new = SOSManifestCreateComplement(r, b, &error); - if (!new) { - CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateComplement: %@"), error); - } else { - passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); - } - test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); - CFReleaseSafe(test_description); - CFReleaseSafe(new); - CFReleaseSafe(error); -} - -static void test_okmfdiff(SOSManifestRef a, SOSManifestRef b, SOSManifestRef exp_a_b, SOSManifestRef exp_b_a, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { - CFErrorRef error = NULL; - SOSManifestRef a_minus_b = NULL; - SOSManifestRef b_minus_a = NULL; - int passed = 0; - CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); - if (test_description && CFStringGetLength(test_description) != 0) - CFStringAppend(extendedDescription, CFSTR(" ")); - appendManifestDescription(extendedDescription, CFSTR("diff "), a); - appendManifestDescription(extendedDescription, CFSTR("->"), b); - if (!SOSManifestDiff(a, b, &a_minus_b, &b_minus_a, &error)) { - CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestDiff: %@"), error); - } else { - passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), exp_a_b, a_minus_b); - passed &= appendManifestComparison(extendedDescription, CFSTR("->"), exp_b_a, b_minus_a); - } - test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); - CFReleaseSafe(test_description); - CFReleaseSafe(a_minus_b); - CFReleaseSafe(b_minus_a); - CFReleaseSafe(error); -} - -static void test_okmfintersection(SOSManifestRef a, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { - CFErrorRef error = NULL; - int passed = 0; - CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); - if (test_description && CFStringGetLength(test_description) != 0) - CFStringAppend(extendedDescription, CFSTR(" ")); - appendManifestDescription(extendedDescription, CFSTR("intersection "), a); - appendManifestDescription(extendedDescription, CFSTR("->") /*CFSTR(" \xe2\x88\xa9 ")*/, b); - SOSManifestRef new = SOSManifestCreateIntersection(a, b, &error); - if (!new) { - CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateIntersection: %@"), error); - } else { - passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); - } - test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); - CFReleaseSafe(test_description); - CFReleaseSafe(new); - CFReleaseSafe(error); -} - -static void test_okmfpatch(SOSManifestRef b, SOSManifestRef r, SOSManifestRef a, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { - CFErrorRef error = NULL; - int passed = 0; - CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); - if (test_description && CFStringGetLength(test_description) != 0) - CFStringAppend(extendedDescription, CFSTR(" ")); - appendManifestDescription(extendedDescription, CFSTR("patch "), b); - appendManifestDescription(extendedDescription, CFSTR("->"), r); - appendManifestDescription(extendedDescription, CFSTR("->"), a); - SOSManifestRef new = SOSManifestCreateWithPatch(b, r, a, &error); - if (!new) { - CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateWithPatch: %@"), error); - } else { - passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); - } - test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); - CFReleaseSafe(test_description); - CFReleaseSafe(new); - CFReleaseSafe(error); -} - -static void test_okmfunion(SOSManifestRef a, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { - CFErrorRef error = NULL; - int passed = 0; - CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); - if (test_description && CFStringGetLength(test_description) != 0) - CFStringAppend(extendedDescription, CFSTR(" ")); - appendManifestDescription(extendedDescription, CFSTR("union "), a); - appendManifestDescription(extendedDescription, CFSTR("->") /*CFSTR(" \xe2\x88\xaa ")*/, b); - SOSManifestRef new = SOSManifestCreateUnion(a, b, &error); - if (!new) { - CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateUnion: %@"), error); - } else { - passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); - } - test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); - CFReleaseSafe(test_description); - CFReleaseSafe(new); - CFReleaseSafe(error); -} - -static SOSManifestRef createManifestWithString(CFStringRef string) { - struct SOSDigestVector dv = SOSDigestVectorInit; - CFIndex length = string ? CFStringGetLength(string) : 0; - CFStringInlineBuffer buf = {}; - CFRange range = { 0, length }; - CFStringInitInlineBuffer(string, &buf, range); - for (CFIndex ix = 0; ix < length; ++ix) { - uint8_t digest[20] = " "; - UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, ix); - digest[0] = c; - SOSDigestVectorAppend(&dv, digest); - } - SOSManifestRef mf = NULL; - mf = SOSManifestCreateWithDigestVector(&dv, NULL); - SOSDigestVectorFree(&dv); - return mf; -} - -static SOSManifestRef testCreateBadManifest() { - SOSManifestRef mf = createManifestWithString(CFSTR("bab")); - is(SOSManifestGetCount(mf), (size_t)2, "dupes eliminated?"); - return mf; -} - - -typedef struct mf_vectors { - SOSManifestRef null; - SOSManifestRef empty; - SOSManifestRef a; - SOSManifestRef b; - SOSManifestRef ab; - SOSManifestRef bab; - SOSManifestRef agh; - SOSManifestRef gh; - SOSManifestRef agghhjk; - SOSManifestRef gghh; - SOSManifestRef agghh; -} mf_t; - -static void setupMF(mf_t *mf) { - CFErrorRef error = NULL; - mf->null = NULL; - mf->empty = SOSManifestCreateWithBytes(NULL, 0, &error); - mf->a = createManifestWithString(CFSTR("a")); - mf->b = createManifestWithString(CFSTR("b")); - mf->ab = createManifestWithString(CFSTR("ab")); - mf->bab = testCreateBadManifest(); - mf->gh = createManifestWithString(CFSTR("gh")); - mf->agh = createManifestWithString(CFSTR("agh")); - mf->agghhjk = createManifestWithString(CFSTR("agghhjk")); - mf->gghh = createManifestWithString(CFSTR("gghh")); - mf->agghh = createManifestWithString(CFSTR("agghh")); -} - -static void teardownMF(mf_t *mf) { - if (!mf) return; - CFReleaseSafe(mf->empty); - CFReleaseSafe(mf->a); - CFReleaseSafe(mf->b); - CFReleaseSafe(mf->ab); - CFReleaseSafe(mf->bab); - CFReleaseSafe(mf->gh); - CFReleaseSafe(mf->agh); - CFReleaseSafe(mf->agghhjk); - CFReleaseSafe(mf->gghh); - CFReleaseSafe(mf->agghh); -} - -static void testNullManifest(SOSManifestRef mf) -{ - is(SOSManifestGetCount(mf), (size_t)0, "count is 0"); - is(SOSManifestGetSize(mf), (size_t)0, "capacity is 0"); -} - -static void testNull(mf_t *mf) { - testNullManifest(mf->null); - testNullManifest(mf->empty); -} - -static void testDiff(mf_t *mf) { - okmfdiff(mf->null, mf->null, mf->empty, mf->empty); - okmfdiff(mf->null, mf->empty, mf->empty, mf->empty); - okmfdiff(mf->null, mf->a, mf->empty, mf->a); - okmfdiff(mf->empty, mf->null, mf->empty, mf->empty); - okmfdiff(mf->empty, mf->empty, mf->empty, mf->empty); - okmfdiff(mf->empty, mf->a, mf->empty, mf->a); - okmfdiff(mf->a, mf->null, mf->a, mf->empty); - okmfdiff(mf->a, mf->empty, mf->a, mf->empty); - okmfdiff(mf->a, mf->a, mf->empty, mf->empty); - okmfdiff(mf->bab, mf->empty, mf->ab, mf->empty); - okmfdiff(mf->bab, mf->a, mf->b, mf->empty); - okmfdiff(mf->a, mf->bab, mf->empty, mf->b); - okmfdiff(mf->bab, mf->b, mf->a, mf->empty); - okmfdiff(mf->b, mf->bab, mf->empty, mf->a); - okmfdiff(mf->bab, mf->bab, mf->empty, mf->empty); -} - -static void testPatch(mf_t *mf) { - okmfpatch(mf->null, mf->null, mf->null, mf->empty); - okmfpatch(mf->empty, mf->empty, mf->empty, mf->empty); - okmfpatch(mf->bab, mf->b, mf->a, mf->a); - okmfpatch(mf->ab, mf->empty, mf->empty, mf->ab); - okmfpatch(mf->ab, mf->empty, mf->a, mf->ab); - okmfpatch(mf->bab, mf->empty, mf->a, mf->ab); - okmfpatch(mf->bab, mf->ab, mf->null, mf->empty); - okmfpatch(mf->bab, mf->empty, mf->empty, mf->ab); -} - -static void testUnion(mf_t *mf) { - okmfunion(mf->null, mf->null, mf->empty); - okmfunion(mf->null, mf->empty, mf->empty); - okmfunion(mf->empty, mf->null, mf->empty); - okmfunion(mf->empty, mf->empty, mf->empty); - okmfunion(mf->null, mf->a, mf->a); - okmfunion(mf->a, mf->null, mf->a); - okmfunion(mf->empty, mf->a, mf->a); - okmfunion(mf->a, mf->empty, mf->a); - okmfunion(mf->bab, mf->ab, mf->ab); - okmfunion(mf->empty, mf->bab, mf->ab); - okmfunion(mf->bab, mf->empty, mf->ab); -} - -static void testIntersect(mf_t *mf) { - okmfintersection(mf->null, mf->null, mf->empty); - okmfintersection(mf->null, mf->empty, mf->empty); - okmfintersection(mf->empty, mf->null, mf->empty); - okmfintersection(mf->empty, mf->empty, mf->empty); - okmfintersection(mf->null, mf->a, mf->empty); - okmfintersection(mf->a, mf->null, mf->empty); - okmfintersection(mf->empty, mf->a, mf->empty); - okmfintersection(mf->a, mf->empty, mf->empty); - okmfintersection(mf->bab, mf->ab, mf->ab); - okmfintersection(mf->bab, mf->a, mf->a); - okmfintersection(mf->a, mf->bab, mf->a); - okmfintersection(mf->b, mf->bab, mf->b); - okmfintersection(mf->bab, mf->bab, mf->ab); - okmfintersection(mf->gghh, mf->agghh, mf->gh); - okmfintersection(mf->agghhjk, mf->agghh, mf->agh); -} - -static void testComplement(mf_t *mf) { - okmfcomplement(mf->null, mf->null, mf->empty); - okmfcomplement(mf->null, mf->empty, mf->empty); - okmfcomplement(mf->empty, mf->null, mf->empty); - okmfcomplement(mf->empty, mf->empty, mf->empty); - okmfcomplement(mf->null, mf->a, mf->a); - okmfcomplement(mf->a, mf->null, mf->empty); - okmfcomplement(mf->empty, mf->a, mf->a); - okmfcomplement(mf->a, mf->empty, mf->empty); - okmfcomplement(mf->bab, mf->ab, mf->empty); - okmfcomplement(mf->ab, mf->bab, mf->empty); - okmfcomplement(mf->bab, mf->a, mf->empty); - okmfcomplement(mf->a, mf->bab, mf->b); - okmfcomplement(mf->b, mf->bab, mf->a); - okmfcomplement(mf->empty, mf->bab, mf->ab); -} - -static void tests(void) -{ - mf_t mf; - setupMF(&mf); - - testNull(&mf); - testDiff(&mf); - testPatch(&mf); - testUnion(&mf); - testIntersect(&mf); - testComplement(&mf); - - teardownMF(&mf); -} - -int secd_49_manifests(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-50-account.m b/OSX/sec/securityd/Regressions/secd-50-account.m deleted file mode 100644 index 097b3990..00000000 --- a/OSX/sec/securityd/Regressions/secd-50-account.m +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" - -static int kTestTestCount = 9 + kSecdTestSetupTestCount; -static void tests(void) -{ - NSError* error = nil; - CFErrorRef cfError = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - - SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); - - ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &cfError), "Credential setting (%@)", cfError); - CFReleaseNull(cfError); - CFReleaseNull(cfpassword); - - ok(NULL != account, "Created"); - - size_t size = [account.trust getDEREncodedSize:account err:&error]; - - error = nil; - uint8_t buffer[size]; - - uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; - error = nil; - - ok(start, "successful encoding"); - ok(start == buffer, "Used whole buffer"); - - const uint8_t *der = buffer; - SOSAccount* inflated = [SOSAccount accountFromDER:&der end:buffer + sizeof(buffer) - factory:test_factory error:&error]; - - ok(inflated, "inflated %@", error); - ok([inflated isEqual:account], "Compares"); - - error = nil; - - CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); - ok(SOSAccountResetToOffering_wTxn(account, &cfError), "Reset to Offering (%@)", error); - CFReleaseNull(cfError); - - is([account getCircleStatus:&cfError], kSOSCCInCircle, "Was in Circle (%@)", error); - CFReleaseNull(cfError); - - [account.trust updateGestalt:account newGestalt:new_gestalt]; - is([account getCircleStatus:&cfError], kSOSCCInCircle, "Still in Circle (%@)", error); - CFReleaseNull(cfError); - - CFReleaseNull(new_gestalt); - - SOSDataSourceFactoryRelease(test_factory); - SOSDataSourceRelease(test_source, NULL); - - account = nil; - inflated = nil; - - SOSTestCleanup(); -} - -int secd_50_account(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-50-message.m b/OSX/sec/securityd/Regressions/secd-50-message.m deleted file mode 100644 index 0fa120bc..00000000 --- a/OSX/sec/securityd/Regressions/secd-50-message.m +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "keychain/SecureObjectSync/SOSManifest.h" -#include "keychain/SecureObjectSync/SOSMessage.h" - -#include "secd_regressions.h" - -#include -#include -#include "keychain/SecureObjectSync/SOSDigestVector.h" -#include - -static void testNullMessage(uint64_t msgid) -{ - SOSMessageRef sentMessage = NULL; - SOSMessageRef rcvdMessage = NULL; - SOSManifestRef sender = NULL; - CFErrorRef error = NULL; - CFDataRef data = NULL; - - // Encode - ok(sender = SOSManifestCreateWithBytes(NULL, 0, &error), "empty sender manifest create: %@", error); - CFReleaseNull(error); - ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, sender, NULL, NULL, false, &error), "sentMessage create: %@", error); - CFReleaseNull(error); - ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@", error); - CFReleaseNull(error); - - // Decode - ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); - CFReleaseNull(error); - __block size_t numObjects = 0; - SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { - numObjects++; - }); - ok(numObjects == 0, "no objects"); - - // Check if we got what we started with - ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); - - CFReleaseNull(data); - CFReleaseNull(sentMessage); - CFReleaseNull(rcvdMessage); - CFReleaseNull(sender); -} - -__unused static void testFlaggedMessage(const char *test_directive, const char *test_reason, uint64_t msgid, SOSMessageFlags flags) -{ - SOSMessageRef sentMessage = NULL; - SOSMessageRef rcvdMessage = NULL; - SOSManifestRef sender = NULL; - CFErrorRef error = NULL; - CFDataRef data = NULL; - - ok(sender = SOSManifestCreateWithBytes(NULL, 0, &error), "empty sender manifest create: %@", error); - CFReleaseNull(error); - ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, sender, NULL, NULL, false, &error), "sentMessage create: %@", error); - CFReleaseNull(error); - SOSMessageSetFlags(sentMessage, flags); - ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@", error); - CFReleaseNull(error); - - // Decode - ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); - CFReleaseNull(error); - __block size_t numObjects = 0; - SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { - numObjects++; - }); - ok(numObjects == 0, "no objects"); - - is(SOSMessageGetFlags(sentMessage), flags, "flags match after roundtrip"); - ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); - - CFReleaseNull(data); - CFReleaseNull(sentMessage); - CFReleaseNull(rcvdMessage); - CFReleaseNull(sender); -} - -__unused static void testDeltaManifestMessage(const char *test_directive, const char *test_reason, uint64_t msgid) -{ - SOSMessageRef sentMessage = NULL; - SOSMessageRef rcvdMessage = NULL; - SOSManifestRef sender = NULL; - SOSManifestRef proposed = NULL; - SOSManifestRef base = NULL; - CFErrorRef error = NULL; - CFDataRef data = NULL; - - struct SOSDigestVector dv = SOSDigestVectorInit; - SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that is 20 bytes long or so and stuff"); - SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); - SOSDigestVectorSort(&dv); - base = SOSManifestCreateWithBytes((const uint8_t *)dv.digest, dv.count * SOSDigestSize, &error); - SOSDigestVectorAppend(&dv, (const uint8_t *)"so much more is good to see here is another one for me"); - SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff!"); - SOSDigestVectorAppend(&dv, (const uint8_t *)"so much for is good to see here is another one for me"); - SOSDigestVectorSort(&dv); - if (msgid) - proposed = SOSManifestCreateWithBytes((const uint8_t *)dv.digest, dv.count * SOSDigestSize, &error); - - CFReleaseNull(error); - ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, proposed, base, proposed, true, &error), "sentMessage create: %@", error); - CFReleaseNull(base); - CFReleaseNull(proposed); - CFReleaseNull(error); - ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@ .. %@", error, sentMessage); - CFReleaseNull(error); - - // Decode - ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); - CFReleaseNull(error); - __block size_t numObjects = 0; - SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { - numObjects++; - }); - ok(numObjects == 0, "no objects"); - - ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); - - CFReleaseNull(data); - CFReleaseNull(sentMessage); - CFReleaseNull(rcvdMessage); - CFReleaseNull(sender); -} - -static CFDataRef testCopyAddedObject(SOSMessageRef message, CFPropertyListRef plist) -{ - CFErrorRef error = NULL; - CFDataRef der; - ok(der = CFPropertyListCreateDERData(kCFAllocatorDefault, plist, &error), "copy der: %@", error); - CFReleaseNull(error); - ok(SOSMessageAppendObject(message, der, &error), "likes object: %@", error); - CFReleaseNull(error); - return der; -} - -__unused static void testObjectsMessage(const char *test_directive, const char *test_reason, uint64_t msgid) -{ - SOSMessageRef sentMessage = NULL; - SOSMessageRef rcvdMessage = NULL; - SOSManifestRef sender = NULL; - SOSManifestRef proposed = NULL; - SOSManifestRef base = NULL; - CFErrorRef error = NULL; - CFDataRef data = NULL; - - struct SOSDigestVector dv1 = SOSDigestVectorInit; - struct SOSDigestVector dv2 = SOSDigestVectorInit; - SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that is 20 bytes long or so and stuff"); - SOSDigestVectorAppend(&dv2, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); - SOSDigestVectorAppend(&dv1, (const uint8_t *)"so much more is good to see here is another one for me"); - SOSDigestVectorAppend(&dv2, (const uint8_t *)"so much more is good to see here is another one for me"); - SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); - SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff!"); - SOSDigestVectorAppend(&dv2, (const uint8_t *)"so much for is good to see here is another one for me"); - SOSDigestVectorSort(&dv1); - SOSDigestVectorSort(&dv2); - base = SOSManifestCreateWithBytes((const uint8_t *)dv1.digest, dv1.count * SOSDigestSize, &error); - if (msgid) - proposed = SOSManifestCreateWithBytes((const uint8_t *)dv2.digest, dv2.count * SOSDigestSize, &error); - CFReleaseNull(error); - ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, proposed, base, proposed, true, &error), "sentMessage create: %@", error); - CFReleaseNull(base); - CFReleaseNull(proposed); - CFDataRef O0, O1, O2, O3; - CFDataRef o0 = CFDataCreate(kCFAllocatorDefault, NULL, 0); - O0 = testCopyAddedObject(sentMessage, o0); - CFDataRef o1 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"test", 4); - O1 = testCopyAddedObject(sentMessage, o1); - CFDataRef o2 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"what an object", 14); - O2 = testCopyAddedObject(sentMessage, o2); - CFDataRef o3 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"This one even has shiny stripe.", 31); - O3 = testCopyAddedObject(sentMessage, o3); - ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@ .. %@", error, sentMessage); - CFReleaseNull(error); - - // Decode - ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); - CFReleaseNull(error); - __block size_t numObjects = 0; - __block bool f0, f1, f2, f3; - f0 = f1 = f2 = f3 = false; - if (rcvdMessage) SOSMessageWithObjects(rcvdMessage, &error, ^(CFDataRef object, bool *stop) { - if (CFEqualSafe(object, O0)) f0 = true; - if (CFEqualSafe(object, O1)) f1 = true; - if (CFEqualSafe(object, O2)) f2 = true; - if (CFEqualSafe(object, O3)) f3 = true; - numObjects++; - }); - ok(f0, "got O0"); - ok(f1, "got O1"); - ok(f2, "got O2"); - ok(f3, "got O3"); - - ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); - - CFReleaseNull(o0); - CFReleaseNull(o1); - CFReleaseNull(o2); - CFReleaseNull(o3); - CFReleaseNull(O0); - CFReleaseNull(O1); - CFReleaseNull(O2); - CFReleaseNull(O3); - CFReleaseNull(data); - CFReleaseNull(sentMessage); - CFReleaseNull(rcvdMessage); - CFReleaseNull(sender); -} - -static void tests(void) -{ - testNullMessage(0); // v0 - - uint64_t msgid = 0; - testNullMessage(++msgid); // v2 - testFlaggedMessage(test_directive, test_reason, ++msgid, 0x865); - testFlaggedMessage(test_directive, test_reason, ++msgid, 0xdeadbeef); -} - -int secd_50_message(int argc, char *const *argv) -{ - plan_tests(26); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-51-account-inflate.m b/OSX/sec/securityd/Regressions/secd-51-account-inflate.m deleted file mode 100644 index c50f219d..00000000 --- a/OSX/sec/securityd/Regressions/secd-51-account-inflate.m +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include - -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" -#include "SOSTransportTestTransports.h" - -#if 0 -const uint8_t v6_der[] = { - 0x30, 0x82, 0x06, 0xee, 0x02, 0x01, 0x06, 0x31, 0x4e, 0x30, 0x11, 0x0c, - 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04, - 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c, - 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, - 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27, 0x73, 0x20, 0x69, - 0x50, 0x61, 0x64, 0x30, 0x82, 0x05, 0xe0, 0x30, 0x82, 0x05, 0xdc, 0x04, - 0x82, 0x04, 0x1c, 0x30, 0x82, 0x04, 0x18, 0x02, 0x01, 0x01, 0x0c, 0x02, - 0x61, 0x6b, 0x02, 0x08, 0x0d, 0x4f, 0xc4, 0x65, 0x00, 0x00, 0x00, 0x03, - 0x30, 0x82, 0x03, 0x2c, 0x30, 0x82, 0x01, 0xa2, 0x31, 0x82, 0x01, 0x56, - 0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x2b, - 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16, 0x32, 0x30, 0x31, - 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30, 0x35, 0x39, 0x2e, - 0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55, 0x0c, 0x10, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, - 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e, 0x16, 0x03, 0x13, - 0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4, 0xf0, 0x47, 0x52, - 0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06, 0x73, 0x23, 0x72, - 0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61, 0xc9, 0x08, 0x43, - 0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49, 0xe3, 0x0c, 0x8e, - 0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11, 0xe1, 0x30, 0x59, - 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x66, - 0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f, 0x75, 0xee, 0x65, - 0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c, 0xdb, 0x46, 0xe5, - 0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20, 0x0a, 0x37, 0xf0, - 0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4, 0x4a, 0x45, 0x02, - 0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf, 0x6b, 0x0b, 0x6b, - 0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, 0x74, 0x31, 0x4e, - 0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, - 0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, - 0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27, - 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, - 0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf, 0xd2, 0xfb, 0x1e, - 0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47, 0x4b, 0xfe, 0xd0, - 0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02, 0x20, 0x6b, 0xcf, - 0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b, 0xad, 0xf5, 0xb9, - 0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e, 0x80, 0xef, 0xb5, - 0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x30, 0x82, 0x01, 0x82, 0x31, 0x82, - 0x01, 0x35, 0x30, 0x12, 0x0c, 0x0d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x01, 0x01, 0x01, 0x30, 0x14, - 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x29, 0x0c, 0x0d, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, - 0x74, 0x31, 0x18, 0x30, 0x16, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x06, 0x69, 0x43, 0x6c, - 0x6f, 0x75, 0x64, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, - 0x18, 0x16, 0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, - 0x30, 0x30, 0x35, 0x39, 0x2e, 0x39, 0x36, 0x30, 0x38, 0x33, 0x35, 0x5a, - 0x30, 0x55, 0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, - 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0x53, - 0x1d, 0x77, 0x7c, 0x1b, 0x8a, 0x53, 0xad, 0x88, 0xdf, 0x56, 0xf9, 0x11, - 0xfd, 0x40, 0x69, 0x7c, 0x0b, 0xbb, 0x2a, 0xf7, 0x48, 0x7e, 0x69, 0x3d, - 0x0c, 0xfb, 0xc8, 0x90, 0x27, 0xb5, 0x18, 0x88, 0x09, 0x3f, 0x06, 0x37, - 0xca, 0x5d, 0x9c, 0x64, 0x34, 0x13, 0x89, 0x09, 0xe9, 0x0e, 0x99, 0xa3, - 0xc8, 0xc1, 0x86, 0xb3, 0x6e, 0x30, 0xf1, 0x20, 0x38, 0x78, 0x56, 0x40, - 0xf4, 0xd7, 0x36, 0x30, 0x5a, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x47, - 0x30, 0x45, 0x02, 0x20, 0x45, 0x47, 0xbf, 0x5b, 0x4d, 0x57, 0x77, 0x90, - 0x7b, 0x74, 0x90, 0x2f, 0x5d, 0x7b, 0x02, 0x3c, 0x21, 0xe8, 0x5c, 0x24, - 0x0c, 0x77, 0xd8, 0x19, 0xff, 0xce, 0x28, 0x45, 0x76, 0x50, 0xb1, 0xee, - 0x02, 0x21, 0x00, 0xe3, 0xea, 0x0f, 0xcb, 0x72, 0xd7, 0x88, 0x15, 0xa4, - 0x71, 0xbe, 0x9e, 0xa6, 0xf2, 0x9c, 0xa8, 0x9b, 0x93, 0xec, 0x31, 0x7a, - 0xe3, 0x92, 0x8a, 0xf2, 0x2f, 0xfd, 0x98, 0xc9, 0xe1, 0xc4, 0x7c, 0x04, - 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xce, 0x5f, 0x67, 0x9d, 0x78, 0x9f, - 0xc6, 0x3b, 0xb3, 0x51, 0xde, 0x6d, 0x9e, 0xff, 0xf5, 0xab, 0xda, 0xf4, - 0x7e, 0xb2, 0xe9, 0x1a, 0xf2, 0xd9, 0x0d, 0x48, 0x30, 0x07, 0xbc, 0x06, - 0xf5, 0x42, 0x02, 0x20, 0x64, 0x1d, 0x7d, 0x43, 0xc1, 0x3b, 0x50, 0xd6, - 0x7b, 0x3b, 0xce, 0x6f, 0xec, 0x23, 0x21, 0x8a, 0x9b, 0x06, 0x3f, 0x64, - 0xfe, 0xd6, 0x29, 0xaf, 0x5b, 0x0c, 0x69, 0x8f, 0x48, 0x88, 0x08, 0x1e, - 0x30, 0x00, 0x30, 0x00, 0x31, 0x81, 0xd0, 0x30, 0x66, 0x0c, 0x1a, 0x30, - 0x56, 0x4f, 0x73, 0x47, 0x76, 0x56, 0x72, 0x51, 0x46, 0x4e, 0x46, 0x6b, - 0x52, 0x35, 0x37, 0x71, 0x59, 0x73, 0x4c, 0x47, 0x6f, 0x33, 0x49, 0x50, - 0x51, 0x04, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xf9, 0xc9, 0x69, 0xda, - 0x69, 0xe7, 0x32, 0xeb, 0x14, 0xc1, 0xbd, 0x56, 0xb7, 0x3e, 0xab, 0x08, - 0x6d, 0xe2, 0x16, 0xd9, 0x0a, 0xa8, 0x67, 0x7a, 0x56, 0xdc, 0x64, 0xf2, - 0x2f, 0x2e, 0xe8, 0xb9, 0x02, 0x21, 0x00, 0xac, 0x5c, 0x29, 0x80, 0x60, - 0x57, 0xd7, 0x51, 0x23, 0x1f, 0x00, 0x09, 0x70, 0xf3, 0xd5, 0x1a, 0x49, - 0xad, 0xaf, 0x35, 0x77, 0x07, 0xf4, 0x85, 0x1f, 0x63, 0xe0, 0xea, 0x67, - 0x36, 0xb5, 0x3b, 0x30, 0x66, 0x0c, 0x1a, 0x6e, 0x6b, 0x62, 0x77, 0x33, - 0x2f, 0x57, 0x72, 0x39, 0x4f, 0x33, 0x6a, 0x45, 0x68, 0x4f, 0x48, 0x46, - 0x67, 0x32, 0x34, 0x67, 0x62, 0x4d, 0x61, 0x6a, 0x76, 0x04, 0x48, 0x30, - 0x46, 0x02, 0x21, 0x00, 0x9f, 0x4f, 0x60, 0x2f, 0x54, 0x5e, 0x9f, 0x6a, - 0x7d, 0x37, 0xd9, 0x9f, 0x62, 0x69, 0xd7, 0x8c, 0xfc, 0xf5, 0x78, 0x54, - 0x7d, 0xb6, 0x91, 0x4b, 0x48, 0x88, 0x3d, 0x59, 0x05, 0x70, 0x09, 0xbf, - 0x02, 0x21, 0x00, 0xe2, 0xaf, 0xc9, 0x27, 0x12, 0xfa, 0x64, 0x51, 0x19, - 0x13, 0x1d, 0x57, 0x56, 0x6b, 0x93, 0xa3, 0xc6, 0x31, 0xf8, 0x70, 0x97, - 0x9e, 0x79, 0xf5, 0xc0, 0x2d, 0xf3, 0x3c, 0x8b, 0x86, 0x92, 0x28, 0x04, - 0x82, 0x01, 0xb8, 0x30, 0x82, 0x01, 0xb4, 0x30, 0x82, 0x01, 0xa2, 0x31, - 0x82, 0x01, 0x56, 0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, - 0x69, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, - 0x00, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16, - 0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30, - 0x35, 0x39, 0x2e, 0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55, - 0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e, - 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e, - 0x16, 0x03, 0x13, 0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4, - 0xf0, 0x47, 0x52, 0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06, - 0x73, 0x23, 0x72, 0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61, - 0xc9, 0x08, 0x43, 0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49, - 0xe3, 0x0c, 0x8e, 0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11, - 0xe1, 0x30, 0x59, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44, - 0x02, 0x20, 0x66, 0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f, - 0x75, 0xee, 0x65, 0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c, - 0xdb, 0x46, 0xe5, 0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20, - 0x0a, 0x37, 0xf0, 0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4, - 0x4a, 0x45, 0x02, 0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf, - 0x6b, 0x0b, 0x6b, 0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, - 0x74, 0x31, 0x4e, 0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, - 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, - 0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, - 0x63, 0x68, 0x27, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30, - 0x44, 0x02, 0x20, 0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf, - 0xd2, 0xfb, 0x1e, 0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47, - 0x4b, 0xfe, 0xd0, 0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02, - 0x20, 0x6b, 0xcf, 0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b, - 0xad, 0xf5, 0xb9, 0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e, - 0x80, 0xef, 0xb5, 0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x04, 0x0c, 0x6b, - 0x65, 0x79, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41, - 0x94, 0x6d, 0x46, 0x38, 0xde, 0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86, - 0xbe, 0xd5, 0x78, 0x08, 0x2f, 0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f, - 0x1e, 0xca, 0x05, 0x21, 0x51, 0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46, - 0x53, 0x7e, 0x49, 0x97, 0xb8, 0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92, - 0xdd, 0x30, 0xe2, 0x4d, 0xd4, 0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c, - 0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41, 0x94, 0x6d, 0x46, 0x38, 0xde, - 0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86, 0xbe, 0xd5, 0x78, 0x08, 0x2f, - 0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f, 0x1e, 0xca, 0x05, 0x21, 0x51, - 0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46, 0x53, 0x7e, 0x49, 0x97, 0xb8, - 0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92, 0xdd, 0x30, 0xe2, 0x4d, 0xd4, - 0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c, 0x04, 0x27, 0x30, 0x25, 0x04, - 0x10, 0x48, 0xd4, 0x7b, 0x6a, 0x50, 0xfb, 0x84, 0xf8, 0xb5, 0x8d, 0x13, - 0x62, 0xcc, 0x42, 0xa5, 0x42, 0x02, 0x03, 0x00, 0xc3, 0x50, 0x02, 0x02, - 0x01, 0x00, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07, - 0x31, 0x00 }; -#endif - -#define kCompatibilityTestCount 0 -#if 0 -static void test_v6(void) { - SOSDataSourceFactoryRef ak_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(ak_factory, CFSTR("ak"), test_source); - CFErrorRef error = NULL; - - const uint8_t *der_p = v6_der; - - SOSAccount* convertedAccount = SOSAccountCreateFromDER(kCFAllocatorDefault, ak_factory, &error, &der_p, v6_der + sizeof(v6_der)); - - ok(convertedAccount, "inflate v6 account (%@)", error); - CFReleaseSafe(error); - - is(kSOSCCInCircle, [convertedAccount.trust getCircleStatus:&error], "in the circle"); - - CFReleaseSafe(convertedAccount); - ak_factory->release(ak_factory); - SOSDataSourceRelease(test_source, NULL); -} -#endif - -static int kTestTestCount = 11 + kSecdTestSetupTestCount; -static void tests(void) -{ - - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - - SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"), CFSTR("TestType")); - ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - ok(NULL != account, "Created"); - - ok(SOSAccountResetToOffering_wTxn(account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - ok(testAccountPersistence(account), "Test Account->DER->Account Equivalence"); - - SOSTestCleanup(); - - test_factory->release(test_factory); - SOSDataSourceRelease(test_source, NULL); -} - -int secd_51_account_inflate(int argc, char *const *argv) -{ - plan_tests(kTestTestCount + kCompatibilityTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - secd_test_clear_testviews(); - tests(); - - /* we can't re-inflate the v6 DER since we don't have a viable private key for it. */ - // test_v6(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-52-account-changed.m b/OSX/sec/securityd/Regressions/secd-52-account-changed.m deleted file mode 100644 index 214c0ab6..00000000 --- a/OSX/sec/securityd/Regressions/secd-52-account-changed.m +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include - -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges( CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "update"); - - - CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); - ok ([bob_account.trust updateGestalt:bob_account newGestalt:new_gestalt], "did we send a null circle?"); - CFReleaseNull(new_gestalt); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "nothing published"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - /* ==================== Three Accounts setup =============================================*/ - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); - - - ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); - - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "update"); - - accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); - accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); - CFDictionaryRef alice_devstate = SOSTestSaveStaticAccountState(alice_account); - CFDictionaryRef bob_devstate = SOSTestSaveStaticAccountState(bob_account); - CFDictionaryRef carol_devstate = SOSTestSaveStaticAccountState(carol_account); - - /* ==================== Three Accounts in circle =============================================*/ - InjectChangeToMulti(changes, CFSTR("^AccountChanged"), CFSTR("none"), alice_account, bob_account, carol_account, NULL); - SOSAccountInflateTestTransportsForCircle(alice_account, CFSTR("TestSource"), CFSTR("Alice"), &error); - SOSAccountInflateTestTransportsForCircle(bob_account, CFSTR("TestSource"), CFSTR("Bob"), &error); - SOSAccountInflateTestTransportsForCircle(carol_account, CFSTR("TestSource"), CFSTR("Carol"), &error); - - SOSTestRestoreAccountState(alice_account, alice_devstate); - SOSTestRestoreAccountState(bob_account, bob_devstate); - SOSTestRestoreAccountState(carol_account, carol_devstate); - - is([alice_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); - CFReleaseNull(error); - is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); - CFReleaseNull(error); - is([carol_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); - CFReleaseNull(error); - - CFDataRef cfpassword2 = CFDataCreate(NULL, (uint8_t *) "ooFooFooF", 10); - CFStringRef cfaccount2 = CFSTR("test2@test.org"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - is([alice_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); - is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - is([bob_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); - is([carol_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); - // Now everyone is playing the same account. - - /* ==================== Three Accounts setup =============================================*/ - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - is(countActivePeers(alice_account), 2, "2 peers - alice and icloud"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - is([alice_account getCircleStatus:&error], kSOSCCInCircle, "Alice is in circle"); - is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in circle"); - is([carol_account getCircleStatus:&error], kSOSCCNotInCircle, "Carol is not in circle"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - is([carol_account getCircleStatus:&error], kSOSCCRequestPending, "Carol has a pending request"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - is(countActivePeers(alice_account), 4, "4 peers - alice, bob, carol, and icloud"); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); - - accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); - accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); - - CFReleaseSafe(cfpassword2); - CFReleaseNull(changes); - alice_account = nil; - bob_account = nil; - carol_account = nil; - - SOSTestCleanup(); - -} - - -int secd_52_account_changed(int argc, char *const *argv) -{ - plan_tests(113); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m b/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m deleted file mode 100644 index 22a15018..00000000 --- a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - - SOSAccountTrustClassic *carolTrust = carol_account.trust; - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); - CFReleaseNull(error); - ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); - CFReleaseNull(cfwrong_password); - is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - //bob now goes def while Alice does some stuff. - - ok([alice_account.trust leaveCircle:alice_account err:&error], "ALICE LEAVES THE CIRCLE (%@)", error); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Alice resets to offering again (%@)", error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - - ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - SOSAccountSetUserPublicTrustedForTesting(carol_account); - ok(SOSAccountResetToOffering_wTxn(carol_account, &error), "Carol is going to push a reset to offering (%@)", error); - - int64_t valuePtr = 0; - CFNumberRef gencount = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &valuePtr); - - SOSCircleSetGeneration(carolTrust.trustedCircle, gencount); - - SecKeyRef user_privkey = SOSUserKeygen(cfpassword, (__bridge CFDataRef)(carol_account.accountKeyDerivationParamters), &error); - CFNumberRef genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); - CFIndex testPtr; - CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); - ok(testPtr== 0); - - SOSCircleSignOldStyleResetToOfferingCircle(carolTrust.trustedCircle, carolTrust.fullPeerInfo, user_privkey, &error); - - SOSTransportCircleTestRemovePendingChange((SOSCircleStorageTransportTest*)carol_account.circle_transport, SOSCircleGetName(carolTrust.trustedCircle), NULL); - CFDataRef circle_data = SOSCircleCopyEncodedData(carolTrust.trustedCircle, kCFAllocatorDefault, &error); - if (circle_data) { - [carol_account.circle_transport postCircle:SOSCircleGetName(carolTrust.trustedCircle) circleData:circle_data err:&error]; - } - CFReleaseNull(circle_data); - - genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); - CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); - ok(testPtr== 0); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - SOSAccountSetUserPublicTrustedForTesting(alice_account); - SOSAccountSetUserPublicTrustedForTesting(bob_account); - - is(ProcessChangesUntilNoChange(changes, carol_account, alice_account, bob_account, NULL), 2, "updates"); - - is([alice_account getCircleStatus:&error],kSOSCCNotInCircle,"alice is not in the account (%@)", error); - is([bob_account getCircleStatus:&error], kSOSCCNotInCircle,"bob is not in the account (%@)", error); - is([carol_account getCircleStatus:&error], kSOSCCInCircle,"carol is in the account (%@)", error); - - CFReleaseNull(gencount); - CFReleaseNull(cfpassword); - CFReleaseNull(user_privkey); - alice_account = nil; - bob_account = nil; - carol_account = nil; - - SOSTestCleanup(); -} - -int secd_52_offering_gencount_reset(int argc, char *const *argv) -{ - plan_tests(63); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-55-account-circle.m b/OSX/sec/securityd/Regressions/secd-55-account-circle.m deleted file mode 100644 index 9e91f032..00000000 --- a/OSX/sec/securityd/Regressions/secd-55-account-circle.m +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 257; - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); - CFReleaseNull(error); - ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); - CFReleaseNull(cfwrong_password); - is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - ok(SOSAccountHasCompletedInitialSync(alice_account), "Alice thinks she's completed initial sync"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - ok(!SOSAccountHasCompletedInitialSync(bob_account), "Bob thinks he hasn't completed initial sync"); - - CFDictionaryRef alice_new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice, but different")); - - ok([alice_account.trust updateGestalt:alice_account newGestalt:alice_new_gestalt], "Update gestalt %@ (%@)", alice_account, error); - SOSAccountUpdateTestTransports(alice_account, alice_new_gestalt); - CFReleaseNull(alice_new_gestalt); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - accounts_agree("Alice's name changed", bob_account, alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - accounts_agree("Alice bails", bob_account, alice_account); - - peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 1, "See one peer %@ (%@)", peers, error); - CFReleaseNull(peers); - - ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - accounts_agree("Alice accepts' Bob", bob_account, alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - accounts_agree("Bob accepts Alice", bob_account, alice_account); - - // As of PR-13917727/PR-13906870 this no longer works (by "design"), in favor of making another more common - // failure (apply/OSX-psudo-reject/re-apply) work. Write races might be "fixed better" with affirmitave rejection. -#if 0 - - // - // Write race emulation. - // - // - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - FeedChangesTo(changes, bob_account); // Bob sees Alice leaving and rejoining - FeedChangesTo(changes, alice_account); // Alice sees bob concurring - - accounts_agree("Alice leaves & returns", bob_account, alice_account); - - ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - FeedChangesTo(changes, bob_account); // Bob sees Alice Applying - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - CFMutableDictionaryRef bobAcceptanceChanges = ExtractPendingChanges(changes); - - // Alice re-applies without seeing that she was accepted. - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves again (%@)", error); - CFReleaseNull(error); - ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - CFReleaseSafe(ExtractPendingChanges(changes)); // Alice loses the race to write her changes - bob never sees em. - - FeedChangesTo(&bobAcceptanceChanges, alice_account); // Alice sees bob inviting her in the circle. - - FeedChangesTo(changes, bob_account); // Bob sees Alice Concurring - - // As of PR-13917727/PR-13906870 - accounts_agree("Alice leave, applies back, loses a race and eventually gets in", bob_account, alice_account); -#endif - - // Both in circle. - - // Emulation of Innsbruck11A368 +Roots: Device A was removed when Device B joined. - - // We want Alice to leave circle while an Applicant on a full concordance signed circle with old-Alice as an Alum and Bob a peer. - // ZZZ - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves once more (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - accounts_agree("Alice and Bob see Alice out of circle", bob_account, alice_account); - - ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves while applying (%@)", error); - FeedChangesTo(changes, bob_account); // Bob sees Alice become an Alum. - - CFReleaseNull(error); - - is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice isn't applying any more"); - accounts_agree("Alice leaves & some fancy concordance stuff happens", bob_account, alice_account); - - ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - //FeedChangesTo(changes, bob_account); // Bob sees Alice reapply. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - accounts_agree("Alice comes back", bob_account, alice_account); - - // Emulation of - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); - CFReleaseNull(error); - - CFMutableDictionaryRef dropped_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - FillChanges(dropped_changes, carol_account); - CFReleaseNull(dropped_changes); - - ok(SOSAccountResetToOffering_wTxn(carol_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 2, "updates"); - accounts_agree("13889901", carol_account, bob_account); - is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSMembershipRevoked, "Bob affirms he hasn't left."); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob ReApplies (%@)", error); - is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 2, "updates"); - { - CFArrayRef applicants = SOSAccountCopyApplicants(carol_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(carol_account, applicants, &error), "Carol accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 3, "updates"); - accounts_agree("rdar://problem/13889901-II", bob_account, carol_account); - - // Alice has been out of the loop, bring her back up to speed before changing things (to avoid gen count race) - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "Reset propogation"); - - // Test multiple removal, including our own departure via that API - ok(SOSAccountResetToOffering_wTxn(alice_account, NULL), "Reset to offering"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "Reset propogation"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, NULL), "bob joins again"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "Bob request"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "carol request"); - - ok(SOSAccountJoinCircles_wTxn(carol_account, NULL), "carol joins again"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "carol request"); - - CFArrayRef peers_to_remove_array = CFArrayCreateForCFTypes(kCFAllocatorDefault, - bob_account.peerInfo, - carol_account.peerInfo, - NULL); - - ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, NULL)); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "Remove peers"); - - ok([alice_account isInCircle:&error], "Alice still here"); - ok(![bob_account isInCircle:&error], "Bob not in circle"); - // Carol's not in circle, but reapplied, as she's persistent until positive rejection. - ok(![carol_account isInCircle:NULL], "carol not in circle"); - - CFReleaseNull(peers_to_remove_array); - - CFReleaseNull(alice_new_gestalt); - alice_account = nil; - bob_account = nil; - carol_account = nil; - - SOSTestCleanup(); -} - -int secd_55_account_circle(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m b/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m deleted file mode 100644 index fcb6b210..00000000 --- a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 10; - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef data_name = CFSTR("TestSource"); - CFStringRef circle_key_name = SOSCircleKeyCreateWithName(data_name, NULL); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_name); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_name); - SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), data_name); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - FillAllChanges(changes); - FeedChangesToMulti(changes, alice_account, carol_account, NULL); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); - CFReleaseNull(cfwrong_password); - is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); - CFReleaseNull(error); - - CFDataRef incompatibleDER = SOSCircleCreateIncompatibleCircleDER(&error); - - InjectChangeToMulti(changes, circle_key_name, incompatibleDER, alice_account, NULL); - CFReleaseNull(circle_key_name); - CFReleaseNull(incompatibleDER); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - CFReleaseNull(changes); - alice_account = nil; - bob_account = nil; - carol_account = nil; - SOSTestCleanup(); -} - -int secd_55_account_incompatibility(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-56-account-apply.m b/OSX/sec/securityd/Regressions/secd-56-account-apply.m deleted file mode 100644 index 7e12348f..00000000 --- a/OSX/sec/securityd/Regressions/secd-56-account-apply.m +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -#define kAccountPasswordString ((uint8_t*) "FooFooFoo") -#define kAccountPasswordStringLen 10 - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - // Lost Application Scenario - is(ProcessChangesOnce(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies too (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - accounts_agree("alice and carole agree", alice_account, carole_account); - accounts_agree("alice and bob agree", alice_account, bob_account); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - accounts_agree("alice and carole agree", alice_account, carole_account); - - CFReleaseNull(error); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); - ok(SOSAccountRejectApplicants(alice_account, applicants, &error), "Everyone out the pool"); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - accounts_agree("alice and carole agree", alice_account, carole_account); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - ok(applicants && CFArrayGetCount(applicants) == 0, "See no applicants %@ (%@)", applicants, error); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole bails (%@)", error); - CFReleaseNull(error); - - // Everyone but bob sees that carole bails. - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 1, "updates"); - - - // Bob reapplies, but it's to an old circle. - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob asks again"); - CFReleaseNull(error); - - // Bob returns and we mix our split worlds up. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); - CFReleaseNull(error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - is(countPeers(bob_account), 2, "Bob sees 2 valid peers after admission from re-apply"); - - accounts_agree("alice and bob agree", alice_account, bob_account); - accounts_agree_internal("alice and carole agree", alice_account, carole_account, false); - - - // Rejected Application Scenario - ok(SOSAccountJoinCircles_wTxn(david_account, &error), "Dave Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - accounts_agree_internal("alice and david agree", alice_account, david_account, false); - - SOSAccountPurgePrivateCredential(alice_account); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountRejectApplicants(alice_account, applicants, &error), "Alice rejects (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - accounts_agree_internal("alice and carole still agree after david is rejected", alice_account, carole_account, false); - - cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); - - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identiy joins (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); - - accounts_agree_internal("carole&alice pair", carole_account, alice_account, false); - - is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); - - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_56_account_apply(int argc, char *const *argv) -{ - plan_tests(181); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m b/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m deleted file mode 100644 index ba45cf74..00000000 --- a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m +++ /dev/null @@ -1,161 +0,0 @@ -// -// secd-57-1-account-last-standing.c -// sec -// -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -static bool acceptApplicants(SOSAccount* account, CFIndex count) { - bool retval = false; - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - ok(applicants && CFArrayGetCount(applicants) == count, "See %ld applicants %@ (%@)", count, applicants, error); - CFReleaseNull(error); - require_quiet(CFArrayGetCount(applicants) == count, xit); - ok((retval=SOSAccountAcceptApplicants(account, applicants, &error)), "Accept applicants into the fold"); - CFReleaseNull(error); -xit: - CFReleaseNull(applicants); - return retval; -} - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(alice_account , &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - ok([alice_account isInCircle:&error], "Alice is back in the circle (%@)", error); - CFReleaseNull(error); - - is(countActivePeers(alice_account), 2, "Alice sees 2 active peers"); - is(countPeers(alice_account), 1, "Alice sees 1 valid peer"); - - // Have Alice leave the circle just as Bob tries to join. - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - - is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 1, "updates"); - ok(SOSAccountTryUserCredentials(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountJoinCircles_wTxn(carole_account , &error), "Carole applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 2, "updates"); - ok(acceptApplicants(alice_account, 1), "Alice accepts Carole"); - is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 3, "updates"); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); - - ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); - ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob applies (%@)", error); - is(ProcessChangesUntilNoChange(changes, bob_account, NULL), 2, "updates"); - CFReleaseNull(error); - - is(countActivePeers(bob_account), 2, "Bob sees 2 active peers"); - is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); - - - CFReleaseNull(cfpassword); - - alice_account = nil; - SOSTestCleanup(); -} - -int secd_57_1_account_last_standing(int argc, char *const *argv) -{ - plan_tests(45); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-57-account-leave.m b/OSX/sec/securityd/Regressions/secd-57-account-leave.m deleted file mode 100644 index 4c9b0732..00000000 --- a/OSX/sec/securityd/Regressions/secd-57-account-leave.m +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -/* - static void trim_retirements_from_circle(SOSAccount* account) { - SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { - SOSCircleRemoveRetired(circle, NULL); - }); - } - */ - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account , applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - SOSAccountPurgePrivateCredential(alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - accounts_agree("Alice bails", bob_account, alice_account); - - { - CFArrayRef concurring = SOSAccountCopyConcurringPeers(alice_account, &error); - - ok(concurring && CFArrayGetCount(concurring) == 2, "See two concurring %@ (%@)", concurring, error); - CFReleaseNull(error); - CFReleaseNull(concurring); - } - - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(alice_account , &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - is(countActivePeers(bob_account), 3, "Bob sees 2 active peers"); - is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See alice's reapp. %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - - is(countActivePeers(bob_account), 3, "Bob sees 3 active peers"); - is(countPeers(bob_account), 2, "Bob sees 2 valid peers"); - - is(countActivePeers(alice_account), 3, "Alice sees 2 active peers"); - is(countPeers(alice_account), 1, "Alice sees 1 valid peers"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - accounts_agree("Alice rejoined", bob_account, alice_account); - accounts_agree_internal("Alice rejoined, carole noticed", bob_account, carole_account, false); - - ok(SOSAccountJoinCircles_wTxn(carole_account , &error), "Carole applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - accounts_agree_internal("Carole applied", bob_account, alice_account, false); - accounts_agree_internal("Carole applied - 2", bob_account, carole_account, false); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See Carole's eapp. %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts carole (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); - // david ends up with a 3 peerinfo member circle. - - accounts_agree_internal("Carole joined", bob_account, alice_account, false); - accounts_agree_internal("Carole joined - 2", bob_account, carole_account, false); - - // Now test lost circle change when two leave simultaneously, needing us to see the retirement tickets - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - ok([carole_account.trust leaveCircle:carole_account err:&error], "carole Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); - is(countActivePeers(bob_account), 4, "Bob sees 4 active peers"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - is(SOSAccountGetLastDepartureReason(carole_account, &error), kSOSWithdrewMembership, "Carole affirms she left on her own."); - - ok(SOSAccountAssertUserCredentialsAndUpdate(david_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - is(countPeers(david_account), 1, "david sees 1 peers"); - is(countActivePeers(david_account), 4, "david sees 4 active peers"); - - ok(SOSAccountJoinCircles_wTxn(david_account , &error), "David applies (%@)", error); - CFReleaseNull(error); - is(countPeers(david_account), 1, "david sees 1 peers"); - is(countActivePeers(david_account), 4, "david sees 4 active peers"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See David's app. %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts carole (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - is(countPeers(bob_account), 2, "Bob sees 2 valid peer"); - is(countActivePeers(bob_account), 3, "Bob sees 3 active peers"); - - - // Now see that bob can call leave without his private key - SOSAccountPurgeIdentity(bob_account); // Hopefully this actually purges, no errors to process - - ok([bob_account.trust leaveCircle:bob_account err:&error], "bob Leaves w/o credentials (%@)", error); - CFReleaseNull(error); - - ok(![bob_account isInCircle:&error], "bob knows he's out (%@)", error); - CFReleaseNull(error); - alice_account = nil; - bob_account = nil; - - SOSTestCleanup(); -} - -int secd_57_account_leave(int argc, char *const *argv) -{ - plan_tests(191); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - secd_test_clear_testviews(); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-58-password-change.m b/OSX/sec/securityd/Regressions/secd-58-password-change.m deleted file mode 100644 index ca235fbb..00000000 --- a/OSX/sec/securityd/Regressions/secd-58-password-change.m +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" -#include "SecdTestKeychainUtilities.h" - - -static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef password) { - CFErrorRef error = NULL; - bool retval; - ok((retval = SOSAccountAssertUserCredentialsAndUpdate(account, acct_name, password, &error)), "Credential setting (%@)", error); - CFReleaseNull(error); - return retval; -} - -static bool ResetToOffering(SOSAccount* account) { - CFErrorRef error = NULL; - bool retval; - ok((retval = SOSAccountResetToOffering_wTxn(account, &error)), "Reset to offering (%@)", error); - CFReleaseNull(error); - return retval; -} - -static bool JoinCircle(SOSAccount* account) { - CFErrorRef error = NULL; - bool retval; - ok((retval = SOSAccountJoinCircles_wTxn(account, &error)), "Join Circle (%@)", error); - CFReleaseNull(error); - return retval; -} - -static bool AcceptApplicants(SOSAccount* account, CFIndex cnt) { - CFErrorRef error = NULL; - bool retval = false; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - - ok((retval = (applicants && CFArrayGetCount(applicants) == cnt)), "See applicants %@ (%@)", applicants, error); - if(retval) ok((retval = SOSAccountAcceptApplicants(account, applicants, &error)), "Accept Applicants (%@)", error); - CFReleaseNull(applicants); - CFReleaseNull(error); - return retval; -} - -static void tests(void) -{ - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - - /* Set Initial Credentials and Parameters for the Syncing Circles ---------------------------------------*/ - ok(AssertCreds(bob_account, cfaccount, cfpassword), "Setting credentials for Bob"); - // Bob wins writing at this point, feed the changes back to alice. - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - ok(AssertCreds(alice_account, cfaccount, cfpassword), "Setting credentials for Alice"); - ok(AssertCreds(carol_account, cfaccount, cfpassword), "Setting credentials for Carol"); - CFReleaseNull(cfpassword); - - /* Make Alice First Peer -------------------------------------------------------------------------------*/ - ok(ResetToOffering(alice_account), "Reset to offering - Alice as first peer"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - /* Bob Joins -------------------------------------------------------------------------------------------*/ - ok(JoinCircle(bob_account), "Bob Applies"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - /* Alice Accepts -------------------------------------------------------------------------------------------*/ - ok(AcceptApplicants(alice_account, 1), "Alice Accepts Bob's Application"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "4 updates"); - accounts_agree("bob&alice pair", bob_account, alice_account); - - /* Carol Applies -------------------------------------------------------------------------------------------*/ - ok(JoinCircle(carol_account), "Carol Applies"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - is(countPeers(alice_account), 2, "See two peers"); - - - /* Change Password ------------------------------------------------------------------------------------------*/ - CFDataRef cfnewpassword = CFDataCreate(NULL, (uint8_t *) "ooFooFooF", 10); - - ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); - is(countPeers(bob_account), 2, "There are two valid peers - iCloud and Bob"); - is(countActivePeers(bob_account), 3, "There are three active peers - bob, alice, and iCloud"); - is(countActiveValidPeers(bob_account), 2, "There is two active valid peer - Bob and iCloud"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - is(countPeers(alice_account), 2, "There are two peers - bob and alice"); - is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - is(countPeers(alice_account), 2, "There are two peers - bob and alice"); - is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); - - ok(AssertCreds(carol_account , cfaccount, cfnewpassword), "Credential resetting for Carol"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); - - ok(AcceptApplicants(alice_account , 1), "Alice Accepts Carol's Application"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); - - accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); - accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); - accounts_agree_internal("carol&alice pair", alice_account, carol_account, false); - - - /* Change Password 2 ----------------------------------------------------------------------------------------*/ - CFReleaseNull(cfnewpassword); - cfnewpassword = CFDataCreate(NULL, (uint8_t *) "ffoffoffo", 10); - - /* Bob */ - ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - - is(countPeers(bob_account), 3, "There are three peers - Alice, Carol, Bob"); - is(countActivePeers(bob_account), 4, "There are four active peers - bob, alice, carol and iCloud"); - is(countActiveValidPeers(bob_account), 2, "There is two active valid peer - Bob and iCloud"); - - - /* Alice */ - ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); - - is(countPeers(alice_account), 3, "There are three peers - Alice, Carol, Bob"); - is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); - is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); - - - /* Carol */ - ok(AssertCreds(carol_account , cfaccount, cfnewpassword), "Credential resetting for Carol"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); - - is(countPeers(carol_account), 3, "There are three peers - Alice, Carol, Bob"); - is(countActivePeers(carol_account), 4, "There are four active peers - bob, alice, carol and iCloud"); - is(countActiveValidPeers(carol_account), 4, "There are three active valid peers - alice, bob, carol, and icloud"); - - accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); - - /* Change Password 3 - cause a parm lost update collision ----------------------------------------------------*/ - CFReleaseNull(cfnewpassword); - cfnewpassword = CFDataCreate(NULL, (uint8_t *) "cococococ", 10); - - ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); - ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); - - is(countPeers(alice_account), 3, "There are three peers - Alice, Carol, Bob"); - is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); - is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); - - CFReleaseNull(cfnewpassword); - alice_account = nil; - bob_account = nil; - carol_account = nil; - SOSTestCleanup(); -} - -int secd_58_password_change(int argc, char *const *argv) -{ - plan_tests(211); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m b/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m deleted file mode 100644 index 380ae6ab..00000000 --- a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef circle_name = CFSTR("TestSource"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circle_name); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circle_name); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), circle_name); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - accounts_agree("Alice bails", bob_account, alice_account); - accounts_agree("Alice bails", bob_account, carole_account); - - [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - - { - CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts Carole (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("Carole joins", bob_account, carole_account); - - [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - is(countPeers(bob_account), 2, "Active peers after forced cleanup"); - is(countActivePeers(bob_account), 3, "Inactive peers after forced cleanup"); - - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_59_account_cleanup(int argc, char *const *argv) -{ - plan_tests(91); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m b/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m deleted file mode 100644 index cdccf871..00000000 --- a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 111; - -#if FIX_ICLOUD_IDENTITY_AS_SET_CRED_SIDE_EFFECT - -static bool purgeICloudIdentity(SOSAccount* account) { - bool retval = false; - SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef([account.trust getCircle:NULL], NULL); - if(!icfpi) return false; - retval = SOSFullPeerInfoPurgePersistentKey(icfpi, NULL); - CFReleaseNull(icfpi); - return retval; -} - -#endif - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - /*----- normal join after restore -----*/ - - ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); - - is(countApplicants(alice_account), 0, "See no applicants"); - - is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - accounts_agree_internal("Carole's in", bob_account, alice_account, false); - accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); - - ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - /*----- join - join after restore -----*/ - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole normally joins (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - is(countApplicants(alice_account), 1, "See one applicant"); - - ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); - - - is(countApplicants(alice_account), 0, "See no applicants"); - - is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - accounts_agree_internal("Carole's in", bob_account, alice_account, false); - accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); - -#if FIX_ICLOUD_IDENTITY_AS_SET_CRED_SIDE_EFFECT - /* Break iCloud identity FPI in all peers */ - - ok(purgeICloudIdentity(alice_account), "remove iCloud private key"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); - - ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - /*----- join - join after restore -----*/ - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole normally joins (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - is(countApplicants(alice_account), 1, "See one applicant"); - - ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); - - - is(countApplicants(alice_account), 0, "See no applicants"); - - is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - accounts_agree_internal("Carole's in", bob_account, alice_account, false); - accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); -#endif - //join after piggybacking the icloud identity?? - CFMutableArrayRef identityArray = SOSAccountCopyiCloudIdentities(alice_account); - - NSMutableArray *encodedIdenities = [NSMutableArray array]; - CFIndex i, count = CFArrayGetCount(identityArray); - for (i = 0; i < count; i++) { - SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identityArray, i); - NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, NULL)); - if (data) - [encodedIdenities addObject:data]; - } - - //store in keychain as the piggy icloud - [encodedIdenities enumerateObjectsUsingBlock:^(NSData *v_data, NSUInteger idx, BOOL *stop) { - - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.sos", - (id)kSecAttrLabel : @"Cloud Identity - piggy", - (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, - (id)kSecUseTombstones : (id)kCFBooleanTrue, - (id)kSecValueData : v_data, - } mutableCopy]; - - OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); - - if(status == errSecDuplicateItem) { - // Sure, okay, fine, we'll update. - NSMutableDictionary* update = [@{ - (id)kSecValueData: v_data, - } mutableCopy]; - query[(id)kSecValueData] = nil; - - status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); - ok(status == 0, "Grabbed icloud identity from the keychain %@", error); - } - }]; - - - //now grab this grom the keychain - NSMutableDictionary* query2 = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.sos", - (id)kSecAttrLabel : @"Cloud Identity - piggy", - (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, - (id)kSecUseTombstones : (id)kCFBooleanTrue, - (id)kSecReturnData : (id)kCFBooleanTrue, - } mutableCopy]; - CFTypeRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query2, &result); - ok(status == 0, "Grabbed icloud identity from the keychain %@", error); - ok(result != NULL, "result from sec item copy matching query %@", error); - - NSDictionary *keyAttributes = @{ - (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, - (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, - }; - - - SecKeyRef privKey = SecKeyCreateWithData(result, (__bridge CFDictionaryRef)keyAttributes, NULL); - - ok(privKey != NULL, "Private key is NULL"); - SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey); - ok(publicKey != NULL, "Private key is NULL"); - - CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); - ok(public_key_hash != NULL, "hash is not null"); - - CFReleaseNull(publicKey); - - SOSAccount* margaret_account = CreateAccountForLocalChanges(CFSTR("margaret"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(margaret_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - ok(SOSAccountJoinCirclesAfterRestore_wTxn(margaret_account, &error), "Carole cloud identity joins (%@)", error); - - CFReleaseNull(identityArray); - CFReleaseNull(changes); - CFReleaseNull(error); - CFReleaseNull(public_key_hash); - CFReleaseNull(cfpassword); - CFReleaseNull(privKey); - - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_60_account_cloud_identity(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m b/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m deleted file mode 100644 index c6cb5cc7..00000000 --- a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -/* - static void trim_retirements_from_circle(SOSAccount* account) { - SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { - SOSCircleRemoveRetired(circle, NULL); - }); - } - */ -static bool accept_applicants(SOSAccount* account, int count) { - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - bool retval = false; - ok(applicants, "Have Applicants"); - if(!applicants) goto errout; - is(CFArrayGetCount(applicants), count, "See applicants %@ (%@)", applicants, error); - if(CFArrayGetCount(applicants) != count) goto errout; - ok(retval = SOSAccountAcceptApplicants(account, applicants, &error), "Account accepts (%@)", error); -errout: - CFReleaseNull(error); - CFReleaseNull(applicants); - return retval; -} - - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges ( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges ( CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges ( CFSTR("Carole"), CFSTR("TestSource")); - SOSAccount* david_account = CreateAccountForLocalChanges ( CFSTR("David"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); - - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - - ok(accept_applicants(alice_account, 1), "Alice Accepts Application"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); - - // ============================== Alice and Bob are in the Account. ============================================ - - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); - - ok(accept_applicants(alice_account, 1), "Alice Accepts Application"); - - // Let everyone concur. - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 3, "updates"); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - - ok(peers && CFArrayGetCount(peers) == 3, "See three peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - // SOSAccountPurgePrivateCredential(alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); - - - ok(SOSAccountJoinCircles_wTxn(david_account, &error), "David Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); - - ok(accept_applicants(carole_account, 1), "Carole Accepts Application"); - - // ============================== We added Carole and David while Bob was in a drawer. Alice has left ============================================ - - // ============================== Bob comes out of the drawer seeing alice left and doesn't recognize the remainder. ============================================ - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); - - CFReleaseNull(error); - is([carole_account getCircleStatus:&error], kSOSCCInCircle, "Carole still in Circle (%@)", error); - CFReleaseNull(error); - is([david_account getCircleStatus:&error], kSOSCCInCircle, "David still in Circle (%@)", error); - CFReleaseNull(error); - is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in Circle (%@)", error); - CFReleaseNull(error); - is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSLeftUntrustedCircle, "Bob affirms he left because he doesn't know anyone."); - CFReleaseNull(error); - is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice is not in Circle (%@)", error); - CFReleaseNull(error); - is(SOSAccountGetLastDepartureReason(alice_account, &error), kSOSWithdrewMembership, "Alice affirms she left by request."); - CFReleaseNull(error); - - CFReleaseNull(cfpassword); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_61_account_leave_not_in_kansas_anymore(int argc, char *const *argv) -{ - plan_tests(82); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-62-account-backup.m b/OSX/sec/securityd/Regressions/secd-62-account-backup.m deleted file mode 100644 index 2875ef20..00000000 --- a/OSX/sec/securityd/Regressions/secd-62-account-backup.m +++ /dev/null @@ -1,283 +0,0 @@ - -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include -#include - -#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#if !TARGET_OS_SIMULATOR -#include "SOSAccountTesting.h" -#endif -#include "SecdTestKeychainUtilities.h" - -#if !TARGET_OS_SIMULATOR - -static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) -{ - __block CFDataRef result = NULL; - CFStringPerformWithUTF8CFData(string, ^(CFDataRef stringAsData) { - result = SOSCopyDeviceBackupPublicKey(stringAsData, error); - }); - return result; -} -#endif - -static void tests(void) -{ -#if !TARGET_OS_SIMULATOR - - __block CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - - CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); - CFDataRef bob_backup_key = CopyBackupKeyForString(CFSTR("Bob Backup Entropy"), &error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok([bob_account.trust checkForRings:&error], "Bob_account is good"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); - CFReleaseNull(error); - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); - CFReleaseNull(error); - - ok([bob_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice's key in backup before sync?"); - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); - - ok([bob_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice in backup after sync?"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "IS bob in the backup after sync"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); - CFReleaseNull(error); - - // - //Bob leaves the circle - // - ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); - CFReleaseNull(error); - - //Alice should kick Bob out of the backup! - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Bob left the circle, Alice is not in the backup"); - - ok(SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is last backup peer"); - CFReleaseNull(error); - ok(!SOSAccountIsLastBackupPeer(bob_account, &error), "Bob is not last backup peer"); - CFReleaseNull(error); - - ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); - - SOSAccountTrustClassic *bobTrust = bob_account.trust; - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); - - //Bob gets back into the circle - ok(SOSAccountJoinCircles_wTxn(bob_account, &error)); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - - //enables view - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is the not the last backup peer - Bob still registers as one"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); - CFReleaseNull(error); - - // - //removing backup key for bob account - // - - ok(SOSAccountRemoveBackupPublickey_wTxn(bob_account, &error), "Removing Bob's backup key (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); - - // - // Setting new backup public key for Bob - // - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); - CFReleaseNull(error); - - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); - - //bob is in his own backup - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); - //alice does not have bob in her backup - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key should be in the backup"); - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Alice is in the backup"); - ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); - ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); - ok(SOSAccountIsBackupRingEmpty(alice_account, kTestView1), "Alice should not be in the backup"); - - - CFReleaseNull(cfpassword); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -#endif - -} - -int secd_62_account_backup(int argc, char *const *argv) -{ -#if !TARGET_OS_SIMULATOR - plan_tests(95); -#else - plan_tests(1); -#endif - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - secd_test_setup_testviews(); // for running this test solo - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m b/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m deleted file mode 100644 index c1ccc9ea..00000000 --- a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -typedef void (^stir_block)(int expected_iterations); -typedef int (^execute_block)(void); - -static void stirBetween(stir_block stir, ...) { - va_list va; - va_start(va, stir); - - execute_block execute = NULL; - - while ((execute = va_arg(va, execute_block)) != NULL) - stir(execute()); -} - -static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) -{ - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - - SKIP: { - skip("Empty applicant array", 2, applicants); - - is(CFArrayGetCount(applicants), expected, "Applicants: %@ (%@)", applicants, error); - CFReleaseNull(error); - - ok(SOSAccountAcceptApplicants(account , applicants, &error), "Accepting all (%@)", error); - CFReleaseNull(error); - } - - CFReleaseNull(applicants); -} - - -static void tests(void) -{ - __block CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - const CFStringRef data_source_name = CFSTR("TestSource"); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); - - SOSAccount* alice_resurrected = NULL; - - __block CFDataRef frozen_alice = NULL; - - - stirBetween(^(int expected){ - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), expected, "stirring"); - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "bob credential setting (%@)", error); - - return 1; - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "alice credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "carole credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - return 2; - }, ^{ - ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - return 2; - }, ^{ - VerifyCountAndAcceptAllApplicants(alice_account, 1); - - return 3; - }, ^{ - accounts_agree("bob&alice pair", bob_account, alice_account); - is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - return 1; - }, ^{ - - NSError *ns_error = nil; - frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); - ok(frozen_alice, "Copy encoded %@", ns_error); - ns_error = nil; - - SOSAccountPurgePrivateCredential(alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - return 2; - }, ^{ - - accounts_agree("Alice bails", bob_account, alice_account); - - { - CFArrayRef concurring = SOSAccountCopyConcurringPeers(alice_account, &error); - - ok(concurring && CFArrayGetCount(concurring) == 2, "See two concurring %@ (%@)", concurring, error); - CFReleaseNull(error); - CFReleaseNull(concurring); - } - - return 1; - }, - NULL); - - alice_resurrected = CreateAccountForLocalChangesFromData(frozen_alice, CFSTR("Alice risen"), data_source_name); - // This is necessary from the change that makes accounts not inflate if the private key was lost - alice_resurected now - // Starts as a brand new account, so this whole series of tests needs to amount to "is this brand new"? - // The trigger is alice leaving the circle - that kills the deviceKey. - ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL); - - stirBetween(^(int expected){ - is(ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL), expected, "stirring"); - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_resurrected, cfaccount, cfpassword, &error), "alice_resurrected credential setting (%@)", error); - CFReleaseNull(error); - return 1; - }, ^{ - ok(![alice_resurrected isInCircle:&error], "Ressurrected not in circle: %@", error); - CFReleaseNull(error); - - ok(SOSAccountJoinCircles_wTxn(alice_resurrected, &error), "Risen-alice Applies (%@)", error); - CFReleaseNull(error); - return 2; - }, ^{ - VerifyCountAndAcceptAllApplicants(bob_account, 1); - return 3; - }, - NULL); - - CFReleaseNull(frozen_alice); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_63_account_resurrection(int argc, char *const *argv) -{ - plan_tests(73); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-64-circlereset.m b/OSX/sec/securityd/Regressions/secd-64-circlereset.m deleted file mode 100644 index 74f8cf9a..00000000 --- a/OSX/sec/securityd/Regressions/secd-64-circlereset.m +++ /dev/null @@ -1,144 +0,0 @@ -// -// secd-64-circlereset.c -// sec -// -// Created by Richard Murphy on 7/22/15. -// -// - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int64_t getCurrentGenCount(SOSAccount* account) { - SOSAccountTrustClassic* trust = account.trust; - return SOSCircleGetGenerationSint(trust.trustedCircle); -} - -static bool SOSAccountResetWithGenCountValue(SOSAccount* account, int64_t gcount, CFErrorRef* error) { - if (!SOSAccountHasPublicKey(account, error)) - return false; - __block bool result = true; - SOSAccountTrustClassic* trust = account.trust; - - result &= [account.trust resetAllRings:account err:error]; - - trust.fullPeerInfo = nil; - [trust setDepartureCode:kSOSWithdrewMembership]; - - result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { - SOSGenCountRef gencount = SOSGenerationCreateWithValue(gcount); - result = SOSCircleResetToEmpty(circle, error); - SOSCircleSetGeneration(circle, gencount); - CFReleaseNull(gencount); - return result; - }]; - - if (!result) { - secerror("error: %@", error ? *error : NULL); - } - - return result; -} - -static SOSCircleRef SOSCircleCreateWithGenCount(int64_t gcount) { - SOSCircleRef c = SOSCircleCreate(kCFAllocatorDefault, CFSTR("a"), NULL); - SOSGenCountRef gencount = SOSGenerationCreateWithValue(gcount); - SOSCircleSetGeneration(c, gencount); - CFReleaseNull(gencount); - return c; -} - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - SOSCircleRef c1 = SOSCircleCreateWithGenCount(1); - SOSCircleRef c99 = SOSCircleCreateWithGenCount(99); - ok(SOSCircleIsOlderGeneration(c1, c99), "Is Comparison working correctly?", NULL); - CFReleaseNull(c1); - CFReleaseNull(c99); - - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - - // Setup Circle with Bob and Alice in it - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - accounts_agree("bob&alice pair", bob_account, alice_account); - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - uint64_t cnt = getCurrentGenCount(alice_account); - - ok(SOSAccountResetWithGenCountValue(alice_account, cnt-1, &error), "Alice resets the circle to empty with old value"); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - is([bob_account getCircleStatus:&error], 0, "Bob Survives bad circle post"); - is([alice_account getCircleStatus:&error], 1, "Alice does not survive bad circle post"); - - CFReleaseNull(cfpassword); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_64_circlereset(int argc, char *const *argv) -{ - plan_tests(35); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m b/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m deleted file mode 100644 index 520cb8cd..00000000 --- a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -typedef void (^stir_block)(int expected_iterations); -typedef int (^execute_block)(void); - -static void stirBetween(stir_block stir, ...) { - va_list va; - va_start(va, stir); - - execute_block execute = NULL; - - while ((execute = va_arg(va, execute_block)) != NULL) - stir(execute()); -} - -__unused static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) -{ - CFErrorRef error = NULL; - CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); - - SKIP: { - skip("Empty applicant array", 2, applicants); - - is(CFArrayGetCount(applicants), expected, "Applicants: %@ (%@)", applicants, error); - CFReleaseNull(error); - - ok(SOSAccountAcceptApplicants(account , applicants, &error), "Accepting all (%@)", error); - CFReleaseNull(error); - } - - CFReleaseNull(applicants); -} - - -static void tests(void) -{ - __block CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - const CFStringRef data_source_name = CFSTR("TestSource"); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); - - SOSAccount* alice_resurrected = NULL; - - __block CFDataRef frozen_alice = NULL; - - - stirBetween(^(int expected){ - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), expected, "stirring"); - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "bob credential setting (%@)", error); - - return 1; - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "alice credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "carole credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - return 2; - }, ^{ - NSError *ns_error = nil; - frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); - ok(frozen_alice, "Copy encoded %@", ns_error); - ns_error = nil; - - SOSAccountPurgePrivateCredential(alice_account); - - ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - - return 2; - }, ^{ - ok(SOSAccountResetToOffering_wTxn(bob_account , &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - return 2; - }, - NULL); - - alice_resurrected = CreateAccountForLocalChangesFromData(frozen_alice, CFSTR("Alice risen"), data_source_name); - // This is necessary from the change that makes accounts not inflate if the private key was lost - alice_resurected now - // Starts as a brand new account, so this whole series of tests needs to amount to "is this brand new"? - // The trigger is alice leaving the circle - that kills the deviceKey. - ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL); - - stirBetween(^(int expected){ - is(ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL), expected, "stirring"); - }, ^{ - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_resurrected, cfaccount, cfpassword, &error), "alice_resurrected credential setting (%@)", error); - CFReleaseNull(error); - return 1; - }, ^{ - ok(![alice_resurrected isInCircle:&error], "Ressurrected not in circle: %@", error); - CFReleaseNull(error); - - ok([bob_account isInCircle:&error], "Should be in circle: %@", error); - CFReleaseNull(error); - - return 1; - }, - NULL); - - CFReleaseNull(frozen_alice); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_65_account_retirement_reset(int argc, char *const *argv) -{ - plan_tests(28); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-66-account-recovery.m b/OSX/sec/securityd/Regressions/secd-66-account-recovery.m deleted file mode 100644 index e8df91f4..00000000 --- a/OSX/sec/securityd/Regressions/secd-66-account-recovery.m +++ /dev/null @@ -1,375 +0,0 @@ -// -// secd-66-account-recovery.c -// Security -// -// Created by Richard Murphy on 10/5/16. -// -// - -#include - -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include - -#include -#include "SecdTestKeychainUtilities.h" - -#if TARGET_OS_SIMULATOR - -int secd_66_account_recovery(int argc, char *const *argv) { - plan_tests(1); - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - return 0; -} - -#else - -#include "SOSAccountTesting.h" - -static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) -{ - __block CFDataRef result = NULL; - CFStringPerformWithUTF8CFData(string, ^(CFDataRef stringAsData) { - result = SOSCopyDeviceBackupPublicKey(stringAsData, error); - }); - return result; -} - - -static inline bool SOSAccountSetRecoveryKey_wTxn(SOSAccount* acct, CFDataRef recoveryPub, CFErrorRef* error) { - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountSetRecoveryKey(txn.account, recoveryPub, error); - }]; - return result; -} - -static inline bool SOSAccountSOSAccountRemoveRecoveryKey_wTxn(SOSAccount* acct, CFErrorRef* error) { - __block bool result = false; - [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountRemoveRecoveryKey(txn.account, error); - }]; - return result; -} - -// 6 test cases -static void registerRecoveryKeyNow(CFMutableDictionaryRef changes, SOSAccount* registrar, SOSAccount* observer, CFDataRef recoveryPub, bool recKeyFirst) { - CFErrorRef error = NULL; - - is(ProcessChangesUntilNoChange(changes, registrar, observer, NULL), 1, "updates"); - - if(recoveryPub) { - ok(SOSAccountSetRecoveryKey_wTxn(registrar, recoveryPub, &error), "Set Recovery Key"); - CFReleaseNull(error); - } else { - ok(SOSAccountSOSAccountRemoveRecoveryKey_wTxn(registrar, &error), "Clear Recovery Key"); - CFReleaseNull(error); - } - ok(error == NULL, "Error shouldn't be %@", error); - CFReleaseNull(error); - ProcessChangesUntilNoChange(changes, registrar, observer, NULL); - - CFDataRef registrar_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, registrar, &error); - CFReleaseNull(error); - CFDataRef observer_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, observer, &error); - CFReleaseNull(error); - - if(recoveryPub) { - ok(registrar_recKey, "Registrar retrieved recKey"); - ok(observer_recKey, "Observer retrieved recKey"); - ok(CFEqualSafe(registrar_recKey, observer_recKey), "recKeys are the same"); - ok(CFEqualSafe(registrar_recKey, recoveryPub), "recKeys are as expected"); - } else { - ok((!registrar_recKey && !observer_recKey), "recKeys are NULL"); - } - CFReleaseNull(observer_recKey); - CFReleaseNull(registrar_recKey); -} - -static void tests(bool recKeyFirst) -{ - __block CFErrorRef error = NULL; - CFStringRef sock_drawer_key = CFSTR("AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW"); - SecRecoveryKey *sRecKey = NULL; - CFDataRef fullKeyBytes = NULL; - CFDataRef pubKeyBytes = NULL; - - sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString*)sock_drawer_key, NULL); - ok(sRecKey, "Create SecRecoveryKey from String"); - if(sRecKey) { - fullKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupFullKey(sRecKey)); - pubKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupPublicKey(sRecKey)); - ok(fullKeyBytes && pubKeyBytes, "Got KeyPair from SecRecoveryKey"); - } - if(!(fullKeyBytes && pubKeyBytes)) { - diag("Cannot Proceed - couldn't make usable recoveryKey from sock-drawer-key"); - CFReleaseNull(fullKeyBytes); - CFReleaseNull(pubKeyBytes); - return; - } - - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef cfdsid = CFSTR("DSIDFooFoo"); - - secd_test_setup_testviews(); // for running this test solo - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountAssertDSID(alice_account, cfdsid); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountAssertDSID(bob_account, cfdsid); - - CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); - CFDataRef bob_backup_key = CopyBackupKeyForString(CFSTR("Bob Backup Entropy"), &error); - - // Start Circle - ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - if(recKeyFirst) registerRecoveryKeyNow(changes, alice_account, bob_account, pubKeyBytes, recKeyFirst); - - - is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); - - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok([bob_account.trust checkForRings:&error], "Bob_account is good"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); - CFReleaseNull(error); - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); - CFReleaseNull(error); - - ok([bob_account.trust checkForRings:&error], "Bob_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup before sync?"); - - if(!recKeyFirst) { - SOSBackupSliceKeyBagRef bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); - CFReleaseNull(error); - ok(!SOSBSKBHasRecoveryKey(bskb), "BSKB should not have recovery key"); - CFReleaseNull(bskb); - } - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); - - ok([bob_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - - - ok([alice_account.trust checkForRings:&error], "Alice_account is good"); - CFReleaseNull(error); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup after sync?"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "IS bob in the backup after sync"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); - CFReleaseNull(error); - - // - //Bob leaves the circle - // - ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); - CFReleaseNull(error); - - //Alice should kick Bob out of the backup! - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Bob left the circle, Alice is in the backup"); - - ok(SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is last backup peer"); - CFReleaseNull(error); - ok(!SOSAccountIsLastBackupPeer(bob_account, &error), "Bob is not last backup peer"); - CFReleaseNull(error); - - //ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); - SOSAccountTrustClassic* bobTrust = bob_account.trust; - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); - - //Bob gets back into the circle - ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Re-Joins"); - - //enables view - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - CFReleaseNull(error); - - ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is the not the last backup peer - Bob still registers as one"); - CFReleaseNull(error); - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); - CFReleaseNull(error); - - // - //removing backup key for bob account - // - - ok(SOSAccountRemoveBackupPublickey_wTxn(bob_account, &error), "Removing Bob's backup key (%@)", error); - int nchanges = (recKeyFirst) ? 2: 2; - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), nchanges, "updates"); - - ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); - - // - // Setting new backup public key for Bob - // - - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); - CFReleaseNull(error); - - is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); - ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); - - //bob is in his own backup - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); - //alice does not have bob in her backup - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); - - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key should be in the backup"); - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Alice is in the backup"); - - if(!recKeyFirst) registerRecoveryKeyNow(changes, alice_account, bob_account, pubKeyBytes, recKeyFirst); - - ok(SOSAccountRecoveryKeyIsInBackupAndCurrentInView(alice_account, kTestView1), "Recovery Key is also in the backup"); - ok(SOSAccountRecoveryKeyIsInBackupAndCurrentInView(bob_account, kTestView1), "Recovery Key is also in the backup"); - - SOSBackupSliceKeyBagRef bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); - CFReleaseNull(error); - - ok(SOSBSKBHasRecoveryKey(bskb), "BSKB should have recovery key"); - - CFDataRef wrappingKey = CFStringCreateExternalRepresentation(kCFAllocatorDefault, sock_drawer_key, kCFStringEncodingUTF8, 0); - ok(wrappingKey, "Made wrapping key from with sock drawer key"); - bskb_keybag_handle_t bskbHandle = SOSBSKBLoadAndUnlockWithWrappingSecret(bskb, wrappingKey, &error); - ok(bskbHandle, "Made bskbHandle with recover key"); - ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); - - // Testing reset (Null) recoveryKey ========= - - CFReleaseNull(bskb); - CFReleaseNull(wrappingKey); - - registerRecoveryKeyNow(changes, alice_account, bob_account, NULL, recKeyFirst); - - ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(alice_account, kTestView1), "Recovery Key is not in the backup"); - ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(bob_account, kTestView1), "Recovery Key is not in the backup"); - - bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); - CFReleaseNull(error); - - ok(!SOSBSKBHasRecoveryKey(bskb), "BSKB should not have recovery key"); - - //========= - - - ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); - ok(SOSAccountIsBackupRingEmpty(alice_account, kTestView1), "Alice should not be in the backup"); - - CFReleaseNull(fullKeyBytes); - CFReleaseNull(pubKeyBytes); - CFReleaseNull(bskb); - - CFReleaseNull(cfpassword); - CFReleaseNull(wrappingKey); - bob_account = nil; - alice_account = nil; - - SOSTestCleanup(); -} - -int secd_66_account_recovery(int argc, char *const *argv) { - plan_tests(278); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(true); - tests(false); - - return 0; -} - -#endif diff --git a/OSX/sec/securityd/Regressions/secd-668-ghosts.m b/OSX/sec/securityd/Regressions/secd-668-ghosts.m deleted file mode 100644 index 957c30ae..00000000 --- a/OSX/sec/securityd/Regressions/secd-668-ghosts.m +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// -// secd-668-ghosts.c -// sec -// - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" - -#include "secd_regressions.h" -#include "SOSAccountTesting.h" -#include "SecdTestKeychainUtilities.h" - -/* - Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab") - have alice leave the circle - release bob, make a new bob - iOS and same serial number - try to join the circle - it should resetToOffering with ghost fix - - For phase 1 we expect the ghostfix to work with iOS devices, but not with MacOSX devices. - */ - -#if 0 -static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef ghostSerialID = CFSTR("abababababab"); - CFStringRef ghostIdsID = CFSTR("targetIDS"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass, ghostSerialID, ghostIdsID); - - // Start Circle - ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); - - // Alice Leaves - ok( [alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - accounts_agree("Alice bails", bob_account, alice_account); - is(countPeers(bob_account), 1, "There should only be 1 valid peer"); - // We're dropping all peers that are in the circle - leaving a circle with only one peer - and that's a ghost - - // Make new bob - same as the old bob except peerID - - SOSAccount* bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); - is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 1, "updates"); - - ok(SOSTestJoinWith(cfpassword, cfaccount, changes, bobFinal), "Application Made"); - CFReleaseNull(cfpassword); - - // Did ghostbuster work? - is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 2, "updates"); - if(expectGhostBusted) { // ghostbusting is currently disabled for MacOSX Peers - ok([bobFinal isInCircle:NULL], "Bob is in"); - } else { - ok(![bobFinal isInCircle:NULL], "Bob is not in"); - } - - is(countPeers(bobFinal), 1, "There should only be 1 valid peer"); - - CFReleaseNull(changes); - - bob_account = nil; - alice_account = nil; - bobFinal = nil; - SOSTestCleanup(); -} - -static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bool delayedPrivKey, bool pairJoin) { - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef ghostSerialID = CFSTR("abababababab"); - CFStringRef ghostIdsID = CFSTR("targetIDS"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - - // Start Circle - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - - SOSTestMakeGhostInCircle(CFSTR("Bob1"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 2); - SOSTestMakeGhostInCircle(CFSTR("Bob2"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 3); - SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 4); - SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 5); - - SOSAccount* bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); - - if(pairJoin) { - SOSTestJoinThroughPiggyBack(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 6, true); - is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle"); - } else if(delayedPrivKey) { - SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, DROP_USERKEY, 6, true); - is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle"); - } else { - SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 2, true); - } - - if(pairJoin || delayedPrivKey) { // this allows the ghostbusting to be done in a delayed fashion for the instances where that is proper - SOSAccountTryUserCredentials(bobFinal_account, cfaccount, cfpassword, &error); - ok(SOSTestChangeAccountDeviceName(bobFinal_account, CFSTR("ThereCanBeOnlyOneBob")), "force an unrelated circle change"); - is(ProcessChangesUntilNoChange(changes, alice_account, bobFinal_account, NULL), 3, "updates"); - } - - CFReleaseNull(cfpassword); - - - ok([bobFinal_account isInCircle:NULL], "bobFinal_account is in"); - - is(countPeers(bobFinal_account), 2, "Expect ghostBobs to be gone"); - is(countPeers(alice_account), 2, "Expect ghostBobs to be gone"); - accounts_agree_internal("Alice and ThereCanBeOnlyOneBob are the only circle peers and they agree", alice_account, bobFinal_account, false); - - CFReleaseNull(changes); - - alice_account = nil; - bobFinal_account = nil; - - SOSTestCleanup(); -} - -static void iosICloudIdentity() { - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef ghostIdsID = CFSTR("targetIDS"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - - // Start Circle - ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); - - SOSCircleRef circle = [alice_account.trust getCircle:NULL]; - __block CFStringRef serial = NULL; - SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { - if(SOSPeerInfoIsCloudIdentity(peer)) { - serial = SOSPeerInfoCopySerialNumber(peer); - } - }); - - SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS, serial, ghostIdsID); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); - CFReleaseNull(cfpassword); - - circle = [alice_account.trust getCircle:&error]; - __block bool hasiCloudIdentity = false; - SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { - if(SOSPeerInfoIsCloudIdentity(peer)) { - hasiCloudIdentity = true; - } - }); - - ok(hasiCloudIdentity, "GhostBusting didn't mess with the iCloud Identity"); - - CFReleaseNull(changes); - alice_account = nil; - SOSTestCleanup(); -} -#endif // 0 - -int secd_68_ghosts(int argc, char *const *argv) -{ - plan_tests(1); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - -#if 0 - // changing ghostbusting. handleUpdateCircle version is going away. - hauntedCircle(SOSPeerInfo_iOS, true); - hauntedCircle(SOSPeerInfo_macOS, false); - multiBob(SOSPeerInfo_iOS, true, false, false); - multiBob(SOSPeerInfo_iOS, false, true, false); - multiBob(SOSPeerInfo_iOS, false, false, true); // piggyback join case - - iosICloudIdentity(); -#endif - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m b/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m deleted file mode 100644 index 93809dfd..00000000 --- a/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m +++ /dev/null @@ -1,129 +0,0 @@ -// -// secd-67-prefixedKeyIDs.c -// Security -// -// Created by Richard Murphy on 11/1/16. -// -// - -#include -// -// secd-66-account-recovery.c -// Security -// -// Created by Richard Murphy on 10/5/16. -// -// - -#include - -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - - -#include -#include -#include "SOSKeyedPubKeyIdentifier.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" - -#include -#include - - - -#include "SOSAccountTesting.h" -static void tests() { - CFErrorRef error = NULL; - int keySizeInBits = 256; - CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberIntType, &keySizeInBits); - - CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecAttrKeyType, kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits, kzib, - NULL); - CFReleaseNull(kzib); - - - SecKeyRef key = SecKeyCreateRandomKey(keyattributes, &error); - CFReleaseNull(keyattributes); - SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(key); - CFDataRef pubKeyData = NULL; - SecKeyCopyPublicBytes(pubKey, &pubKeyData); - CFStringRef properPref = CFSTR("RK"); - CFStringRef shortPref = CFSTR("R"); - CFStringRef longPref = CFSTR("RKR"); - - ok(key, "Made private key"); - ok(pubKey, "Made public key"); - ok(pubKeyData, "Made public key data"); - - CFStringRef pkidseckey = SOSKeyedPubKeyIdentifierCreateWithSecKey(properPref, pubKey); - ok(pkidseckey, "made string"); - CFStringRef pkidseckeyshort = SOSKeyedPubKeyIdentifierCreateWithSecKey(shortPref, pubKey); - ok(!pkidseckeyshort, "didn't make string"); - CFStringRef pkidseckeylong = SOSKeyedPubKeyIdentifierCreateWithSecKey(longPref, pubKey); - ok(!pkidseckeylong, "didn't make string"); - - ok(SOSKeyedPubKeyIdentifierIsPrefixed(pkidseckey), "properly prefixed string was made"); - CFStringRef retPref = SOSKeyedPubKeyIdentifierCopyPrefix(pkidseckey); - ok(retPref, "got prefix"); - ok(CFEqualSafe(retPref, properPref), "prefix matches"); - CFReleaseNull(retPref); - CFStringRef retHpub = SOSKeyedPubKeyIdentifierCopyHpub(pkidseckey); - ok(retHpub, "got hash of pubkey"); - - - CFStringRef pkiddata = SOSKeyedPubKeyIdentifierCreateWithData(properPref, pubKeyData); - ok(pkiddata, "made string"); - ok(CFEqualSafe(pkiddata, pkidseckey), "strings match"); - - //diag("pkiddata %@", pkiddata); - //diag("retPref %@", retPref); - CFReleaseNull(retHpub); - CFReleaseNull(key); - CFReleaseNull(pubKey); - CFReleaseNull(pubKeyData); - CFReleaseNull(pkidseckey); - CFReleaseNull(pkidseckeyshort); - CFReleaseNull(pkidseckeylong); - CFReleaseNull(pkiddata); - - -} - -int secd_67_prefixedKeyIDs(int argc, char *const *argv) { - plan_tests(12); - - tests(); - return 0; -} - diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m b/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m deleted file mode 100644 index cf7fba71..00000000 --- a/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// Test syncing between SecItemDataSource and SOSTestDataSource - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -#include "keychain/SecureObjectSync/SOSDigestVector.h" -#include "keychain/SecureObjectSync/SOSEngine.h" -#include "keychain/SecureObjectSync/SOSPeer.h" -#import "keychain/SecureObjectSync/SOSChangeTracker.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int kTestTestCount = 121; - -static void nosha1(void) { - __block int iteration = 0; - __block CFErrorRef error = NULL; - SOSTestDeviceListTestSync("nosha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 10 items in first 10 sync messages - if (iteration <= 6) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - SOSTestDeviceAddGenericItem(source, account, CFSTR("nosha1")); - CFReleaseSafe(account); - // Corrupt the 4th item added - if (iteration == 4) { - ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { - ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { - ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error), - "Corrupting rowid 5 by zeroing sha1: %@", error); - CFReleaseNull(error); - }), "SecDbTransaction: %@", error); - CFReleaseNull(error); - }), "SecDbPerformWrite: %@", error); - CFReleaseNull(error); - return true; - } - return true; - } - - - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("Bad"), CFSTR("Good"), NULL); -} - -static void drop_item(void) { - __block int iteration = 0; - __block CFErrorRef error = NULL; - SOSTestDeviceListTestSync("drop_item", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 10 items in first 10 sync messages - if (iteration <= 6) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_item")); - CFReleaseSafe(account); - // Corrupt the 4th item added - if (iteration == 4) { - ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { - ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { - ok(SecDbExec(dbconn, CFSTR("DELETE FROM genp WHERE rowid=5;"), &error), - "Corrupting rowid 5 by deleting object: %@", error); - CFReleaseNull(error); - }), "SecDbTransaction: %@", error); - CFReleaseNull(error); - }), "SecDbPerformWrite: %@", error); - CFReleaseNull(error); - return true; - } - return true; - } - - - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("Abegail"), CFSTR("Billy"), NULL); -} - -static void drop_manifest(void) { - __block int iteration = 0; - SOSTestDeviceListTestSync("drop_manifest", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 5 items on Alice and 4 on Bob in first 9 sync messages - if (iteration <= 9) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration / 2); - SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_manifest")); - CFReleaseSafe(account); - // Corrupt the manifest after 4th item added - if (iteration == 4) { - SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); - SOSPeerRef peer = SOSEngineCopyPeerWithID(engine, SOSTestDeviceGetID(dest), NULL); - SOSManifestRef mf = SOSEngineCopyLocalPeerManifest(engine, peer, NULL); - CFReleaseNull(peer); - CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - SOSManifestForEach(mf, ^(CFDataRef e, bool *stop) { - SOSChangesAppendDelete(changes, e); - }); - ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "droped manifest from %@", source); - CFReleaseNull(changes); - CFReleaseNull(mf); - return true; - } - return true; - } - - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("Ann"), CFSTR("Ben"), NULL); -} - -static void add_sha1(void) { - TODO: { - //todo("this never stops syncing"); - __block int iteration = 0; - __block CFErrorRef error = NULL; - SOSTestDeviceListTestSync("add_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 9 items in first 9 sync messages - if (iteration <= 9) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - SOSTestDeviceAddGenericItem(source, account, CFSTR("add_sha1")); - CFReleaseSafe(account); - // Corrupt the manifest after 4th item added - if (iteration == 4) { - ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { - ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { - ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error), - "Corrupting rowid 5 by zeroing sha1: %@", error); - CFReleaseNull(error); - }), "SecDbTransaction: %@", error); - CFReleaseNull(error); - }), "SecDbPerformWrite: %@", error); - CFReleaseNull(error); - - SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); - uint8_t zeroDigest[20] = {}; - CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20); - CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - SOSChangesAppendAdd(changes, zDigest); - ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest"); - CFReleaseSafe(zDigest); - CFReleaseNull(changes); - return true; - } - return true; - } - - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("Andy"), CFSTR("Bill"), NULL); - } -} - -static void change_sha1(void) { -TODO: { - //todo("this never stops syncing"); - __block int iteration = 0; - __block CFErrorRef error = NULL; - SOSTestDeviceListTestSync("change_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 9 items in first 9 sync messages - if (iteration <= 9) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - CFStringRef server = CFSTR("change_sha1"); - // Corrupt the manifest after 4th item added - if (!SOSDataSourceWithAPI(source->ds, true, &error, ^(SOSTransactionRef txn, bool *commit) { - SOSObjectRef object = SOSDataSourceCreateGenericItem(source->ds, account, server); - ok(SOSDataSourceMergeObject(source->ds, txn, object, NULL, &error), "%@ added API object %@", SOSTestDeviceGetID(source), error ? (CFTypeRef)error : (CFTypeRef)CFSTR("ok")); - if (iteration == 3) { - sqlite_int64 rowid = SecDbItemGetRowId((SecDbItemRef)object, NULL); - CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=%lld;"), rowid); - ok(SecDbExec((SecDbConnectionRef)txn, sql, &error), - "Corrupting rowid %lld by zeroing sha1: %@", rowid, error); - CFReleaseNull(sql); - SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); - CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - uint8_t zeroDigest[20] = {}; - CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20); - SOSChangesAppendAdd(changes, zDigest); - CFDataRef digest = SOSObjectCopyDigest(source->ds, object, NULL); - SOSChangesAppendDelete(changes, digest); - const uint8_t *d = CFDataGetBytePtr(digest); - ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest %lld %02X%02x%02x%02x", - rowid, d[0], d[1], d[2], d[3]); - CFReleaseSafe(zDigest); - CFReleaseSafe(digest); - CFReleaseNull(changes); - } - CFReleaseSafe(object); - CFReleaseNull(error); - })) - fail("ds transaction %@", error); - CFReleaseNull(error); - CFReleaseNull(account); - return true; - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - if (iteration >= 3) - pass("%@", source); - return false; - }, CFSTR("Alice"), CFSTR("Bob"), NULL); -} -} - -int secd_70_engine_corrupt(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - __security_simulatecrash_enable(false); - - /* custom keychain dir */ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - nosha1(); - drop_item(); - drop_manifest(); - add_sha1(); - change_sha1(); - - __security_simulatecrash_enable(true); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-smash.m b/OSX/sec/securityd/Regressions/secd-70-engine-smash.m deleted file mode 100644 index 62be20d5..00000000 --- a/OSX/sec/securityd/Regressions/secd-70-engine-smash.m +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 581; - -// Smash together identical items, but mute the devices every once in a while. -// (Simulating packet loss.) -static void smash(void) { - __block int iteration=0; - SOSTestDeviceListTestSync("smash", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - if (iteration < 100 && iteration % 10 == 0) { - SOSTestDeviceSetMute(source, !SOSTestDeviceIsMute(source)); - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - if (iteration++ < 200) { - CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("smash-post-%d"), iteration); - SOSTestDeviceAddGenericItem(source, name, name); - SOSTestDeviceAddGenericItem(dest, name, name); - CFReleaseNull(name); - return true; - } - return false; - }, CFSTR("alice"), CFSTR("bob"), NULL); -} - -int secd_70_engine_smash(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - /* custom keychain dir */ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - smash(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-70-engine.m b/OSX/sec/securityd/Regressions/secd-70-engine.m deleted file mode 100644 index eba7cb04..00000000 --- a/OSX/sec/securityd/Regressions/secd-70-engine.m +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// Test syncing between SecItemDataSource and SOSTestDataSource - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -#include "keychain/SecureObjectSync/SOSEngine.h" -#include "keychain/SecureObjectSync/SOSPeer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -__unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) { - - CFMutableArrayRef trustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFMutableArrayRef untrustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef peerID = NULL; - const uint8_t expected[20] = { 0xea, 0x6c, 0x01, 0x4d, - 0xc7, 0x2d, 0x6f, 0x8c, - 0xcd, 0x1e, 0xd9, 0x2a, - 0xce, 0x1d, 0x41, 0xf0, - 0xd8, 0xde, 0x89, 0x57 }; - - const char resultSize = sizeof(expected); - - CFDataRef coder = CFDataCreate(kCFAllocatorDefault, expected, resultSize); - CFArrayForEachC(SOSEngineGetPeerIDs(engine), peerID){ - CFArrayAppendValue(trustedPeers, peerID); - }; - CFReleaseNull(coder); - - CFShow(trustedPeers); - // all trusted - SOSEngineCircleChanged(engine, myID,trustedPeers, untrustedPeers); - - // make first peer untrusted - peerID = (CFStringRef)CFArrayGetValueAtIndex(trustedPeers, 0); - CFArrayAppendValue(untrustedPeers, peerID); - CFArrayRemoveAllValue(trustedPeers, peerID); - //we should see peerState cleared out except for the coder! - SOSEngineCircleChanged(engine, myID, trustedPeers, untrustedPeers); - - CFArrayAppendValue(trustedPeers, peerID); - CFArrayRemoveAllValue(untrustedPeers, peerID); - - - return true; -} - -static void testsync3(const char *name, const char *test_directive, const char *test_reason) { - __block int iteration=0; - SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - if (iteration == 12 || iteration == 13) { - pass("pre-rcv %@", dest); - } - if (iteration == 19) { - pass("pre-send %@", source); - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - if (iteration == 10) { - pass("pre-add %@", source); - //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service")); - SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service")); - pass("post-add %@", source); - return true; // db changed - } else if (iteration == 12 || iteration == 15) { - pass("post-rcv %@", dest); - } - return false; - }, CFSTR("AAA"), CFSTR("BBB"), CFSTR("CCC"), NULL); -} - -static void testsync2(const char *name, const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), CFStringRef msg, ...) { - __block int iteration=0; - SOSTestDeviceListTestSync(name, test_directive, test_reason, kSOSPeerVersion, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - if (iteration == 96) { - pass("%@ before message", source); - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - iteration++; - if (iteration == 60) { - pass("%@ before addition", source); - //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service")); - SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service")); - pass("%@ after addition", source); - return true; - } - return false; - }, CFSTR("alice"), CFSTR("bob"), CFSTR("claire"), CFSTR("dave"),CFSTR("edward"), CFSTR("frank"), CFSTR("gary"), NULL); -} - -static void testsync(const char *name, const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), ...) { - __block int msg_index = 0; - __block int last_msg_index = 0; - va_list args; - va_start(args, bobInit); - CFArrayRef messages = CFArrayCreateForVC(kCFAllocatorDefault, &kCFTypeArrayCallBacks, args); - SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false, - ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - if (msg_index == 0) { - aliceInit(source->ds); - bobInit(dest->ds); - return true; - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - CFStringRef hexMsg = msg_index < CFArrayGetCount(messages) ? (CFStringRef)CFArrayGetValueAtIndex(messages, msg_index) : 0; - /* We are expecting a message and msg is it's digest. */ - if (message) { - msg_index++; - CFStringRef messageDigestStr = SOSMessageCopyDigestHex(message); - if (hexMsg) { - if (CFEqual(messageDigestStr, hexMsg)) { - pass("%s %@ handled message [%d] %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, message); - } else { - TODO: { - todo("manifest caching changed"); - fail("%s %@ received message [%d] digest %@ != %@ %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, messageDigestStr, hexMsg, message); - } - } - last_msg_index = msg_index; - } else { - TODO: { - todo("manifest caching changed"); - fail("%s %@ sent extra message [%d] with digest %@: %@", name, SOSEngineGetMyID(source->ds->engine), msg_index, messageDigestStr, message); - } - } - CFReleaseSafe(messageDigestStr); - //SOSCircleHandleCircleWithLock(source->ds->engine, SOSEngineGetMyID(source->ds->engine), CFDataCreate(kCFAllocatorDefault, 0, 0), NULL); - - } - return false; - }, CFSTR("alice"), CFSTR("bob"), NULL); - - if (msg_index < CFArrayGetCount(messages)) { - TODO: { - todo("manifest caching changed"); - fail("%s nothing sent expecting message [%d] digest %@", name, msg_index, CFArrayGetValueAtIndex(messages, msg_index)); - } - } else if (last_msg_index < msg_index) { - TODO: { - todo("manifest caching changed"); - fail("%s exchanged %d messages not in expected list", name, msg_index - last_msg_index); - } - } - - -} - -#if 0 -// Test syncing an empty circle with 1 to 10 devices and both version 0 and version 2 protocols -static void testsyncempty(void) { - CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - for (int deviceIX=0; deviceIX < 10; ++deviceIX) { - CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX); - CFArrayAppendValue(deviceIDs, deviceID); - CFReleaseSafe(deviceID); - if (deviceIX > 0) { - for (CFIndex version = 0; version < 3; version += 2) { - CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, NULL); - SOSTestDeviceListSync("syncempty", test_directive, test_reason, testDevices, NULL, NULL); - SOSTestDeviceListInSync("syncempty", test_directive, test_reason, testDevices); - SOSTestDeviceDestroyEngine(testDevices); - CFReleaseSafe(testDevices); - } - } - } - CFReleaseSafe(deviceIDs); -} -#endif - -static CFIndex syncmany_add(int iteration) { - if (iteration % 7 < 3 && iteration < 10) - return iteration % 17 + 200; - return 0; -} - -static void testsyncmany(const char *name, const char *test_directive, const char *test_reason, int devFirst, int devCount, int version, CFIndex (*should_add)(int iteration)) { - CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - for (int deviceIX=0; deviceIX < devCount; ++deviceIX) { - CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX); - CFArrayAppendValue(deviceIDs, deviceID); - CFReleaseSafe(deviceID); - if (deviceIX >= devFirst) { - CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, NULL); - __block int iteration = 0; - SOSTestDeviceListSync(name, test_directive, test_reason, testDevices, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - bool didAdd = false; - iteration++; - // Add 10 items in first 10 sync messages - CFIndex toAdd = should_add(iteration); - if (toAdd) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - didAdd = SOSTestDeviceAddGenericItems(source, toAdd, account, CFSTR("testsyncmany")); - CFReleaseSafe(account); - } - if (iteration == 279 || iteration == 459) - pass("pre-send[%d] %@", iteration, source); - - return didAdd; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - if (iteration == 262) - pass("post-rcv[%d] %@", iteration, dest); - - if (iteration == 272 || iteration == 279) - pass("post-send[%d] %@", iteration, source); - - return false; - }); - SOSTestDeviceListInSync(name, test_directive, test_reason, testDevices); - SOSTestDeviceDestroyEngine(testDevices); - CFReleaseSafe(testDevices); - } - } - CFReleaseSafe(deviceIDs); -} - -static void testsync2p(void) { - __block int iteration = 0; - SOSTestDeviceListTestSync("testsync2p", test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - iteration++; - // Add 10 items in first 10 sync messages - if (iteration <= 10) { - CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); - SOSTestDeviceAddGenericItem(source, account, CFSTR("testsync2p")); - CFReleaseSafe(account); - return true; - } - return false; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("Atestsync2p"), CFSTR("Btestsync2p"), NULL); -} - -static void synctests(void) { -#if 0 - // TODO: Adding items gives us non predictable creation and mod dates so - // the message hashes can't be precomputed. - CFDictionaryRef item = CFDictionaryCreateForCFTypes - (0, - kSecClass, kSecClassGenericPassword, - kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, - kSecAttrSynchronizable, kCFBooleanTrue, - kSecAttrService, CFSTR("service"), - kSecAttrAccount, CFSTR("account"), - NULL); - SecItemAdd(item, NULL); - CFReleaseSafe(item); -#endif - -SKIP: - { - -#ifdef NO_SERVER - // Careful with this in !NO_SERVER, it'll destroy debug keychains. - WithPathInKeychainDirectory(CFSTR("keychain-2-debug.db"), ^(const char *keychain_path) { - unlink(keychain_path); - }); - - // Don't ever do this in !NO_SERVER, it'll destroy real keychains. - WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *keychain_path) { - unlink(keychain_path); - }); - - SecKeychainDbReset(NULL); -#else - skip("Keychain not reset", 0, false); -#endif - - testsync3("secd_70_engine3", test_directive, test_reason); - - // Sync between 2 empty dataSources - testsync("secd_70_engine", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) {}, - ^ (SOSDataSourceRef dataSource) {}, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - NULL); - - // Sync a dataSource with one object to an empty dataSource - testsync("secd_70_engine-alice1", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - }), "ds transaction failed %@", error); - CFReleaseSafe(object); - CFReleaseNull(error); - }, - ^ (SOSDataSourceRef dataSource) {}, - CFSTR("DDDB2DCEB7B36F0757F400251ECD11E377A0DCE8"), - CFSTR("B2777CC898AE381B3F375B27E4FD9757F6CE9948"), - CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"), - CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - //CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"), - //CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"), - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - NULL); - - // Sync a dataSource with one object to another dataSource with the same object - testsync("secd_70_engine-alice1bob1", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) { -#if 0 - CFErrorRef error = NULL; - // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... - CFDictionaryRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - CFReleaseNull(error); -#endif - }, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - }), "ds transaction failed %@", error); - CFReleaseSafe(object); - CFReleaseNull(error); - }, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"), - CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - NULL); - - // Sync a dataSource with one object to another dataSource with the same object - testsync("secd_70_engine-alice1bob2", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) { -#if 0 - CFErrorRef error = NULL; - // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... - SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - CFReleaseNull(error); -#endif - }, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - CFReleaseNull(error); - object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - }), "ds transaction failed %@", error); - CFReleaseNull(error); - }, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"), - CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), - - //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), - //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"), - //CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"), - //CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"), - //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), - NULL); - - // Sync a dataSource with a tombstone object to another dataSource with the same object - TODO: { - todo(" Test case in sd-70-engine fails due to need for RowID"); - testsync("secd_70_engine-update", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - const char *password = "password1"; - CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password)); - // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... - SOSObjectRef object_to_find = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), true, NULL); - SOSObjectRef object = SOSDataSourceCopyObject(dataSource, object_to_find, &error); - SOSObjectRef old_object = NULL; - SKIP: { - skip("no object", 1, ok(object, "Finding object %@, error: %@", object_to_find, error)); - CFReleaseNull(data); - // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... - old_object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ update object %@", SOSEngineGetMyID(dataSource->engine), error); - }), "ds transaction failed %@", error); - } - CFReleaseSafe(data); - CFReleaseSafe(old_object); - CFReleaseSafe(object); - CFReleaseNull(error); - }, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - CFReleaseNull(error); - object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - }), "ds transaction failed %@", error); - CFReleaseNull(error); - }, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"), - CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), - - //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"), - //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"), - //CFSTR("137FD34E9BF11B4BA0620E8EBFAB8576BCCCF294"), - //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"), - NULL); - } - - // Sync a dataSource with one object to another dataSource with the same object - testsync("secd_70_engine-foreign-add", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) { - }, - ^ (SOSDataSourceRef dataSource) { - __block CFErrorRef error = NULL; - const char *password = "password1"; - CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password)); - __block SOSObjectRef object = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), false, data); - CFReleaseSafe(data); - ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - CFReleaseNull(error); - object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); - ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); - CFReleaseSafe(object); - }), "ds transaction failed %@", error); - CFReleaseNull(error); - }, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("769F63675CEE9CB968BFD9CA48DB9079BFCAFB6C"), - CFSTR("818C24B9BC495940836B9C8F76517C838CEFFA98"), - - //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), - //CFSTR("607EEF976943FD781CFD2B3850E6DC7979AA61EF"), - //CFSTR("28434CD1B90CC205460557CAC03D7F12067F2329"), - //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), - NULL); - } - - // Sync between 2 empty dataSources - testsync2("secd_70_engine2", test_directive, test_reason, - ^ (SOSDataSourceRef dataSource) {}, - ^ (SOSDataSourceRef dataSource) {}, - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), - NULL); - - //testsyncempty(); - testsyncmany("syncmany", test_directive, test_reason, 9, 10, 0, syncmany_add); - testsyncmany("v2syncmany", test_directive, test_reason, 9, 10, 2, syncmany_add); - testsync2p(); -} - -int secd_70_engine(int argc, char *const *argv) -{ - plan_tests(1172); - - /* custom keychain dir */ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - synctests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-70-otr-remote.m b/OSX/sec/securityd/Regressions/secd-70-otr-remote.m deleted file mode 100644 index 88735ab4..00000000 --- a/OSX/sec/securityd/Regressions/secd-70-otr-remote.m +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include - -#include "secd_regressions.h" - -#include -#include -#include -#include -#include -#include - -#include -#include "keychain/SecureObjectSync/SOSCircle.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include "SOSCircle_regressions.h" -#include "SOSRegressionUtilities.h" -#include "SOSTestDataSource.h" -#include "SecOTRRemote.h" -#include "SOSAccount.h" -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - - -static void RegressionsLogError(CFErrorRef error) { - if (error == NULL) { - return; - } - CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error); - CFIndex errorCode = CFErrorGetCode(error); - CFStringRef errorDomain = CFErrorGetDomain(error); - CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey); - CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey); - if (previousError != NULL) { - RegressionsLogError(previousError); - } - char errorDomainStr[1024]; - char errorStringStr[1024]; - - CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8); - CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8); - printf("OTR: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr); - CFReleaseSafe(tempDictionary); -} - -static int kTestTestCount = 11; -static void tests(void) -{ - NSError* ns_testError = nil; - __block CFErrorRef testError = NULL; - - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - - CFStringRef circleName = CFSTR("Woot Circle"); - - /* DataSource */ - SOSDataSourceRef aliceDs = SOSTestDataSourceCreate(); - SOSDataSourceRef bobDs = SOSTestDataSourceCreate(); - - SOSDataSourceFactoryRef aliceDsf = SOSTestDataSourceFactoryCreate(); - SOSTestDataSourceFactorySetDataSource(aliceDsf, circleName, aliceDs); - - SOSDataSourceFactoryRef bobDsf = SOSTestDataSourceFactoryCreate(); - SOSTestDataSourceFactorySetDataSource(bobDsf, circleName, bobDs); - - CFDictionaryRef alice_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice Device")); - CFDictionaryRef bob_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Bob Device")); - - SOSAccount* alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf); - SOSAccount* bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf); - - SOSAccountAssertUserCredentialsAndUpdate(alice_account, CFSTR("alice"), cfpassword, &testError); - SOSAccountAssertUserCredentialsAndUpdate(bob_account, CFSTR("bob"), cfpassword, &testError); - - CFReleaseNull(cfpassword); - - SOSAccountJoinCircles_wTxn(alice_account, &testError); - SOSAccountJoinCircles_wTxn(bob_account, &testError); - - NSData* alice_account_data = [alice_account encodedData:&ns_testError]; - NSData* bob_account_data = [bob_account encodedData:&ns_testError];; - - CFArrayRef alice_peers = SOSAccountCopyPeers(alice_account, &testError); - CFArrayRef bob_peers = SOSAccountCopyPeers(bob_account, &testError); - - SOSPeerInfoRef alice_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(alice_peers, 0); - SOSPeerInfoRef bob_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(bob_peers, 0); - - CFStringRef alice_peer_id = SOSPeerInfoGetPeerID(alice_peer_info); - CFStringRef bob_peer_id = SOSPeerInfoGetPeerID(bob_peer_info); - - CFDataRef alice_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, alice_peer_id, kCFStringEncodingUTF8, '?'); - CFDataRef bob_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, bob_peer_id, kCFStringEncodingUTF8, '?'); - - bool aliceReady = false; - bool bobReady = false; - - CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) bob_account_data, bob_peer_external_form, (__bridge CFDataRef) alice_account_data, &testError); - RegressionsLogError(testError); - CFReleaseNull(testError); - - ok(aliceSideSession != NULL, "Make Alice side remote session"); - - CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) alice_account_data, alice_peer_external_form, (__bridge CFDataRef) bob_account_data, &testError); - RegressionsLogError(testError); - CFReleaseNull(testError); - - ok(bobSideSession != NULL, "Make Bob side remote session"); - - CFDataRef aliceSideSessionResult = NULL; - CFDataRef bobSideSessionResult = NULL; - CFDataRef aliceToBob = NULL; - CFDataRef bobToAlice = NULL; - - do { - bool aliceStatus = SecOTRSessionProcessPacketRemote(aliceSideSession, bobToAlice, &aliceSideSessionResult, &aliceToBob, &aliceReady, &testError); - ok (aliceStatus, "Alice sent packet OK"); - RegressionsLogError(testError); - CFReleaseNull(testError); - CFReleaseSafe(aliceSideSession); - aliceSideSession = aliceSideSessionResult; - - if (aliceReady) { - break; - } - - bool bobStatus = SecOTRSessionProcessPacketRemote(bobSideSession, aliceToBob, &bobSideSessionResult, &bobToAlice, &bobReady, &testError); - ok (bobStatus, "Bob sent packet OK"); - RegressionsLogError(testError); - CFReleaseNull(testError); - CFReleaseSafe(bobSideSession); - bobSideSession = bobSideSessionResult; - } while (1); - - ok(bobReady, "Bob finished negotiating at the same time as Alice."); - - CFReleaseNull(aliceSideSession); - CFReleaseNull(bobSideSession); - SOSDataSourceRelease(aliceDs, NULL); - SOSDataSourceFactoryRelease(aliceDsf); - - SOSDataSourceRelease(bobDs, NULL); - SOSDataSourceFactoryRelease(bobDsf); - - SecOTRFIPurgeAllFromKeychain(&testError); - RegressionsLogError(testError); - CFReleaseNull(bob_peer_external_form); - CFReleaseNull(alice_peer_external_form); - CFReleaseNull(alice_peers); - CFReleaseNull(bob_peers); - CFReleaseNull(aliceSideSession); - CFReleaseNull(bobSideSession); - CFReleaseNull(testError); -} - -int secd_70_otr_remote(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-71-engine-save-sample1.h b/OSX/sec/securityd/Regressions/secd-71-engine-save-sample1.h deleted file mode 100644 index b2916f85..00000000 --- a/OSX/sec/securityd/Regressions/secd-71-engine-save-sample1.h +++ /dev/null @@ -1,125 +0,0 @@ - -/* - MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state - acct : engine-state - agrp : com.apple.security.sos - cdat : 2016-04-18 20:40:33 +0000 - mdat : 2016-04-18 20:40:33 +0000 - musr : // - pdmn : dk - svce : SOSDataSource-ak - sync : 0 - tomb : 0 -*/ - -static unsigned char es_mango_bin[] = { - 0x31, 0x82, 0x0a, 0x1b, 0x30, 0x20, 0x0c, 0x02, 0x69, 0x64, 0x0c, 0x1a, 0x68, 0x42, 0x79, 0x73, 0x6d, 0x66, 0x31, 0x73, 0x44, 0x4f, 0x63, 0x2f, - 0x6f, 0x4d, 0x56, 0x49, 0x51, 0x66, 0x45, 0x74, 0x4b, 0x69, 0x71, 0x65, 0x64, 0x6e, 0x30, 0x27, 0x0c, 0x07, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, - 0x73, 0x30, 0x1c, 0x0c, 0x1a, 0x79, 0x48, 0x6d, 0x77, 0x76, 0x76, 0x6f, 0x75, 0x44, 0x38, 0x65, 0x44, 0x4d, 0x74, 0x49, 0x48, 0x5a, 0x66, 0x39, - 0x75, 0x65, 0x75, 0x53, 0x58, 0x2f, 0x47, 0x30, 0x82, 0x03, 0xa3, 0x0c, 0x0d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x43, 0x61, 0x63, - 0x68, 0x65, 0x31, 0x82, 0x03, 0x90, 0x30, 0x18, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, - 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x04, 0x00, 0x30, 0x7c, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, - 0x0c, 0x5b, 0xe3, 0xaf, 0x06, 0x2c, 0x77, 0x5b, 0x04, 0x64, 0x5a, 0x57, 0x4b, 0xb4, 0xec, 0x90, 0xc3, 0xbb, 0xcc, 0x69, 0xee, 0x73, 0xcb, 0xfe, - 0x03, 0x91, 0x33, 0xae, 0x80, 0x72, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, - 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, - 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, 0xab, 0xa3, 0xca, 0x34, 0x29, 0x66, - 0xef, 0xf8, 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0x30, 0x82, 0x01, 0x6e, 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, - 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x04, 0x82, 0x01, 0x54, 0x07, 0x57, 0x1e, 0x96, - 0x78, 0xfd, 0x7d, 0x68, 0x81, 0x2e, 0x40, 0x9c, 0xc9, 0x6c, 0x1f, 0x54, 0x83, 0x4a, 0x09, 0x9a, 0x0c, 0x3a, 0x2d, 0x12, 0xcc, 0xe2, 0xea, 0x95, - 0xf4, 0x50, 0x5e, 0xa5, 0x2f, 0x2c, 0x98, 0x2b, 0x2a, 0xde, 0xe3, 0xda, 0x14, 0xd4, 0x71, 0x2c, 0x00, 0x03, 0x09, 0xbf, 0x63, 0xd5, 0x4a, 0x98, - 0xb6, 0x1a, 0xa1, 0xd9, 0x63, 0xc4, 0x0e, 0x0e, 0x25, 0x31, 0xc8, 0x3b, 0x28, 0xca, 0x5b, 0xe6, 0xda, 0x0d, 0x26, 0x40, 0x0c, 0x3c, 0x77, 0xa6, - 0x18, 0xf7, 0x11, 0xdd, 0x3c, 0xc0, 0xbf, 0x86, 0xcc, 0xba, 0xf8, 0xaa, 0x33, 0x32, 0x97, 0x32, 0x68, 0xb3, 0x0e, 0xeb, 0xf2, 0x1c, 0xd8, 0x18, - 0x4d, 0x9c, 0x84, 0x27, 0xca, 0x13, 0xde, 0xcc, 0xc7, 0xbb, 0x83, 0xc8, 0x00, 0x09, 0xa2, 0xef, 0x45, 0xcc, 0xc0, 0x7f, 0x58, 0x63, 0x15, 0xc8, - 0x0c, 0xee, 0xee, 0xf5, 0xd5, 0x35, 0x2f, 0xd0, 0x00, 0xaa, 0xe6, 0xd9, 0xcb, 0xb4, 0x29, 0x4d, 0x59, 0x59, 0xfd, 0x00, 0x19, 0x82, 0x25, 0xaf, - 0x9a, 0xbd, 0x09, 0xb3, 0x41, 0xa2, 0xfd, 0xc2, 0x78, 0xe9, 0xfd, 0x14, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, - 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, - 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, - 0x95, 0xc9, 0xd4, 0xd8, 0xa8, 0xbc, 0xa2, 0xe8, 0x24, 0x2a, 0xb0, 0xd4, 0x09, 0xf6, 0x71, 0xf2, 0x98, 0xb6, 0xdc, 0xae, 0x9b, 0xc4, 0x23, 0x8c, - 0x09, 0xe0, 0x75, 0x48, 0xce, 0xfb, 0x30, 0x00, 0x98, 0x60, 0x6f, 0x9e, 0x4f, 0x23, 0x0c, 0x99, 0xab, 0xa3, 0xca, 0x34, 0x29, 0x66, 0xef, 0xf8, - 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0xb4, 0xfe, 0xfb, 0x84, 0xf8, 0xcf, 0x75, 0xc0, 0xc6, 0x9c, 0x59, 0x53, - 0x2c, 0x35, 0x4d, 0x17, 0x5a, 0x59, 0xf9, 0x61, 0xba, 0x4d, 0x4d, 0xfa, 0x01, 0x7f, 0xd8, 0x19, 0x22, 0x88, 0xf1, 0x42, 0x78, 0xae, 0x76, 0x71, - 0x2e, 0x12, 0x7d, 0x65, 0xfe, 0x61, 0x6c, 0x7e, 0x4f, 0xd0, 0x71, 0x36, 0x44, 0xf7, 0xc9, 0xa7, 0xab, 0xa1, 0xce, 0x06, 0x56, 0x94, 0xa9, 0x68, - 0x30, 0x82, 0x01, 0x82, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, - 0xdc, 0xad, 0x04, 0x82, 0x01, 0x68, 0x07, 0x57, 0x1e, 0x96, 0x78, 0xfd, 0x7d, 0x68, 0x81, 0x2e, 0x40, 0x9c, 0xc9, 0x6c, 0x1f, 0x54, 0x83, 0x4a, - 0x09, 0x9a, 0x0c, 0x3a, 0x2d, 0x12, 0xcc, 0xe2, 0xea, 0x95, 0xf4, 0x50, 0x5e, 0xa5, 0x2f, 0x2c, 0x98, 0x2b, 0x2a, 0xde, 0xe3, 0xda, 0x14, 0xd4, - 0x71, 0x2c, 0x00, 0x03, 0x09, 0xbf, 0x63, 0xd5, 0x4a, 0x98, 0xb6, 0x1a, 0xa1, 0xd9, 0x63, 0xc4, 0x0e, 0x0e, 0x25, 0x31, 0xc8, 0x3b, 0x28, 0xca, - 0x5b, 0xe6, 0xda, 0x0d, 0x26, 0x40, 0x0c, 0x3c, 0x77, 0xa6, 0x18, 0xf7, 0x11, 0xdd, 0x3c, 0xc0, 0xbf, 0x86, 0xcc, 0xba, 0xf8, 0xaa, 0x33, 0x32, - 0x97, 0x32, 0x68, 0xb3, 0x0e, 0xeb, 0xf2, 0x1c, 0xd8, 0x18, 0x4d, 0x9c, 0x84, 0x27, 0xca, 0x13, 0xde, 0xcc, 0xc7, 0xbb, 0x83, 0xc8, 0x00, 0x09, - 0xa2, 0xef, 0x45, 0xcc, 0xc0, 0x7f, 0x58, 0x63, 0x15, 0xc8, 0x0c, 0xee, 0xee, 0xf5, 0xd5, 0x35, 0x2f, 0xd0, 0x00, 0xaa, 0xe6, 0xd9, 0xcb, 0xb4, - 0x29, 0x4d, 0x59, 0x59, 0xfd, 0x00, 0x19, 0x82, 0x25, 0xaf, 0x9a, 0xbd, 0x09, 0xb3, 0x41, 0xa2, 0xfd, 0xc2, 0x78, 0xe9, 0xfd, 0x14, 0x5a, 0x57, - 0x4b, 0xb4, 0xec, 0x90, 0xc3, 0xbb, 0xcc, 0x69, 0xee, 0x73, 0xcb, 0xfe, 0x03, 0x91, 0x33, 0xae, 0x80, 0x72, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, - 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, - 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, - 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, 0x95, 0xc9, 0xd4, 0xd8, 0xa8, 0xbc, 0xa2, 0xe8, 0x24, 0x2a, 0xb0, 0xd4, 0x09, 0xf6, 0x71, 0xf2, 0x98, 0xb6, - 0xdc, 0xae, 0x9b, 0xc4, 0x23, 0x8c, 0x09, 0xe0, 0x75, 0x48, 0xce, 0xfb, 0x30, 0x00, 0x98, 0x60, 0x6f, 0x9e, 0x4f, 0x23, 0x0c, 0x99, 0xab, 0xa3, - 0xca, 0x34, 0x29, 0x66, 0xef, 0xf8, 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0xb4, 0xfe, 0xfb, 0x84, 0xf8, 0xcf, - 0x75, 0xc0, 0xc6, 0x9c, 0x59, 0x53, 0x2c, 0x35, 0x4d, 0x17, 0x5a, 0x59, 0xf9, 0x61, 0xba, 0x4d, 0x4d, 0xfa, 0x01, 0x7f, 0xd8, 0x19, 0x22, 0x88, - 0xf1, 0x42, 0x78, 0xae, 0x76, 0x71, 0x2e, 0x12, 0x7d, 0x65, 0xfe, 0x61, 0x6c, 0x7e, 0x4f, 0xd0, 0x71, 0x36, 0x44, 0xf7, 0xc9, 0xa7, 0xab, 0xa1, - 0xce, 0x06, 0x56, 0x94, 0xa9, 0x68, 0x30, 0x82, 0x06, 0x25, 0x0c, 0x09, 0x70, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x82, 0x06, - 0x16, 0x30, 0x81, 0xd5, 0x0c, 0x0f, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x56, 0x30, 0x2d, 0x74, 0x6f, 0x6d, 0x62, 0x31, 0x81, 0xc1, - 0x30, 0x0e, 0x0c, 0x09, 0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x01, 0x01, 0x00, 0x30, 0x11, 0x0c, 0x0c, 0x73, 0x65, 0x6e, 0x64, - 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x01, 0x01, 0x01, 0x30, 0x12, 0x0c, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x6e, - 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x00, 0x30, 0x14, 0x0c, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x02, 0x01, 0x00, 0x30, 0x1a, 0x0c, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, 0xd1, 0x11, 0x0c, 0x0f, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x56, 0x30, 0x2d, 0x74, 0x6f, 0x6d, 0x62, 0x30, 0x2a, 0x0c, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x6e, - 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x16, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, 0x0c, 0x5b, 0xe3, - 0xaf, 0x06, 0x2c, 0x77, 0x5b, 0x30, 0x2a, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, - 0x65, 0x73, 0x74, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, 0x0c, 0x5b, 0xe3, 0xaf, 0x06, 0x2c, 0x77, - 0x5b, 0x30, 0x82, 0x05, 0x3a, 0x0c, 0x1a, 0x79, 0x48, 0x6d, 0x77, 0x76, 0x76, 0x6f, 0x75, 0x44, 0x38, 0x65, 0x44, 0x4d, 0x74, 0x49, 0x48, 0x5a, - 0x66, 0x39, 0x75, 0x65, 0x75, 0x53, 0x58, 0x2f, 0x47, 0x31, 0x82, 0x05, 0x1a, 0x30, 0x0e, 0x0c, 0x09, 0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x65, - 0x6e, 0x64, 0x01, 0x01, 0x00, 0x30, 0x11, 0x0c, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x01, 0x01, 0x00, - 0x30, 0x14, 0x0c, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x02, 0x01, 0x03, 0x30, 0x27, - 0x0c, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, - 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x30, 0x29, 0x0c, 0x11, 0x75, 0x6e, 0x77, 0x61, 0x6e, - 0x74, 0x65, 0x64, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, - 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x30, 0x2a, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x2d, - 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, - 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, 0x30, 0x3e, 0x0c, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, - 0x30, 0x2c, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, - 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x30, 0x40, - 0x0c, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x2c, 0x04, 0x14, 0xcc, 0xf1, - 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, - 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x30, 0x82, 0x01, 0x16, 0x0c, 0x05, 0x76, 0x69, - 0x65, 0x77, 0x73, 0xd1, 0x82, 0x01, 0x0b, 0x0c, 0x04, 0x57, 0x69, 0x46, 0x69, 0x0c, 0x07, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x54, 0x56, 0x0c, 0x07, - 0x48, 0x6f, 0x6d, 0x65, 0x4b, 0x69, 0x74, 0x0c, 0x07, 0x50, 0x43, 0x53, 0x2d, 0x46, 0x44, 0x45, 0x0c, 0x09, 0x50, 0x43, 0x53, 0x2d, 0x4e, 0x6f, - 0x74, 0x65, 0x73, 0x0c, 0x09, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x45, 0x73, 0x63, 0x72, 0x6f, 0x77, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x50, 0x68, 0x6f, 0x74, - 0x6f, 0x73, 0x0c, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x61, 0x67, 0x56, 0x30, 0x0c, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, - 0x61, 0x72, 0x64, 0x73, 0x0c, 0x0b, 0x50, 0x43, 0x53, 0x2d, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x43, - 0x6c, 0x6f, 0x75, 0x64, 0x4b, 0x69, 0x74, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x46, 0x65, 0x6c, 0x64, 0x73, 0x70, 0x61, 0x72, 0x0c, 0x0c, 0x50, - 0x43, 0x53, 0x2d, 0x4d, 0x61, 0x69, 0x6c, 0x64, 0x72, 0x6f, 0x70, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x69, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x0c, 0x0d, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x53, 0x79, 0x6e, 0x63, 0x61, 0x62, 0x6c, 0x65, 0x0c, 0x0d, 0x50, 0x43, 0x53, 0x2d, 0x4d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x0c, 0x0e, 0x69, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x0c, - 0x0f, 0x50, 0x43, 0x53, 0x2d, 0x69, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x44, 0x72, 0x69, 0x76, 0x65, 0x0c, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, - 0x75, 0x69, 0x74, 0x79, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x30, 0x82, 0x02, 0xc1, 0x0c, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x04, 0x82, 0x02, - 0xb6, 0x30, 0x82, 0x02, 0xb2, 0x04, 0x82, 0x02, 0xab, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x0c, 0x6b, 0x65, 0x79, 0x73, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x04, 0x46, 0x62, 0x20, 0xcd, 0xee, 0x34, 0x9b, 0xb8, 0x68, 0x98, 0x21, 0xa6, 0xfc, 0x3a, 0x7c, 0xc3, - 0x77, 0x5d, 0x58, 0x39, 0xaf, 0xd6, 0x3c, 0xc6, 0x1c, 0xf9, 0x1e, 0xa8, 0xdb, 0x93, 0xba, 0xdd, 0xc6, 0x29, 0x6e, 0x86, 0xd9, 0x54, 0xc2, 0xe3, - 0x3d, 0x5f, 0x3b, 0x13, 0x87, 0xe1, 0xad, 0x4e, 0x06, 0x12, 0xab, 0xc0, 0x5e, 0x60, 0x4e, 0xf8, 0x2c, 0x37, 0x97, 0xa9, 0x5d, 0xc8, 0x25, 0x12, - 0x30, 0x45, 0x81, 0x43, 0x00, 0x41, 0x04, 0x70, 0xbc, 0xaa, 0x24, 0x80, 0xbf, 0x11, 0x7e, 0xeb, 0x2c, 0x4f, 0xe2, 0x86, 0xf3, 0x38, 0xab, 0x48, - 0x3c, 0xe5, 0xd7, 0xdc, 0x69, 0xb7, 0x81, 0x71, 0x83, 0x9b, 0xf3, 0xf7, 0xa0, 0x96, 0x0b, 0xe8, 0xcd, 0xef, 0xf7, 0x26, 0x0a, 0x7a, 0xc1, 0x22, - 0x7d, 0xa0, 0x00, 0x13, 0x2a, 0x95, 0xee, 0x89, 0x83, 0x9b, 0x7a, 0xf0, 0x56, 0x24, 0x28, 0x89, 0x86, 0x2e, 0x3a, 0x06, 0xca, 0xea, 0x7d, 0x67, - 0x0c, 0x42, 0x15, 0x56, 0x55, 0xc2, 0x39, 0x13, 0x89, 0x31, 0x73, 0xf1, 0x26, 0xce, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x41, 0x04, 0x3a, 0x81, 0x2c, 0x93, 0xa5, 0xe2, 0x51, 0x73, 0xe3, 0xe8, 0xe4, 0xa1, 0x4b, 0xaf, 0xf9, 0xfe, 0x5c, 0x34, 0x2b, 0xde, 0xc1, 0x0a, - 0xe7, 0x14, 0x41, 0x4c, 0xbd, 0x93, 0xc5, 0x8e, 0x2e, 0x57, 0x0d, 0xcf, 0x68, 0x85, 0x89, 0xe8, 0x47, 0xfc, 0xf1, 0x57, 0xcb, 0xcf, 0x55, 0x6b, - 0x30, 0xf9, 0x95, 0x30, 0x73, 0x05, 0x90, 0x26, 0xad, 0x67, 0x6b, 0x52, 0x0a, 0x14, 0x35, 0x66, 0x6c, 0x68, 0x00, 0x00, 0x00, 0x20, 0xb7, 0x75, - 0x89, 0x6c, 0xa0, 0xf3, 0xb8, 0x5c, 0xcb, 0x42, 0x76, 0x5c, 0xfa, 0x23, 0xbc, 0x31, 0x25, 0x2c, 0xff, 0xbf, 0xab, 0x42, 0x93, 0xe3, 0xfe, 0xa5, - 0xab, 0xa1, 0x8b, 0xb9, 0xfb, 0x5d, 0x00, 0x00, 0x00, 0x41, 0x04, 0x32, 0xa0, 0x73, 0xc6, 0x84, 0x50, 0x7c, 0xd6, 0xad, 0x0f, 0x4e, 0x8e, 0x89, - 0xbb, 0x87, 0xe1, 0x41, 0xad, 0xc3, 0xfc, 0x10, 0x6a, 0x03, 0x2e, 0x80, 0x87, 0x57, 0xf0, 0x28, 0xbc, 0xd3, 0x2b, 0x70, 0xf5, 0x71, 0x33, 0x03, - 0x92, 0xa7, 0x6f, 0x85, 0xa3, 0x51, 0xc5, 0xa5, 0xea, 0xd3, 0xd1, 0x5d, 0xbf, 0xf1, 0x94, 0x1e, 0xb9, 0x14, 0x76, 0x6a, 0xa5, 0x6e, 0xbb, 0x3a, - 0x84, 0xa9, 0xd4, 0x00, 0x00, 0x00, 0x20, 0x69, 0x79, 0x82, 0x88, 0xd1, 0x99, 0x93, 0x6e, 0x8d, 0x67, 0x02, 0x00, 0xb1, 0xe5, 0x09, 0x90, 0x1c, - 0xa0, 0x9d, 0x4c, 0xb5, 0x4c, 0x8c, 0x21, 0x4b, 0x51, 0x16, 0x4a, 0x85, 0x43, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, - 0x04, 0x51, 0xbc, 0xc5, 0xb7, 0xa1, 0xa1, 0xf0, 0x8c, 0x32, 0xb0, 0xe0, 0x37, 0x71, 0x60, 0x7a, 0x52, 0x67, 0x92, 0x24, 0x13, 0xa1, 0x57, 0x24, - 0x7d, 0x04, 0x86, 0x97, 0x70, 0xb0, 0xfd, 0xbd, 0xda, 0x73, 0xea, 0x21, 0x59, 0xaa, 0x5e, 0x93, 0xcd, 0x92, 0xbb, 0x23, 0x9d, 0x28, 0x67, 0x78, - 0xa4, 0x6f, 0xa5, 0x98, 0xcd, 0x43, 0x7b, 0xf1, 0xf2, 0xf3, 0x65, 0xa0, 0xa3, 0x7d, 0xd9, 0xb1, 0x91, 0x00, 0x00, 0x00, 0x41, 0x04, 0xd5, 0x55, - 0x5f, 0xa3, 0x0d, 0xfa, 0x00, 0xea, 0x45, 0xf2, 0x3d, 0x27, 0xc8, 0xa5, 0x44, 0x7c, 0xa7, 0xc0, 0x01, 0x62, 0x26, 0xab, 0x44, 0x4b, 0xe1, 0xf6, - 0x89, 0x2a, 0x2b, 0x8c, 0x52, 0xaa, 0x0c, 0x1b, 0xfa, 0xf8, 0x3d, 0x1b, 0xbe, 0xc1, 0x29, 0x08, 0xdf, 0xa7, 0x30, 0x89, 0x0b, 0x5a, 0xdd, 0xcf, - 0xd6, 0x2e, 0x1a, 0x63, 0x81, 0x39, 0x0c, 0x61, 0x1a, 0x64, 0x0c, 0x0d, 0xb3, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xad, 0xc2, 0xb3, 0xe0, 0x47, 0xbe, 0xbd, 0x4f, 0xe1, 0x4b, 0xd9, 0x2c, 0x5d, 0x08, - 0x88, 0xb2, 0x0f, 0x2a, 0xf5, 0x9a, 0x15, 0xa3, 0xb7, 0x3b, 0xd8, 0xe6, 0x48, 0x33, 0x30, 0x51, 0x26, 0x6a, 0x31, 0x99, 0x24, 0x63, 0xa8, 0xaa, - 0xa7, 0x46, 0xdd, 0xcf, 0x62, 0xec, 0x98, 0x97, 0xbe, 0xe0, 0xd3, 0x41, 0x15, 0x58, 0x42, 0x62, 0xd8, 0x55, 0x02, 0xc4, 0x46, 0x5c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00 -}; -unsigned int es_mango_bin_len = 2591; diff --git a/OSX/sec/securityd/Regressions/secd-71-engine-save.m b/OSX/sec/securityd/Regressions/secd-71-engine-save.m deleted file mode 100644 index 1de658be..00000000 --- a/OSX/sec/securityd/Regressions/secd-71-engine-save.m +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// Test save and restore of SOSEngine states - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -#include "keychain/SecureObjectSync/SOSEngine.h" -#include "keychain/SecureObjectSync/SOSPeer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int kTestTestCount = 8; - -/* - Attributes for a v0 engine-state genp item - - MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state - acct : engine-state - agrp : com.apple.security.sos - cdat : 2016-04-18 20:40:33 +0000 - mdat : 2016-04-18 20:40:33 +0000 - musr : // - pdmn : dk - svce : SOSDataSource-ak - sync : 0 - tomb : 0 - */ - -#include "secd-71-engine-save-sample1.h" - -static bool verifyV2EngineState(SOSDataSourceRef ds, CFStringRef myPeerID) { - bool rx = false; - CFErrorRef error = NULL; - SOSTransactionRef txn = NULL; - CFDataRef basicEngineState = NULL; - CFDictionaryRef engineState = NULL; - - SKIP: { - CFDataRef basicEngineState = SOSDataSourceCopyStateWithKey(ds, kSOSEngineStatev2, kSecAttrAccessibleAlwaysPrivate, txn, &error); - skip("Failed to get V2 engine state", 2, basicEngineState); - ok(basicEngineState, "SOSDataSourceCopyStateWithKey:kSOSEngineStatev2"); - engineState = derStateToDictionaryCopy(basicEngineState, &error); - skip("Failed to DER decode V2 engine state", 1, basicEngineState); - CFStringRef engID = (CFStringRef)asString(CFDictionaryGetValue(engineState, CFSTR("id")), &error); - ok(CFEqualSafe(myPeerID, engID),"Check myPeerID"); - rx = true; - } - - CFReleaseSafe(basicEngineState); - CFReleaseSafe(engineState); - CFReleaseSafe(error); - return rx; -} - -static bool verifyV2PeerStates(SOSDataSourceRef ds, CFStringRef myPeerID, CFArrayRef peers) { - bool rx = false; - __block CFErrorRef error = NULL; - SOSTransactionRef txn = NULL; - CFDictionaryRef peerStateDict = NULL; - CFDataRef data = NULL; - __block CFIndex peerCount = CFArrayGetCount(peers) - 1; // drop myPeerID - - SKIP: { - data = SOSDataSourceCopyStateWithKey(ds, kSOSEnginePeerStates, kSOSEngineProtectionDomainClassD, txn, &error); - skip("Failed to get V2 peerStates", 3, data); - - peerStateDict = derStateToDictionaryCopy(data, &error); - skip("Failed to DER decode V2 peerStates", 2, peerStateDict); - ok(peerStateDict, "SOSDataSourceCopyStateWithKey:kSOSEnginePeerStates"); - - // Check that each peer passed in exists in peerStateDict - CFArrayForEach(peers, ^(const void *key) { - CFStringRef peerID = (CFStringRef)asString(key, &error); - if (!CFEqualSafe(myPeerID, peerID)) { - if (CFDictionaryContainsKey(peerStateDict, peerID)) - peerCount--; - } - }); - ok(peerCount==0,"Peers exist in peer list (%ld)", (CFArrayGetCount(peers) - 1 - peerCount)); - rx = true; - } - - CFReleaseSafe(peerStateDict); - CFReleaseSafe(data); - CFReleaseSafe(error); - return rx; -} - -static bool checkV2EngineStates(SOSTestDeviceRef td, CFStringRef myPeerID, CFArrayRef peers) { - bool rx = true; - CFErrorRef error = NULL; - SOSTransactionRef txn = NULL; - CFDictionaryRef manifestCache = NULL; - CFDataRef data = NULL; -// CFMutableDictionaryRef codersDict = NULL; // SOSEngineLoadCoders - - rx &= verifyV2EngineState(td->ds, myPeerID); - - data = SOSDataSourceCopyStateWithKey(td->ds, kSOSEngineManifestCache, kSOSEngineProtectionDomainClassD, txn, &error); - manifestCache = derStateToDictionaryCopy(data, &error); - CFReleaseNull(data); - - rx &= verifyV2PeerStates(td->ds, myPeerID, peers); - - CFReleaseSafe(manifestCache); - return rx; -} - -static void testSaveRestore(void) { - CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayAppendValue(deviceIDs, CFSTR("lemon")); - CFArrayAppendValue(deviceIDs, CFSTR("lime")); - CFArrayAppendValue(deviceIDs, CFSTR("orange")); - bool bx = false; - int version = 2; - CFErrorRef error = NULL; - __block int devIdx = 0; - CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, ^(SOSDataSourceRef ds) { - // This block is called before SOSEngineLoad - if (devIdx == 0) { - // Test migration of v0 to v2 engine state - CFDataRef engineStateData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, es_mango_bin, es_mango_bin_len, kCFAllocatorNull); - SOSTestDeviceAddV0EngineStateWithData(ds, engineStateData); - CFReleaseSafe(engineStateData); - } - devIdx++; - }); - - CFStringRef sourceID = (CFStringRef)CFArrayGetValueAtIndex(deviceIDs, 0); - SOSTestDeviceRef source = (SOSTestDeviceRef)CFDictionaryGetValue(testDevices, sourceID); - - ok(SOSTestDeviceEngineSave(source, &error),"SOSTestDeviceEngineSave: %@",error); - - bx = SOSTestDeviceEngineLoad(source, &error); - ok(bx,"SOSTestEngineLoad: %@",error); - - bx = checkV2EngineStates(source, sourceID, deviceIDs); - ok(bx,"getV2EngineStates: %@",error); - - bx = SOSTestDeviceEngineSave(source, &error); - ok(bx,"SOSTestDeviceEngineSave v2: %@",error); - - SOSTestDeviceDestroyEngine(testDevices); - CFReleaseSafe(deviceIDs); - CFReleaseSafe(testDevices); - CFReleaseSafe(error); -} - -int secd_71_engine_save(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - testSaveRestore(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m b/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m deleted file mode 100644 index d814afdf..00000000 --- a/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 646; - -// Add 1000 items on each device. Then delete 1000 items on each device. -static void beer_servers(void) { - __block int iteration=0; - __block int objectix=0; - __block CFMutableArrayRef objectNames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - const size_t itemDataSize = 1024; - const int peerCount = 4; - const int edgeCount = peerCount * (peerCount - 1); - const int itemsPerPeer = 1000; - const int itemsPerIteration = 100; - const int itemChunkCount = (itemsPerPeer / itemsPerIteration); - const int deleteIteration = edgeCount * (itemChunkCount + 30); - const int idleIteration = 616; //deleteIteration + edgeCount * (itemChunkCount + 10); - - CFMutableDataRef itemData = CFDataCreateMutable(kCFAllocatorDefault, itemDataSize); - CFDataSetLength(itemData, itemDataSize); - SOSTestDeviceListTestSync("beer_servers", test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - bool result = false; - if (iteration <= edgeCount * itemChunkCount) { - if (iteration % (peerCount - 1) == 0) { - for (int j = 0; j < itemsPerIteration; ++j) { - CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-pre-%d"), SOSTestDeviceGetID(source), objectix++); - CFArrayAppendValue(objectNames, name); - SOSTestDeviceAddGenericItemWithData(source, name, name, itemData); - CFReleaseNull(name); - } - } - result = true; - } else if (iteration == deleteIteration) { - //diag("deletion starting"); - } else if (deleteIteration < iteration && iteration <= deleteIteration + edgeCount * itemChunkCount) { - if (iteration % (peerCount - 1) == 0) { - for (int j = 0; j < itemsPerIteration; ++j) { - CFStringRef name = CFArrayGetValueAtIndex(objectNames, --objectix); - SOSTestDeviceAddGenericItemTombstone(source, name, name); - } - result = true; - } - } else if (idleIteration == iteration) { - //diag("idle starting"); - } else if (617 == iteration) { - //diag("interesting"); - } - iteration++; - return result || iteration < deleteIteration; - }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }, CFSTR("becks"), CFSTR("corona"), CFSTR("heineken"), CFSTR("spaten"), NULL); - CFRelease(objectNames); - CFRelease(itemData); -} - -int secd_74_engine_beer_servers(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - /* custom keychain dir */ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - beer_servers(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-75-engine-views.m b/OSX/sec/securityd/Regressions/secd-75-engine-views.m deleted file mode 100644 index 6e65d3c3..00000000 --- a/OSX/sec/securityd/Regressions/secd-75-engine-views.m +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" -#include -#include "keychain/SecureObjectSync/SOSPeer.h" - -static int kTestTestCount = 53; - -// Add 1000 items on each device. Then delete 1000 items on each device. -static void test_engine_views(void) { - __block int iteration=0; - __block int objectix=0; - __block CFMutableArrayRef objectNames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - const size_t itemDataSize = 1024; - const int peerCount = 4; - const int edgeCount = peerCount * (peerCount - 1); - const int itemsPerPeer = 1000; - const int itemsPerIteration = 100; - const int itemChunkCount = (itemsPerPeer / itemsPerIteration); - const int deleteIteration = edgeCount * (itemChunkCount + 30); - const int idleIteration = 616; //deleteIteration + edgeCount * (itemChunkCount + 10); - - CFMutableDataRef itemData = CFDataCreateMutable(kCFAllocatorDefault, itemDataSize); - CFDataSetLength(itemData, itemDataSize); - - const char *name = "engine_views"; - //const char *test_directive - //const char *test_reason - CFIndex version = 0; - bool(^pre)(SOSTestDeviceRef source, SOSTestDeviceRef dest) = ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { - bool result = false; - if (iteration <= edgeCount * itemChunkCount) { - if (iteration % (peerCount - 1) == 0) { - for (int j = 0; j < itemsPerIteration; ++j) { - CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-pre-%d"), SOSTestDeviceGetID(source), objectix++); - CFArrayAppendValue(objectNames, name); - SOSTestDeviceAddGenericItemWithData(source, name, name, itemData); - CFReleaseNull(name); - } - } - result = true; - } else if (iteration == deleteIteration) { - //diag("deletion starting"); - } else if (deleteIteration < iteration && iteration <= deleteIteration + edgeCount * itemChunkCount) { - if (iteration % (peerCount - 1) == 0) { - for (int j = 0; j < itemsPerIteration; ++j) { - CFStringRef name = CFArrayGetValueAtIndex(objectNames, --objectix); - SOSTestDeviceAddGenericItemTombstone(source, name, name); - } - result = true; - } - } else if (idleIteration == iteration) { - //diag("idle starting"); - } else if (617 == iteration) { - //diag("interesting"); - } - iteration++; - return result || iteration < deleteIteration; - }; - bool(^post)(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) = ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { - return false; - }; - - // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault, CFSTR("becks"), CFSTR("corona"), CFSTR("heineken"), CFSTR("spaten"), NULL); - CFSetRef views = SOSViewsCopyTestV2Default(); - CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef deviceID; - CFArrayForEachC(deviceIDs, deviceID) { - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); - CFArrayAppendValue(peerMetas, peerMeta); - CFReleaseNull(peerMeta); - } - - CFMutableDictionaryRef testDevices = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayForEachC(deviceIDs, deviceID) { - SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); - SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - CFDictionarySetValue(testDevices, deviceID, device); - CFReleaseNull(device); - } - CFDictionarySetValue(testDevices, CFSTR("@devicesIDs"), deviceIDs); - CFReleaseNull(deviceIDs); - - SOSTestDeviceListSync(name, test_directive, test_reason, testDevices, pre, post); - SOSTestDeviceListInSync(name, test_directive, test_reason, testDevices); - SOSTestDeviceDestroyEngine(testDevices); - CFReleaseNull(testDevices); - - CFReleaseNull(views); - CFReleaseNull(objectNames); - CFReleaseNull(itemData); -} - -int secd_75_engine_views(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - /* custom keychain dir */ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - test_engine_views(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-76-idstransport.m b/OSX/sec/securityd/Regressions/secd-76-idstransport.m deleted file mode 100644 index 164c56f0..00000000 --- a/OSX/sec/securityd/Regressions/secd-76-idstransport.m +++ /dev/null @@ -1,315 +0,0 @@ -// -// secd-76-idstransport.c -// sec -// -// - -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include "SecdTestKeychainUtilities.h" -#import "SOSAccountTesting.h" -#import "SOSTransportTestTransports.h" -#include -#include -#include "SOSTestDevice.h" - - - -static int kTestTestCount = 73; - -static void tests() -{ - CFErrorRef error = NULL; - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); - SOSAccountTrustClassic *aliceTrust = alice_account.trust; - SOSAccountTrustClassic *bobTrust = bob_account.trust; - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(NULL != alice_account, "Alice Created"); - ok(NULL != bob_account, "Bob Created"); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - //creating test devices - CFIndex version = 0; - - // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); - CFSetRef views = SOSViewsCopyTestV2Default(); - CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef deviceID; - CFArrayForEachC(deviceIDs, deviceID) { - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); - CFArrayAppendValue(peerMetas, peerMeta); - CFReleaseNull(peerMeta); - } - - CFReleaseNull(views); - CFArrayForEachC(deviceIDs, deviceID) { - SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); - SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - - if(CFEqualSafe(deviceID, (__bridge CFTypeRef)(alice_account.peerID))){ - alice_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); - } - else{ - bob_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); - } - CFReleaseNull(device); - } - CFReleaseNull(deviceIDs); - CFReleaseNull(peerMetas); - - SOSUnregisterAllTransportMessages(); - CFArrayRemoveAllValues(message_transports); - - alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error]; - - - bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; - ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); - ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); - - bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^(SOSCircleRef circle) { - CFErrorRef localError = NULL; - - SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - - return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); - }]; - - ok(result, "Alice account update circle with transport type"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - result &= [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^(SOSCircleRef circle) { - CFErrorRef localError = NULL; - - SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - - return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); - }]; - - ok(result, "Bob account update circle with transport type"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); - CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); - ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); - ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); - - CFReleaseNull(alice_transportType); - CFReleaseNull(bob_accountTransportType); - - SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); - ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); - ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); - ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); - CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); - ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); - - ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); - CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); - ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); - ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("DSID"),&error), "Setting IDS device ID"); - CFStringRef dsid = SOSAccountCopyDeviceID(alice_account, &error); - ok(CFEqualSafe(dsid, CFSTR("DSID")), "Getting IDS device ID"); - CFReleaseNull(dsid); - - ok(SOSAccountStartPingTest(alice_account, CFSTR("hai there!"), &error), "Ping test"); - ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); - SOSTransportMessageIDSTestClearChanges((SOSMessageIDSTest*)alice_account.ids_message_transport); - - ok(SOSAccountSendIDSTestMessage(alice_account, CFSTR("hai again!"), &error), "Send Test Message"); - ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); - - CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); - CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII); - CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII); - - //test IDS message handling - CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] - == kHandleIDSMessageDontHandle, "sending empty message dictionary"); - - CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending device ID only"); - - CFReleaseNull(messageDict); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peer ID only"); - - CFReleaseNull(messageDict); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDataRef data = CFDataCreate(kCFAllocatorDefault, 0, 0); - CFDictionaryAddValue(messageDict, dataKey, data); - ok( [alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data only"); - - CFReleaseNull(messageDict); - CFReleaseNull(data); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - data = CFDataCreate(kCFAllocatorDefault, 0, 0); - CFDictionaryAddValue(messageDict, dataKey, data); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending data and peerid only"); - - CFReleaseNull(messageDict); - CFReleaseNull(data); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - data = CFDataCreate(kCFAllocatorDefault, 0, 0); - CFDictionaryAddValue(messageDict, dataKey, data); - CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data and deviceid only"); - - CFReleaseNull(messageDict); - CFReleaseNull(data); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peerid and deviceid only"); - - CFReleaseNull(messageDict); - CFReleaseNull(data); - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - data = CFDataCreate(kCFAllocatorDefault, 0, 0); - CFDictionaryAddValue(messageDict, dataKey, data); - CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, SOSPeerInfoGetPeerID(bob_account.peerInfo)); - ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); - - CFReleaseNull(messageDict); - CFReleaseNull(data); - - messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - data = CFDataCreate(kCFAllocatorDefault, 0, 0); - CFDictionaryAddValue(messageDict, dataKey, data); - CFStringRef BobDeviceID = SOSPeerInfoCopyDeviceID(bob_account.peerInfo); - CFDictionaryAddValue(messageDict, deviceIDKey, BobDeviceID); - CFReleaseNull(BobDeviceID); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); - - CFReleaseNull(data); - CFReleaseNull(dataKey); - CFReleaseNull(deviceIDKey); - CFReleaseNull(sendersPeerIDKey); - - CFReleaseNull(alice_dsid); - CFReleaseNull(bob_dsid); - CFReleaseNull(changes); - - SOSTestCleanup(); -} -int secd_76_idstransport(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m b/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m deleted file mode 100644 index 57bc8d44..00000000 --- a/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// -// secd-80-views-alwayson.c -// Security -// -// -// - - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" - -#include "secd_regressions.h" -#include "SOSAccountTesting.h" -#include "SecdTestKeychainUtilities.h" - -static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { - CFErrorRef error = NULL; - SOSViewResultCode vcode = 9999; - switch(action) { - case kSOSCCViewQuery: - vcode = [account.trust viewStatus:account name:view err:&error]; - break; - case kSOSCCViewEnable: - case kSOSCCViewDisable: // fallthrough - vcode = [account.trust updateView:account name:view code:action err:&error]; - break; - default: - break; - } - is(vcode, expected, "%s (%@)", label, error); - CFReleaseNull(error); -} - -/* - Make a circle with two peers - alice and bob - Check for ContinuityUnlock View on Alice - it should be there - turn off ContinuityUnlock on Alice - Change the password with Bob - makeing Alice invalid - Update Alice with the new password - see that ContinuityUnlock is automatically back on because it's "always on" - */ - -static void alwaysOnTest() -{ - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfpasswordNew = CFDataCreate(NULL, (uint8_t *) "FooFooFo2", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - - // Start Circle - ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); - CFReleaseNull(cfpassword); - - testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); - testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewDisable, "Not expected to disable kSOSViewContinuityUnlock - it's always-on"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpasswordNew, NULL), "Bob changes the password"); - testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected kSOSViewContinuityUnlock is on for alice still"); - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpasswordNew, NULL), "Alice sets the new password"); - CFReleaseNull(cfpasswordNew); - testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); - - CFReleaseNull(changes); - - SOSTestCleanup(); -} - -int secd_80_views_alwayson(int argc, char *const *argv) -{ - plan_tests(35); - secd_test_clear_testviews(); - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - alwaysOnTest(); - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-80-views-basic.m b/OSX/sec/securityd/Regressions/secd-80-views-basic.m deleted file mode 100644 index b628d575..00000000 --- a/OSX/sec/securityd/Regressions/secd-80-views-basic.m +++ /dev/null @@ -1,180 +0,0 @@ -// -// secd-80-views-basic.c -// sec -// -// Created by Richard Murphy on 1/26/15. -// -// - -#include -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#include -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSFullPeerInfo.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" - - -static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { - CFErrorRef error = NULL; - SOSViewResultCode vcode = 9999; - switch(action) { - case kSOSCCViewQuery: - vcode = [account.trust viewStatus:account name:view err:&error]; - break; - case kSOSCCViewEnable: - case kSOSCCViewDisable: // fallthrough - vcode = [account.trust updateView:account name:view code:action err:&error]; - break; - default: - break; - } - is(vcode, expected, "%s (%@)", label, error); - CFReleaseNull(error); -} - -static void testViewLists(void) { - CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); - CFSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault); - CFSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial); - CFSetRef alwaysOnViews = SOSViewCopyViewSet(kViewSetAlwaysOn); - CFSetRef backupRequiredViews = SOSViewCopyViewSet(kViewSetRequiredForBackup); - CFSetRef V0Views = SOSViewCopyViewSet(kViewSetV0); - - is(CFSetGetCount(allViews), 24, "make sure count of allViews is correct"); - is(CFSetGetCount(defaultViews), 20, "make sure count of defaultViews is correct"); - is(CFSetGetCount(initialViews), 0, "make sure count of initialViews is correct"); - is(CFSetGetCount(alwaysOnViews), 20, "make sure count of alwaysOnViews is correct"); - is(CFSetGetCount(backupRequiredViews), 3, "make sure count of backupRequiredViews is correct"); - is(CFSetGetCount(V0Views), 6, "make sure count of V0Views is correct"); - - CFReleaseNull(allViews); - CFReleaseNull(defaultViews); - CFReleaseNull(initialViews); - CFReleaseNull(alwaysOnViews); - CFReleaseNull(backupRequiredViews); - CFReleaseNull(V0Views); -} - -static int kTestTestCount = 38; -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFSetRef nullSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); - SOSDataSourceRef test_source = SOSTestDataSourceCreate(); - SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - - SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); - - ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - ok(SOSAccountJoinCircles_wTxn(account, &error), "Join circle: %@", error); - - ok(NULL != account, "Created"); - - ok(SOSAccountCheckHasBeenInSync_wTxn(account), "In sync already"); - - testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychain"); - // Default views no longer includes kSOSViewAppleTV - testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV"); - testView(account, kSOSCCViewMember, kSOSViewPCSPhotos, kSOSCCViewQuery, "Expected no view capability for kSOSViewPCSPhotos"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected no view capability for kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCNoSuchView, CFSTR("FOO"), kSOSCCViewQuery, "Expected no such view for FOO"); - - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewEnable, "Expected to enable kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewDisable, "Expected cannot disable kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); - - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewEnable, "Expected to enable kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewEnable, "Expected to enable kSOSViewKeychainV0"); - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewEnable, "Expected to enable kSOSViewAppleTV"); - - testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); - testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychainV0"); - testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV"); - - ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0"); - testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0"); - - ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0"); - testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0"); - - SOSPeerInfoRef pi = account.peerInfo; - ok(pi, "should have the peerInfo"); - SOSViewResultCode vr = SOSViewsEnable(pi, kSOSViewKeychainV0, NULL); - - ok(vr == kSOSCCViewMember, "Set Virtual View manually"); - - ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0"); - testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there"); - - ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0"); - testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there"); - - SOSDataSourceRelease(test_source, NULL); - SOSDataSourceFactoryRelease(test_factory); - - SOSTestCleanup(); -} - -int secd_80_views_basic(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - secd_test_clear_testviews(); - testViewLists(); - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m b/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m deleted file mode 100644 index b5c60442..00000000 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m +++ /dev/null @@ -1,366 +0,0 @@ -// -// si-81-item-acl.c -// sec -// -// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. -// -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "secd_regressions.h" - -#if USE_KEYSTORE -#include -#include "SecdTestKeychainUtilities.h" -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR -#include -#endif - -#endif - -enum ItemAttrType { - kBoolItemAttr, - kNumberItemAttr, - kStringItemAttr, - kDataItemAttr, - kBlobItemAttr, - kDateItemAttr, - kAccessabilityItemAttr, - kAccessGroupItemAttr, -}; - -extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); - -#if LA_CONTEXT_IMPLEMENTED -static keybag_handle_t test_keybag; -static const char *passcode = "password"; - -static bool changePasscode(const char *old_passcode, const char *new_passcode) -{ - size_t old_passcode_len = 0; - size_t new_passcode_len = 0; - - if (old_passcode) - old_passcode_len = strlen(old_passcode); - - if (new_passcode) - new_passcode_len = strlen(new_passcode); - - kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); - return status == 0; -} -#endif - -static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { - va_list ap; - va_start(ap, each); - CFStringRef attr; - while((attr = va_arg(ap, CFStringRef)) != NULL) { - enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); - each(attr, atype); - } - va_end(ap); -} - -static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { - CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); - if (!iclass) { - return; - } else if (CFEqual(iclass, kSecClassGenericPassword)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrAccount, kStringItemAttr, - kSecAttrService, kStringItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassInternetPassword)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrAccount, kStringItemAttr, - kSecAttrSecurityDomain, kStringItemAttr, - kSecAttrServer, kStringItemAttr, - kSecAttrProtocol, kNumberItemAttr, - kSecAttrAuthenticationType, kNumberItemAttr, - kSecAttrPort, kNumberItemAttr, - kSecAttrPath, kStringItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassCertificate)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrCertificateType, kNumberItemAttr, - kSecAttrIssuer, kDataItemAttr, - kSecAttrSerialNumber, kDataItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassKey)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies - kSecAttrApplicationLabel, kDataItemAttr, - kSecAttrApplicationTag, kDataItemAttr, - kSecAttrKeyType, kNumberItemAttr, - kSecAttrKeySizeInBits, kNumberItemAttr, - kSecAttrEffectiveKeySize, kNumberItemAttr, - kSecAttrStartDate, kDateItemAttr, - kSecAttrEndDate, kDateItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassIdentity)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrCertificateType, kNumberItemAttr, - kSecAttrIssuer, kDataItemAttr, - kSecAttrSerialNumber, kDataItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies - kSecAttrApplicationLabel, kDataItemAttr, - kSecAttrApplicationTag, kDataItemAttr, - kSecAttrKeyType, kNumberItemAttr, - kSecAttrKeySizeInBits, kNumberItemAttr, - kSecAttrEffectiveKeySize, kNumberItemAttr, - kSecAttrStartDate, kDateItemAttr, - kSecAttrEndDate, kDateItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } -} - -#if LA_CONTEXT_IMPLEMENTED -CF_RETURNS_RETAINED -static CFErrorRef createCFError(CFStringRef message, CFIndex code) -{ - const void* keysPtr[1]; - const void* messagesPtr[1]; - - keysPtr[0] = kCFErrorLocalizedDescriptionKey; - messagesPtr[0] = message; - return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, CFSTR(kLAErrorDomain), code, keysPtr, messagesPtr, 1); -} -#endif - -static void fillItem(CFMutableDictionaryRef item, uint32_t num) -{ - ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { - CFTypeRef value = NULL; - switch (atype) { - case kBoolItemAttr: - value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); - CFRetain(value); - break; - case kNumberItemAttr: - value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); - break; - case kStringItemAttr: - case kBlobItemAttr: - value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num); - break; - case kDataItemAttr: - { - char buf[50]; - int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num); - value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); - break; - } - case kDateItemAttr: - value = NULL; // Don't mess with dates on create. - break; - case kAccessabilityItemAttr: - { break; } - case kAccessGroupItemAttr: - { - CFStringRef accessGroups[] = { - NULL, - CFSTR("com.apple.security.sos"), // Secd internally uses this - }; - value = accessGroups[num % array_size(accessGroups)]; - break; - } - } - if (value) - CFDictionarySetValue(item, attr, value); - CFReleaseSafe(value); - }); - - CFDictionarySetValue(item, kSecValueData, (__bridge CFDataRef)[NSData dataWithBytes:"some data" length:9]); -} - -static void tests(bool isPasscodeSet) -{ - CFErrorRef (^okBlock)(void) = ^ { - return (CFErrorRef)NULL; - }; - -#if LA_CONTEXT_IMPLEMENTED - CFErrorRef (^errorNotInteractiveBlock)(void) = ^ { - return createCFError(CFSTR(""), kLAErrorNotInteractive); - }; -#endif - - CFArrayRef classArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecClassInternetPassword, kSecClassGenericPassword, kSecClassKey, kSecClassCertificate, NULL); - CFArrayRef protectionClassArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlwaysPrivate, - kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, - kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL); - - __block uint32_t pass = 0; - CFArrayForEach(classArray, ^(CFTypeRef itemClass) { - CFArrayForEach(protectionClassArray, ^(CFTypeRef protectionClass) { - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, itemClass, NULL); - fillItem(item, ++pass); - - LASetErrorCodeBlock(okBlock); - SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(aclRef, "Create SecAccessControlRef"); - ok(SecAccessControlSetProtection(aclRef, protectionClass, NULL), "Set protection"); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL), "Set operation decrypt to true"); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL), "Set operation delete to true"); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL), "Set operation encrypt to true"); - - LASetErrorCodeBlock(okBlock); - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); -#if LA_CONTEXT_IMPLEMENTED - ok_status(SecItemAdd(item, NULL), "add local "); - ok_status(SecItemCopyMatching(item, NULL), "find local"); - ok_status(SecItemDelete(item), "delete local"); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local"); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue); - is_status(SecItemAdd(item, NULL), errSecParam, "add sync"); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find sync"); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - - if(isPasscodeSet) { - SecAccessControlRef aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL); - ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction"); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef); - ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); - LASetErrorCodeBlock(errorNotInteractiveBlock); - is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI"); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "find local - acl with authentication UI"); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); - LASetErrorCodeBlock(okBlock); - ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI"); - - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); - ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); - LASetErrorCodeBlock(errorNotInteractiveBlock); - is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI"); - LASetErrorCodeBlock(okBlock); - ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI"); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); - - SecAccessControlRef aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL); - ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation"); - CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL); - ok(constraint); - ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete"); - CFReleaseSafe(constraint); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef); - ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); - LASetErrorCodeBlock(errorNotInteractiveBlock); - is_status(SecItemDelete(item), errSecInteractionNotAllowed, "delete local - acl with authentication UI"); - - if (CFEqual(protectionClass, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); - ok(changePasscode(passcode, NULL)); - LASetErrorCodeBlock(okBlock); - ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); - ok(changePasscode(NULL, passcode)); - - CFReleaseSafe(aclWithUIRef); - CFReleaseSafe(aclWithDeleteConstraintRef); - - aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); - ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction"); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef); - ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); - changePasscode(passcode, NULL); - ok_status(SecItemDelete(item), "delete local - AKPU"); - changePasscode(NULL, passcode); - - aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); - ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation"); - constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL); - ok(constraint); - ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete"); - CFReleaseSafe(constraint); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef); - ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); - changePasscode(passcode, NULL); - ok_status(SecItemDelete(item), "delete local - AKPU + prot odel"); - changePasscode(NULL, passcode); - - CFReleaseNull(aclWithUIRef); - CFReleaseNull(aclWithDeleteConstraintRef); - } - CFReleaseNull(aclWithUIRef); - CFReleaseNull(aclWithDeleteConstraintRef); - } -#endif - CFReleaseNull(item); - CFReleaseNull(aclRef); - }); - }); - - CFRelease(classArray); - CFRelease(protectionClassArray); -} - -int secd_81_item_acl_stress(int argc, char *const *argv) -{ -#if LA_CONTEXT_IMPLEMENTED - secd_test_setup_temp_keychain(__FUNCTION__, ^{ - keybag_state_t state; - int passcode_len=(int)strlen(passcode); - - ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &test_keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(test_keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(test_keybag); - }); - - bool isPasscodeSet = true; -#else - bool isPasscodeSet = false; -#endif - - plan_tests(isPasscodeSet?776:140); - - tests(isPasscodeSet); - -#if LA_CONTEXT_IMPLEMENTED - SecItemServerResetKeychainKeybag(); -#endif - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl.m b/OSX/sec/securityd/Regressions/secd-81-item-acl.m deleted file mode 100644 index c51a8aed..00000000 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl.m +++ /dev/null @@ -1,501 +0,0 @@ -// -// si-81-item-acl.c -// sec -// -// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. -// -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "secd_regressions.h" - -#if USE_KEYSTORE -#include -#include -#include "SecdTestKeychainUtilities.h" - -#include "OSX/utilities/SecAKSWrappers.h" - -#if LA_CONTEXT_IMPLEMENTED -static keybag_handle_t test_keybag; -static const char *passcode1 = "passcode1"; -static const char *passcode2 = "passcode2"; - -static bool changePasscode(const char *old_passcode, const char *new_passcode) -{ - size_t old_passcode_len = 0; - size_t new_passcode_len = 0; - - if (old_passcode) - old_passcode_len = strlen(old_passcode); - - if (new_passcode) - new_passcode_len = strlen(new_passcode); - - kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); - return status == 0; -} - -#endif -#endif - - -enum ItemAttrType { - kBoolItemAttr, - kNumberItemAttr, - kStringItemAttr, - kDataItemAttr, - kBlobItemAttr, - kDateItemAttr, - kAccessabilityItemAttr, - kAccessGroupItemAttr, -}; - -extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); - -static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { - va_list ap; - va_start(ap, each); - CFStringRef attr; - while((attr = va_arg(ap, CFStringRef)) != NULL) { - enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); - each(attr, atype); - } - va_end(ap); -} - -static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { - CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); - if (!iclass) { - return; - } else if (CFEqual(iclass, kSecClassGenericPassword)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrAccount, kStringItemAttr, - kSecAttrService, kStringItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassInternetPassword)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrAccount, kStringItemAttr, - kSecAttrSecurityDomain, kStringItemAttr, - kSecAttrServer, kStringItemAttr, - kSecAttrProtocol, kNumberItemAttr, - kSecAttrAuthenticationType, kNumberItemAttr, - kSecAttrPort, kNumberItemAttr, - kSecAttrPath, kStringItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassCertificate)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrCertificateType, kNumberItemAttr, - kSecAttrIssuer, kDataItemAttr, - kSecAttrSerialNumber, kDataItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassKey)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies - kSecAttrApplicationLabel, kDataItemAttr, - kSecAttrApplicationTag, kDataItemAttr, - kSecAttrKeyType, kNumberItemAttr, - kSecAttrKeySizeInBits, kNumberItemAttr, - kSecAttrEffectiveKeySize, kNumberItemAttr, - kSecAttrStartDate, kDateItemAttr, - kSecAttrEndDate, kDateItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } else if (CFEqual(iclass, kSecClassIdentity)) { - WithEachString(each, - kSecAttrAccessible, kAccessabilityItemAttr, - kSecAttrAccessGroup, kAccessGroupItemAttr, - kSecAttrCertificateType, kNumberItemAttr, - kSecAttrIssuer, kDataItemAttr, - kSecAttrSerialNumber, kDataItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies - kSecAttrApplicationLabel, kDataItemAttr, - kSecAttrApplicationTag, kDataItemAttr, - kSecAttrKeyType, kNumberItemAttr, - kSecAttrKeySizeInBits, kNumberItemAttr, - kSecAttrEffectiveKeySize, kNumberItemAttr, - kSecAttrStartDate, kDateItemAttr, - kSecAttrEndDate, kDateItemAttr, - kSecAttrSynchronizable, kBoolItemAttr, - NULL); - } -} - -static void fillItem(CFMutableDictionaryRef item, uint32_t num) -{ - ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { - CFTypeRef value = NULL; - switch (atype) { - case kBoolItemAttr: - value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); - CFRetain(value); - break; - case kNumberItemAttr: - value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); - break; - case kStringItemAttr: - case kBlobItemAttr: - value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num); - break; - case kDataItemAttr: - { - char buf[50]; - int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num); - value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); - break; - } - case kDateItemAttr: - value = NULL; // Don't mess with dates on create. - break; - case kAccessabilityItemAttr: - { break; } - case kAccessGroupItemAttr: - { - CFStringRef accessGroups[] = { - NULL, - CFSTR("com.apple.security.sos"), // Secd internally uses this - }; - value = accessGroups[num % array_size(accessGroups)]; - break; - } - } - if (value) - CFDictionarySetValue(item, attr, value); - CFReleaseSafe(value); - }); - - CFDictionarySetValue(item, kSecValueData, (__bridge CFDataRef)[NSData dataWithBytes:"some data" length:9]); -} - -#if LA_CONTEXT_IMPLEMENTED -CF_RETURNS_RETAINED -static CFErrorRef createCFError(CFStringRef message, CFIndex code) -{ - const void* keysPtr[1]; - const void* messagesPtr[1]; - - keysPtr[0] = kCFErrorLocalizedDescriptionKey; - messagesPtr[0] = message; - return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, CFSTR(kLAErrorDomain), code, keysPtr, messagesPtr, 1); -} - -#if TARGET_OS_IPHONE -static void set_app_password(ACMContextRef acmContext) -{ - CFDataRef appPwdData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("Application password"), kCFStringEncodingUTF8, 0); - ACMCredentialRef acmCredential = NULL; - ok_status(ACMCredentialCreate(kACMCredentialTypePassphraseEntered, &acmCredential), "Create ACM credential"); - ACMPassphrasePurpose purpose = kACMPassphrasePurposeGeneral; - ok_status(ACMCredentialSetProperty(acmCredential, kACMCredentialPropertyPassphrase, CFDataGetBytePtr(appPwdData), CFDataGetLength(appPwdData)), "Set ACM credential property - passphrase"); - ok_status(ACMCredentialSetProperty(acmCredential, kACMCredentialPropertyPassphrasePurpose, &purpose, sizeof(purpose)), "Set ACM credential property - purpose"); - ok_status(ACMContextAddCredentialWithScope(acmContext, acmCredential, kACMScopeContext), "aad ACM credential to ACM context"); - ACMCredentialDelete(acmCredential); - CFReleaseSafe(appPwdData); -} -#endif - -static void item_with_application_password(uint32_t *item_num) -{ -#if TARGET_OS_IPHONE - CFErrorRef (^okBlock)(void) = ^ { - return (CFErrorRef)NULL; - }; - - CFErrorRef (^authFailedBlock)(void) = ^ { - return createCFError(CFSTR(""), kLAErrorAuthenticationFailed); - }; - - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); - fillItem(item, (*item_num)++); - - LASetErrorCodeBlock(okBlock); - SecAccessControlRef aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlApplicationPassword, NULL); - ok(aclRef, "Create SecAccessControlRef"); - - ACMContextRef acmContext = NULL; - ok_status(ACMContextCreate(&acmContext), "Create ACM context"); - set_app_password(acmContext); - - __block CFDataRef credRefData = NULL; - ACMContextGetExternalForm(acmContext, ^(const void *externalForm, size_t dataBufferLength) { - credRefData = CFDataCreate(kCFAllocatorDefault, externalForm, dataBufferLength); - }); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - ok_status(SecItemAdd(item, NULL), "add local - acl with application password"); - ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password"); - ok_status(SecItemDelete(item), "delete local - acl with application password"); - - CFReleaseSafe(aclRef); - - LASetErrorCodeBlock(okBlock); - aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); - SecAccessControlSetRequirePassword(aclRef, true); - ok(aclRef, "Create SecAccessControlRef"); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); - ok_status(SecItemAdd(item, NULL), "add local - acl with application password and user present"); - LASetErrorCodeBlock(authFailedBlock); - CFDictionarySetValue(item, kSecReturnData, kCFBooleanTrue); - is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password and user present"); - CFDictionaryRemoveValue(item, kSecReturnData); - LASetErrorCodeBlock(okBlock); - set_app_password(acmContext); - ok_status(SecItemDelete(item), "delete local - acl with application password and user present"); - CFReleaseSafe(aclRef); - - LASetErrorCodeBlock(okBlock); - aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); - SecAccessControlSetRequirePassword(aclRef, true); - SecAccessConstraintRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR(kACMPolicyDeviceOwnerAuthentication), NULL); - SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, constraint, NULL); - CFRelease(constraint); - ok(aclRef, "Create SecAccessControlRef"); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - ok_status(SecItemAdd(item, NULL), "add local - acl with application password and user present"); - LASetErrorCodeBlock(authFailedBlock); - is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password and user present"); - set_app_password(acmContext); - is_status(SecItemDelete(item), errSecAuthFailed, "delete local - acl with application password and user present"); - - CFRelease(item); - CFReleaseSafe(aclRef); - - // Update tests for item with application password: - - // Prepare query for item without ACL. - item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); - fillItem(item, (*item_num)++); - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - - // Add test item without ACL and check that it can be found. - ok_status(SecItemAdd(item, NULL), "add local - no acl"); - ok_status(SecItemCopyMatching(item, NULL), "find local - no acl"); - - // Update test item by adding ACL with application password flag. - CFMutableDictionaryRef update = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAlwaysPrivate, kSecAccessControlApplicationPassword, NULL); - CFDictionarySetValue(update, kSecAttrAccessControl, aclRef); - set_app_password(acmContext); - CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); - LASetErrorCodeBlock(okBlock); - ok_status(SecItemUpdate(item, update), "update local - acl with application password"); - - LASetErrorCodeBlock(authFailedBlock); - ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password"); - CFDictionaryRemoveValue(item, kSecUseCredentialReference); - is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password (without ACM context)"); - CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); - ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password (with ACM context)"); - - // Try to update item with ACL with application password with the same password (it will fail because ACM context is not allowd for update attributes). - CFDictionarySetValue(update, kSecUseCredentialReference, credRefData); - LASetErrorCodeBlock(okBlock); - is_status(SecItemUpdate(item, update), errSecNoSuchAttr, "update local - add application password"); - - CFDictionaryRemoveValue(update, kSecUseCredentialReference); - LASetErrorCodeBlock(okBlock); - ok_status(SecItemUpdate(item, update), "update local - updated with the same application password"); - LASetErrorCodeBlock(authFailedBlock); - ok_status(SecItemCopyMatching(item, NULL), "find local - updated with the same application password"); // LA authFailedBlock is not called. - - CFReleaseSafe(aclRef); - // Update item with ACL without application password. - aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAlwaysPrivate, 0, NULL); - CFDictionarySetValue(update, kSecAttrAccessControl, aclRef); - - LASetErrorCodeBlock(okBlock); - ok_status(SecItemUpdate(item, update), "update local - remove application password"); - - CFDictionaryRemoveValue(item, kSecUseCredentialReference); - LASetErrorCodeBlock(authFailedBlock); - ok_status(SecItemCopyMatching(item, NULL), "find local - acl without application password"); // LA authFailedBlock is not called. - - ok_status(SecItemDelete(item), "delete local - acl without application password"); - - CFRelease(update); - CFRelease(item); - CFReleaseSafe(aclRef); - - ACMContextDelete(acmContext, true); - CFReleaseSafe(credRefData); -#endif -} - -static void item_with_invalid_acl(uint32_t *item_num) -{ - CFErrorRef (^errorParamBlock)(void) = ^ { - return createCFError(CFSTR(""), kLAErrorParameter); - }; - - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); - fillItem(item, (*item_num)++); - - SecAccessControlRef invalidAclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(invalidAclRef, "Create invalid SecAccessControlRef"); - ok(SecAccessControlSetProtection(invalidAclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL), "Set protection"); - CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("invalidPolicy"), NULL); - ok(constraint, "Create invalid constraint"); - ok(SecAccessControlAddConstraintForOperation(invalidAclRef, kAKSKeyOpDecrypt, constraint, NULL), "Add invalid constraint"); - CFReleaseSafe(constraint); - - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - CFDictionarySetValue(item, kSecAttrAccessControl, invalidAclRef); - - LASetErrorCodeBlock(errorParamBlock); - is_status(SecItemAdd(item, NULL), errSecParam, "do not add local with invalid acl"); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after add failed"); - - CFReleaseSafe(invalidAclRef); - CFRelease(item); -} - -static void item_with_acl_caused_maxauth(uint32_t *item_num) -{ - CFErrorRef (^okBlock)(void) = ^ { - return (CFErrorRef)NULL; - }; - - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); - fillItem(item, (*item_num)++); - - SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(aclRef, "Create SecAccessControlRef"); - ok(SecAccessControlSetProtection(aclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL)); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrpyt, kCFBooleanFalse, NULL)); - - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - - __security_simulatecrash_enable(false); - - LASetErrorCodeBlock(okBlock); - diag("this will cause an internal assert - on purpose"); - is_status(SecItemAdd(item, NULL), errSecAuthFailed, "max auth attempts failed"); - - is(__security_simulatecrash_enable(true), 1, "Expecting simcrash max auth threshold passed"); - - CFReleaseSafe(aclRef); - CFRelease(item); -} - -static void item_with_akpu(uint32_t *item_num) -{ - CFErrorRef (^okBlock)(void) = ^ { - return (CFErrorRef)NULL; - }; - - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassGenericPassword, NULL); - fillItem(item, (*item_num)++); - - SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); - ok(aclRef, "Create SecAccessControlRef"); - ok(SecAccessControlSetProtection(aclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL)); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrpyt, kCFBooleanTrue, NULL)); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL)); - ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL)); - - CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - - LASetErrorCodeBlock(okBlock); - ok_status(SecItemAdd(item, NULL), "add item with akpu"); - ok_status(SecItemCopyMatching(item, NULL), "find item with akpu"); - changePasscode(passcode1, NULL); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); - is_status(SecItemAdd(item, NULL), errSecNotAvailable, "cannot add item with akpu without passcode"); - changePasscode(NULL, passcode2); - is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); - ok_status(SecItemAdd(item, NULL), "add item with akpu"); - - changePasscode(passcode2, passcode1); - CFReleaseSafe(aclRef); - CFRelease(item); -} -#endif - -static void item_with_skip_auth_ui(uint32_t *item_num) -{ - CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); - fillItem(item, (*item_num)++); - - SecAccessControlRef aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlDevicePasscode, NULL); - ok(aclRef, "Create SecAccessControlRef"); - - CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); - CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip); - is_status(SecItemAdd(item, NULL), errSecParam, "add local - invalid kSecUseAuthenticationUISkip"); - is_status(SecItemDelete(item), errSecParam, "delete local - invalid kSecUseAuthenticationUISkip"); - - CFReleaseNull(aclRef); - CFRelease(item); -} - -int secd_81_item_acl(int argc, char *const *argv) -{ - uint32_t item_num = 1; -#if LA_CONTEXT_IMPLEMENTED - secd_test_setup_temp_keychain(__FUNCTION__, ^{ - keybag_state_t state; - int passcode_len=(int)strlen(passcode1); - - ok(kAKSReturnSuccess==aks_create_bag(passcode1, passcode_len, kAppleKeyStoreDeviceBag, &test_keybag), "create keybag"); - ok(kAKSReturnSuccess==aks_get_lock_state(test_keybag, &state), "get keybag state"); - ok(!(state&keybag_state_locked), "keybag unlocked"); - SecItemServerSetKeychainKeybag(test_keybag); - }); -#if TARGET_OS_IPHONE - plan_tests(70); -#else - plan_tests(29); -#endif - item_with_skip_auth_ui(&item_num); - item_with_invalid_acl(&item_num); - item_with_application_password(&item_num); - item_with_acl_caused_maxauth(&item_num); - item_with_akpu(&item_num); -#else - plan_tests(3); - item_with_skip_auth_ui(&item_num); -#endif - -#if LA_CONTEXT_IMPLEMENTED - SecItemServerResetKeychainKeybag(); -#endif - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m b/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m deleted file mode 100644 index 3d033767..00000000 --- a/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m +++ /dev/null @@ -1,72 +0,0 @@ -// -// secd-82-persistent-ref.c -// sec -// -// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. -// -// - -#include -#include -#include - -#include "secd_regressions.h" -#include "SecdTestKeychainUtilities.h" - -int secd_82_persistent_ref(int argc, char *const *argv) -{ - plan_tests(5); - - /* custom keychain dir */ - secd_test_setup_temp_keychain("secd_82_persistent_ref", NULL); - - CFMutableDictionaryRef attrs = NULL; - CFMutableDictionaryRef query = NULL; - CFDataRef data = NULL; - CFTypeRef result = NULL; - CFArrayRef array = NULL; - CFIndex i, n; - CFDictionaryRef item = NULL; - - attrs = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); - CFDictionarySetValue( attrs, kSecClass, kSecClassGenericPassword ); - CFDictionarySetValue( attrs, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate ); - CFDictionarySetValue( attrs, kSecAttrLabel, CFSTR( "TestLabel" ) ); - CFDictionarySetValue( attrs, kSecAttrDescription, CFSTR( "TestDescription" ) ); - CFDictionarySetValue( attrs, kSecAttrAccount, CFSTR( "TestAccount" ) ); - CFDictionarySetValue( attrs, kSecAttrService, CFSTR( "TestService" ) ); - data = CFDataCreate( NULL, (const uint8_t *) "\x00\x01\x02", 3 ); - CFDictionarySetValue( attrs, kSecValueData, data ); - CFReleaseNull( data ); - - is(SecItemAdd(attrs, NULL), errSecSuccess); - CFReleaseNull( attrs ); - - query = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); - CFDictionarySetValue( query, kSecClass, kSecClassGenericPassword ); - CFDictionarySetValue( query, kSecAttrSynchronizable, kSecAttrSynchronizableAny );; - CFDictionarySetValue( query, kSecAttrAccount, CFSTR( "TestAccount" ) ); - CFDictionarySetValue( query, kSecReturnAttributes, kCFBooleanTrue ); - CFDictionarySetValue( query, kSecReturnPersistentRef, kCFBooleanTrue ); - CFDictionarySetValue( query, kSecMatchLimit, kSecMatchLimitAll ); - - is(SecItemCopyMatching(query, &result), errSecSuccess); - CFReleaseNull( query ); - array = (CFArrayRef) result; - - SKIP: { - skip("No results from SecItemCopyMatching", 2, array && (CFArrayGetTypeID() == CFGetTypeID(array))); - n = CFArrayGetCount( array ); - is(n, 1); - for( i = 0; i < n; ++i ) - { - item = (CFDictionaryRef) CFArrayGetValueAtIndex(array, i); - - ok((CFDataRef) CFDictionaryGetValue(item, kSecValuePersistentRef)); - } - } - CFReleaseNull( result ); - - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m b/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m deleted file mode 100644 index 76040252..00000000 --- a/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m +++ /dev/null @@ -1,234 +0,0 @@ -// -// secd-81-item-match-policy.m -// sec - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - -#import -#import -#import -#import -#import - - -#import "secd_regressions.h" -#import "SecdTestKeychainUtilities.h" -#import "secd-83-item-match.h" - -//Test SSL SMIME2 -NSString *secdTestSMIME1BASE64String = @"MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMTELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MUBhcHBsZS5jb20wHhcNMTYwNDA3MDYzNDM0WhcNMTcwNDA3MDYzNDM0WjBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMTELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MUBhcHBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHedMsbVecoqyZwoTTE85bm3QImVz45HYFGKq/L6E5dVPamiiMRZ2BX1XnIdthbIRZhg7OU0zk2KiQKyg+bjnk+l3ZW/C6N3sAx4blq/UemOg6XtdI1Iq/HwLw5qJW8hiy9INA2nMJnSXZrnM6Ezsj92l0PQ2+8oOa95sLfi2e9NJZONESY/XNyc6tclaUYHSQR+BAzllKRorrqvpa3T2o6lmcUG+29TsRUHth6OHZLccMoA6ITk8Eq/vlAsaH4BnD7rFfBwcE/GhkkbZrmH1xaFziEIwMx3uvhsQCpspt50Pf9RWcsj3/bD4aIPUNLRkyn49ZE6MhOmMp7p5UCXapAgMBAAGjSjBIMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAeBgNVHREEFzAVgRN0ZXN0Y2VydDFAYXBwbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAm3pbBBqrzR3tTwZrjLORH72PY3f/4IvhYNadP3A70Smln0xC+BIjxqTPP1YXcvwY2PfIaNkXrxaqM8/mbR5MjiDQ7SZz5jfYTuJP6+Z9Y9nL2S/62DyhVwJcRskrDCArkaXz1b2n6yEWCw4L5uJmwdRruW5D7mF10f2GtNvGlq5Wj7csKjw6Pwh8kgG3lnGqrWaNfiJku49lbAugZr2bryQvzxi3q0Kk0LBlxVt1fMae/H/cO9nwlqe+mOclJ96zRPWnXKNMduDf00OIp131gqAknXQwSJZoI2mvX9deFdaaS21T1COhvPN+dL7D5umX85NGzoLN2svzihAhMkIK+"; -//Test SSL SMIME2 -NSString *secdTestSMIME2BASE64String = @"MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMjELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MkBhcHBsZS5jb20wHhcNMTYwNDA3MDYzNjUzWhcNMTcwNDA3MDYzNjUzWjBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMjELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MkBhcHBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk4emo4RNYI7WXtdOjFBgxIaLf80zTH0peza4PMJO7fC+KtStC4KpvRWbIhm+CcvJjpT4jpScKuHisMgfPxfEcK7jv8kRU7waAaW3H5o56YBX+Qen+fA18ulrwwzEHO4KBK7kXT9oSLy1m09u17yf46x3NPshrg0JpTh4F1jPtEK7HPZnzoJMx8i69Rd9zfddm+Gs0TPFtqaUQ9wuKeKr/Vda9kaPo98UabpiXx94sy/rtlULiUY8Nh993KUDcGPI2LTmQSeR8EB37AEoeBm8mRR9IGdZNvkDPEXIoilw1HVMsczxCEVV0HOAcFh+HfvVsWGYySentCpOe95r4/CSbAgMBAAGjSjBIMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAeBgNVHREEFzAVgRN0ZXN0Y2VydDJAYXBwbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAAVic5KfpUoy7Bu8dZ8qc+1RM/wXscK/2906/ZD7cndFSM2X7x+oRB78mtbmHlvfDC5FC5OAlxpY9S5ITtK/R67wi6LwOK3TkoQzevSqAkl8ylTfh3Sp/bwCRpVJo1yFCBdNnq4clEktu2+W6YSczjrDieN6CvhRE+AQ3sYNpxeaRJUS8PtNdPmYNnPdLK9VLB8Fg2WIHTAYV1nvai8Dvj1Fk6ukJGQxLJmXs6qUT8O+VE0CiVI5wspX+XSO/FSXiYLzFsLSRQNdWOO6U0zJlVpa1UoiRZCiVHnkDcYAMKB66hNUvRPtZYAguH7Ipg5bSld6fr8b43Vt2lkDM1iZAK"; -//Test SSL client1 -NSString *secdTestSSLClient1BASE64String = @"MIIDPTCCAiWgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBMMRkwFwYDVQQDDBBUZXN0IFNTTCBjbGllbnQxMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQzQGFwcGxlLmNvbTAeFw0xNjA0MDcwNjM5NDBaFw0xNzA0MDcwNjM5NDBaMEwxGTAXBgNVBAMMEFRlc3QgU1NMIGNsaWVudDExCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDNAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKF0N/zPBmahsQwcSrCqiUavXVLj5DEVricqEmOPd77Zr3CVf4B/zDEFqyLh2cg15WBlYV0hG8TDa49yOlJ8JZ8d58n/0A0p6Qq27/S1qc7DvpwVqSwwUl5S3DXSrVBxnJKz20Q3f2yNnHv3hJvp7dMI4C+rQK/uSy2syJalTSVUXMLjQegfv3EVBVTL8omb4Myo7HbjYhEUw/faM9NXwUNs0foR2cRvpkqJPi7r6gM/a+4T2SlSst0U+ByPgaFy2QJPPuzQSEa7vA5fmsMDSQ7BHnla1YVjloWh4LHdB32BGmjIwyHYfn5hqKl37V+oASqLeWVD1cK/2dG6nl2AmQIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEIs0r+XYOl2Tt1dcRVgTXoFT8w4xAJ7JeErhBqEbhPnQ4i/7GGnd20wL3keCLeLvIJm+KOI+OMjLft276MGn6VEN33o8GKt53m0Mz/mS36xdmAdxBu0t1dh2bnBRYh+asD2gz3AFnlUDOC5DqRZ5yz0FwK9UPpN6KqBZc0YbzS/p/cc3UkzywdAX01RTzmxqGgrl5CPruIECRSieykl7fgmqitlLnYms/QvaS963cFvIM6XJdXltbED6GkVc39ab/lXFYfkSC4Wx2LGeP5NEBqeEfLpKHFOuNVo6dks8OGXXfW14jhCRaLJi6P3kh9jfTXAvW8Fw0mGoNciTLPKTK4="; -//Test SSL client2 -NSString *secdTestSSLClient2BASE64String = @"MIIDPTCCAiWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBMMRkwFwYDVQQDDBBUZXN0IFNTTCBjbGllbnQyMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ0QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQxMDFaFw0xNzA0MDcwNjQxMDFaMEwxGTAXBgNVBAMMEFRlc3QgU1NMIGNsaWVudDIxCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDRAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAneZGoEDMw7ZdqT5jVA+omajFDixAd9HB5kaw1kUxd6MuFTn95WhLyI84oa8FvmbxGXZ2zBxtZF3hrm2xHPJB0bwpCfzR0GlaoZKbgUzvRx8x+i/+tEkbFnlOlmU1ZW7cGWyu6bI60rfPZ5VwEe6/JgFaKTRdOACxzIaYDJhS2S2LSzgrom27k424LbCWtfwaqEuiPtF3hGmuCAfrdxJ9Pr/qBcKCjkbWdrtIYhsEJzN8oLwdLduy8jM+fiAXwW1skEgIQa7Bo4zJRIsT6fG0U/0HeSESxGfghN3dBCaWGM7yB1Cahrk8pfalhs5IFmFhNy/+UtpBYhO1DGbr4ijfHQIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAFrDD3o6uG8lU1NxLa+i0zSihFDv0b3y516AScUAf6jpuW0Wfhpqb/U1Gk91Zo2ZBFtQ5WniLf4wGZRFeeUOv6PTHdkBz7PtYa/nzyXOlUBdTuZ0w52e2+mEJfCpwhR7MVBvs3QmtXpg7H/lSePbbun/tl8fYRMzcycLWH9Yrz+TluNdS9/Qa3SRgXo4JUKGl8F/nvXohuz2JyGLk43l3Cq9z68IKv7c8SA448E9d+MwwsYc2YcHf9aZAwu81aP5c3XOSaWvP3uzATxb/w6tIhs7O8iHgyq7mRy2iQqACDxpcILKGEu4advaBPmB14kSz/HUS4VahafayXxhCQPqYtc="; -//secdtest1.apple.com -NSString *secdTestSSLServer1BASE64String = @"MIIDYzCCAkugAwIBAgIBBTANBgkqhkiG9w0BAQsFADBPMRwwGgYDVQQDDBNzZWNkdGVzdDEuYXBwbGUuY29tMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ1QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQ3MThaFw0xNzA0MDcwNjQ3MThaME8xHDAaBgNVBAMME3NlY2R0ZXN0MS5hcHBsZS5jb20xCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDVAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxWOhlJjFJ+Fyp0KRCb4Dx20TMf+/gYaNwN9/i0+YNi3wb5mAepO7gN8VoZhYf+fWO6eUGzxFwggCK5b2plZ5dW/3su5B/K5onYxE7wWPsHGfw/rolpkp84fgj2aSUBQnOuwhFvot1dmFUeh55SaIv56sLw5aIbW/xWP6Mhc8kpf8ji5xpFA5JZxmbBZi4iG4E4395DD3lXE1jN4B3aY6gknnA6BYvngvxH/2whitKTDKCqsnWPxGqbJ5kg+0julkgYVEPlfdus/MNTB/c6llKiqIkwNuzPPaHq9VRNnPctEljVJcch7ZwqbluTY+AwRGXuY0RpJ9S6+uEPaQbuDX3QIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwHgYDVR0RBBcwFYITc2VjZHRlc3QxLmFwcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAfJqxsLI03nm9YSVeOqcyOB+Cj41WmNCgaSvftGmPtmz4QLbEYTYDqrv2zTvTtmS5Z1ugy6XeA4sUx9j9oKJq9+FRkfxQTDOHz7e8dqUvF0ToLPRo0dlGv55FsbVgOM8vKCeqra12FWvSUHXhUn7tC+lQDDiDs5st4NkVRgRsCYHUIfYtYBWABd5Z6kWAR33qysxbxx4cHLGb/1CCfsPF+/IQYS1sF9u+q/Jvbe6Oylyb1qxoe4dcsub4AYgS+yHItcQeZksItwYWLdAQUat7r6bbMLp+EN2DJRzrIQl+Kf3nzSKRBW6HTJR19+6D/pum0q8A0A3chsMW34rvMS469w=="; -//secdtest2.apple.com -NSString *secdTestSSLServer2BASE64String = @"MIIDYzCCAkugAwIBAgIBBjANBgkqhkiG9w0BAQsFADBPMRwwGgYDVQQDDBNzZWNkdGVzdDIuYXBwbGUuY29tMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ2QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQ1NTFaFw0xNzA0MDcwNjQ1NTFaME8xHDAaBgNVBAMME3NlY2R0ZXN0Mi5hcHBsZS5jb20xCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDZAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmI95AUYia7UATWdqAUHQGge1vK11u5CXuQm0rpvKMTwzSD/HkEX6jFnCoJ4J+3FUpeY70ZhWfnwiumGmMB6RfI3S2jIWvyrMgIRkiPhiLh5ZDmV6K/w2MVzOEiPRKPVcxgLJm8CF2/EdJnCMmJG8pvWyTwahW43WT7oAj5KdnqSCtysEZ5pOKR+U4S89x0mUuGXc6K3xVWSfM0Az2tepWc11dtuLWPSe5vCU3JuZzFfXsUqgHInWnBNjPfQrgI9LE5EIqslA5dAZLLlr4+OLCmENi6qwQ6GIvzR9S30gAk4Mo/H+RUeqqimkMD8JUL9D72FQdqcC1cFgsADbxslLgwIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwHgYDVR0RBBcwFYITc2VjZHRlc3QyLmFwcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAC3BDk+HtpO+FKmgx0BfNz4gXR3NjDoe0Ms2toC2YAzR33Z/VycBjLbQ0gfQHyGHYQPYzGgurYPypyzUqKJJVFClmj/VXaNANiFhegHPXRKPyFuw5wbxKE2tgCq3sJ+x4RbDoyGXZz+7bfvWbjynpgiXWWx1V1ABop1UByiYTWp7zVDLTEzYfVGkisr0sV3qoMrKxYBgjUJjXM6p5DeIFr8HaB6lSSqSlCek3oMBfgjEIurpU3LhcGeOn2ItFS8F3wj1YqLvxzgzn3LfPjUOENXI+Fy8lPgibiEeqAcT7//NwleuNQfYL5eGVzuAxcNG9b1NeDkG5t1RQgUL5JwP8bg=="; - -void addTestCertificates(void) { - NSData *certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSMIME1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - SecCertificateRef certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); - - certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSMIME2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); - - certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLClient1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); - - certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLClient2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); - - certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLServer1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); - - certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLServer2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); - ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); - CFRelease(certRef); -} - -static void test(id returnKeyName) { - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"]; - [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"us_EN"]]; - NSDate *validDate = [dateFormatter dateFromString: @"2016-04-07 16:00:00 GMT"]; - NSDate *dateBefore = [dateFormatter dateFromString: @"2016-04-06 16:00:00 GMT"]; - NSDate *dateAfter = [dateFormatter dateFromString: @"2017-04-08 16:00:00 GMT"]; - - CFTypeRef result = NULL; - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 6); - CFReleaseNull(result); -#if TARGET_OS_IPHONE - SecPolicyRef policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, NULL); -#else - SecPolicyRef policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES }); -#endif - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 2); - CFReleaseNull(policy); - CFReleaseNull(result); - -#if TARGET_OS_IPHONE - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ -#else - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, -#endif - (id)kSecPolicyName : @"testcert1@apple.com" }); - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 1); - CFReleaseNull(result); - - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 1); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateBefore, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateAfter, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(policy); - CFReleaseNull(result); -#if TARGET_OS_IPHONE - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, NULL); -#else - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES }); -#endif - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 2); - CFReleaseNull(policy); - CFReleaseNull(result); - -#if TARGET_OS_IPHONE - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ -#else - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, -#endif - (id)kSecPolicyName : @"secdtest1.apple.com" }); - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 1); - CFReleaseNull(result); - - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 1); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateBefore, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateAfter, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(policy); - CFReleaseNull(result); - -#if TARGET_OS_IPHONE - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ -#else - policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, -#endif - (id)kSecPolicyClient : @YES }); - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 2); - CFReleaseNull(result); - - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 2); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateBefore, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchPolicy : (__bridge id)policy, - (id)kSecMatchValidOnDate : dateAfter, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(policy); - CFReleaseNull(result); -} - -int secd_83_item_match_policy(int argc, char *const *argv) -{ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - plan_tests(103); - - @autoreleasepool { - addTestCertificates(); - NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; - for (id returnKeyName in returnKeyNames) - test(returnKeyName); - } - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-trusted.m b/OSX/sec/securityd/Regressions/secd-83-item-match-trusted.m deleted file mode 100644 index 0231610b..00000000 --- a/OSX/sec/securityd/Regressions/secd-83-item-match-trusted.m +++ /dev/null @@ -1,51 +0,0 @@ -// -// secd-83-item-match-trusted.m -// sec - - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - -#import -#import -#import -#import - - -#import "secd_regressions.h" -#import "SecdTestKeychainUtilities.h" -#import "secd-83-item-match.h" - -static void test(id returnKeyName) { - CFTypeRef result = NULL; - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 6); - CFReleaseNull(result); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchTrustedOnly : @YES, - returnKeyName : @YES }, &result), errSecItemNotFound); - CFReleaseNull(result); -} - -int secd_83_item_match_trusted(int argc, char *const *argv) -{ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - plan_tests(19); - - @autoreleasepool { - addTestCertificates(); - NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; - for (id returnKeyName in returnKeyNames) - test(returnKeyName); - } - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-valid-on-date.m b/OSX/sec/securityd/Regressions/secd-83-item-match-valid-on-date.m deleted file mode 100644 index 7922de7a..00000000 --- a/OSX/sec/securityd/Regressions/secd-83-item-match-valid-on-date.m +++ /dev/null @@ -1,68 +0,0 @@ -// -// secd-83-item-match-valid-on-date.m -// sec - -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 - -#import -#import -#import -#import - - -#import "secd_regressions.h" -#import "SecdTestKeychainUtilities.h" -#import "secd-83-item-match.h" - -static void test(id returnKeyName) { - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"]; - [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"us_EN"]]; - NSDate *validDate = [dateFormatter dateFromString: @"2016-04-07 16:00:00 GMT"]; - NSDate *dateBefore = [dateFormatter dateFromString: @"2016-04-06 16:00:00 GMT"]; - NSDate *dateAfter = [dateFormatter dateFromString: @"2017-04-08 16:00:00 GMT"]; - - CFTypeRef result = NULL; - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 6); - CFReleaseNull(result); - - ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchValidOnDate : validDate, - returnKeyName : @YES }, &result)); - ok(result && CFArrayGetCount(result) == 6); - - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchValidOnDate : dateBefore, - returnKeyName : @YES }, &result), errSecItemNotFound); - ok(result && CFArrayGetCount(result) == 6); - is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - (id)kSecMatchValidOnDate : dateAfter, - returnKeyName : @YES }, &result), errSecItemNotFound); - ok(result && CFArrayGetCount(result) == 6); -} - -int secd_83_item_match_valid_on_date(int argc, char *const *argv) -{ - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - plan_tests(39); - - @autoreleasepool { - addTestCertificates(); - NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; - for (id returnKeyName in returnKeyNames) - test(returnKeyName); - } - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match.h b/OSX/sec/securityd/Regressions/secd-83-item-match.h deleted file mode 100644 index cae87a88..00000000 --- a/OSX/sec/securityd/Regressions/secd-83-item-match.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// secd-83-item-match.h -// sec - -#ifndef secd_83_item_match_h -#define secd_83_item_match_h - -void addTestCertificates(void); - -#endif /* secd_83_item_match_h */ diff --git a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m b/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m deleted file mode 100644 index c2d4cdda..00000000 --- a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static void tests(void) -{ - CFErrorRef error = NULL; - - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); - CFReleaseNull(error); - CFReleaseSafe(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); - - withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { - CFStringAppend(timeDescription, decription); - }); - CFStringAppend(timeDescription, CFSTR("]")); - - int tries = 5; - - CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &tries); - - CFMutableArrayRef escrowTimeAndTries = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayAppendValue(escrowTimeAndTries, timeDescription); - CFArrayAppendValue(escrowTimeAndTries, attempts); - CFDictionaryRef escrowRecord = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("account label"), escrowTimeAndTries, NULL); - - CFMutableDictionaryRef record = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(record, CFSTR("12345"), escrowRecord); - - SOSFullPeerInfoRef alice_fpi = alice_account.fullPeerInfo; - ok(SOSFullPeerInfoAddEscrowRecord(alice_fpi, CFSTR("12345"), escrowRecord, &error), "Adding Escrow records to Alice FPI(%@)", error); - CFDictionaryRef fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(alice_fpi)); - ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Alice's FPI has escrow (%@)", error); - - ok(SOSAccountAddEscrowRecords(bob_account, CFSTR("12345"), escrowRecord, &error), "Adding escrow to Bob's account (%@)", error); - CFReleaseNull(fpi_escrow); - - fpi_escrow = (CFDictionaryRef)SOSAccountGetValue(bob_account, kSOSEscrowRecord, NULL); - ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); - ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); - - ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset to offering (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - ok(SOSAccountHasPublicKey(bob_account, &error), "Has Public Key" ); - - ok([bob_account.trust resetAccountToEmpty:bob_account transport:bob_account.circle_transport err:&error], "Reset to offering (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountAddEscrowRecords(bob_account, CFSTR("12345"), escrowRecord, &error), "Adding escrow to Bob's account (%@)", error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - SOSAccountTrustClassic *bobTrust = bob_account.trust; - CFDictionaryRef bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); - ok(bob_fpi_escrow == NULL, "Bob's FPI escrow should be null"); - CFReleaseNull(bob_fpi_escrow); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); - ok(bob_fpi_escrow && CFEqualSafe(CFDictionaryGetValue(bob_fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); - CFReleaseNull(bob_fpi_escrow); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - fpi_escrow = (CFDictionaryRef)SOSAccountGetValue(bob_account, kSOSEscrowRecord, NULL); - ok(isNull(fpi_escrow), "Bob's escrow records in the account object should be gone"); - - CFReleaseNull(record); - CFReleaseNull(escrowRecord); - CFReleaseNull(timeDescription); - CFReleaseNull(attempts); - SOSTestCleanup(); - -} - -int secd_95_escrow_persistence(int argc, char *const *argv) -{ - plan_tests(41); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m b/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m deleted file mode 100644 index 0eca1b36..00000000 --- a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// -// secd60-account-cloud-exposure.c -// sec -// - - - -#include -#include - -#include - -#include "keychain/SecureObjectSync/SOSAccount.h" -#include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" -#include -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static bool SOSAccountResetCircleToNastyOffering(SOSAccount* account, SecKeyRef userPriv, SOSPeerInfoRef pi, CFErrorRef *error) { - bool result = false; - SecKeyRef userPub = SecKeyCreatePublicFromPrivate(userPriv); - SOSAccountTrustClassic *trust = account.trust; - if(!SOSAccountHasCircle(account, error)){ - CFReleaseNull(userPub); - return result; - } - if(![account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error]){ - CFReleaseNull(userPub); - return result; - } - (void) [account.trust resetAllRings:account err:error]; - - [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { - bool result = false; - CFErrorRef localError = NULL; - SOSFullPeerInfoRef iCloudfpi = NULL; - - //sleep(10); - require_quiet(SOSCircleResetToEmpty(circle, error), err_out); - require_quiet([account.trust addiCloudIdentity:circle key:userPriv err:error], err_out); - require_quiet(iCloudfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, error), err_out); - - /* Add the defenders peerInfo to circle */ - require_quiet(SOSCircleRequestReadmission(circle, userPub, pi, error), err_out); - require_quiet(SOSCircleAcceptRequest(circle, userPriv, iCloudfpi, pi, error), err_out); - - [trust setDepartureCode:kSOSNeverLeftCircle]; - result = true; - SOSCircleRef copiedCircle = SOSCircleCopyCircle(kCFAllocatorDefault, circle, error); // I don't think this copy is necessary, but... - [trust setTrustedCircle:copiedCircle]; - CFReleaseNull(copiedCircle); - SOSAccountPublishCloudParameters(account, NULL); - trust.fullPeerInfo = nil; - - err_out: - if (result == false) { - secerror("error resetting circle (%@) to offering: %@", circle, localError); - } - if (localError && error && *error == NULL) { - *error = localError; - localError = NULL; - } - - CFReleaseNull(iCloudfpi); - CFReleaseNull(localError); - return result; - }]; - - result = true; - - return result; -} - -static bool SOSAccountResetToNastyOffering(SOSAccount* account, SOSPeerInfoRef pi, CFErrorRef* error) { - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - if (!user_key) - return false; - - SOSAccountTrustClassic* trust = account.trust; - trust.fullPeerInfo = nil; - - return user_key && SOSAccountResetCircleToNastyOffering(account, user_key, pi, error); -} - -static bool performiCloudIdentityAttack(SOSAccount* attacker, SOSAccount* defender, SOSAccount* accomplice, CFMutableDictionaryRef changes) { - CFErrorRef error = NULL; - bool retval = false; // false means the attack succeeds - CFArrayRef applicants = NULL; - SOSAccountTrustClassic* defenderTrust = defender.trust; - - /*----- Carole makes bogus circle with fake iCloud identity and Alice's peerInfo but only signed with fake iCloud identity -----*/ - - require_action_quiet(SOSAccountResetToNastyOffering(attacker, defenderTrust.peerInfo, &error), testDone, retval = true); - CFReleaseNull(error); - - ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); - - /*----- Now use our fake iCloud identity to get in to the circle for real -----*/ - require_action_quiet(SOSAccountJoinCirclesAfterRestore_wTxn(attacker, &error), testDone, retval = true); - CFReleaseNull(error); - require_action_quiet(countPeers(attacker) == 2, testDone, retval = true); - - /*----- Let's see if carole can get bob into the circle and have alice believe it -----*/ - require_action_quiet(SOSAccountJoinCircles_wTxn(accomplice, &error), testDone, retval = true); - CFReleaseNull(error); - - ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); - - applicants = SOSAccountCopyApplicants(attacker, &error); - CFReleaseNull(error); - - if(CFArrayGetCount(applicants) > 0) { - require_action_quiet(SOSAccountAcceptApplicants(attacker, applicants, &error), testDone, retval = true); - } - - ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); - - require_action_quiet(countPeers(defender) == 3, testDone, retval = true); - require_action_quiet(countPeers(accomplice) == 3, testDone, retval = true); - require_action_quiet(countPeers(attacker) == 3, testDone, retval = true); - -testDone: - CFReleaseNull(applicants); - CFReleaseNull(error); - return retval; -} - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - - ok(performiCloudIdentityAttack(carole_account, alice_account, bob_account, changes), "Attack is defeated"); - - CFReleaseNull(cfpassword); - alice_account = nil; - bob_account = nil; - SOSTestCleanup(); -} - -int secd_60_account_cloud_exposure(int argc, char *const *argv) -{ - plan_tests(41); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m b/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m deleted file mode 100644 index a23cdabb..00000000 --- a/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m +++ /dev/null @@ -1,296 +0,0 @@ -// -// secd_77_ids_messaging.c -// sec -// - -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include - -#include -#include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" -#import "SOSTransportTestTransports.h" -#include "SOSTestDevice.h" -#include "SOSTestDataSource.h" -#include -#include - -static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { - SOSAccountTrustClassic* trust = account.trust; - SOSPeerInfoRef mypi = trust.peerInfo; - CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); - - return myPeerID && CFEqualSafe(myPeerID, peerID); -} - -__unused static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){ - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - __block bool SyncingCompletedOverIDS = false; - __block CFErrorRef localError = NULL; - __block bool done = false; - SOSAccountTrustClassic* aliceTrust = alice_account.trust; - SOSAccountTrustClassic* bobTrust = bob_account.trust; - - do{ - SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { - if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ - secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); - - CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - - SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError]; - CFReleaseNull(ids); - } - } - }); - - ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); - - SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { - if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ - secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); - - CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - - SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; - CFReleaseNull(ids); - } - } - }); - - ok(SyncingCompletedOverIDS, "synced items over IDS"); - if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)bob_account.ids_message_transport)) == 0){ - done = true; - break; - } - - ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); - - }while(done == false); - CFReleaseNull(changes); -} - -static void tests() -{ - CFErrorRef error = NULL; - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef dsName = CFSTR("Test"); - - SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), dsName); - SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), dsName); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - CFReleaseNull(error); - - ok(NULL != alice_account, "Alice Created"); - ok(NULL != bob_account, "Bob Created"); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - //creating test devices - CFIndex version = 0; - - // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); - CFSetRef views = SOSViewsCopyTestV2Default(); - CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFStringRef deviceID; - CFArrayForEachC(deviceIDs, deviceID) { - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); - CFArrayAppendValue(peerMetas, peerMeta); - CFReleaseNull(peerMeta); - } - - CFReleaseNull(views); - CFArrayForEachC(deviceIDs, deviceID) { - SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); - SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - - if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ - alice_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); - } - else{ - bob_account.factory = device->dsf; - SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); - } - - CFReleaseNull(device); - } - CFReleaseNull(deviceIDs); - CFReleaseNull(peerMetas); - - SOSUnregisterAllTransportMessages(); - CFArrayRemoveAllValues(message_transports); - - SOSAccountTrustClassic* aliceTrust = alice_account.trust; - SOSAccountTrustClassic* bobTrust = bob_account.trust; - - alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error ]; - - bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; - - ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); - ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); - - bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { - CFErrorRef localError = NULL; - - SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - - return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); - }]; - - ok(result, "Alice account update circle with transport type"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { - CFErrorRef localError = NULL; - - SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - - return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); - }]; - - ok(result, "Bob account update circle with transport type"); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - - CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); - CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); - ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); - ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); - - CFReleaseNull(alice_transportType); - CFReleaseNull(bob_accountTransportType); - - SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); - ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); - ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); - ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - - ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); - CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); - ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); - - ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); - CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); - ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - - - ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); - - ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); - - - //ids_test_sync(alice_account, bob_account); - - CFReleaseNull(bob_dsid); - CFReleaseNull(alice_dsid); - CFReleaseNull(changes); - - SOSTestCleanup(); -} - -int secd_77_ids_messaging(int argc, char *const *argv) -{ - plan_tests(100); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd_regressions.h b/OSX/sec/securityd/Regressions/secd_regressions.h deleted file mode 100644 index d3de4a06..00000000 --- a/OSX/sec/securityd/Regressions/secd_regressions.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include "OSX/sec/Security/SecItemShim.h" - -ONE_TEST(secd_01_items) -ONE_TEST(secd_02_upgrade_while_locked) -ONE_TEST(secd_03_corrupted_items) -DISABLED_ONE_TEST(secd_04_corrupted_items) -ONE_TEST(secd_05_corrupted_items) -ONE_TEST(secd_20_keychain_upgrade) -ONE_TEST(secd_21_transmogrify) -DISABLED_ONE_TEST(secd_30_keychain_upgrade) //obsolete, needs updating -DISABLED_ONE_TEST(secd_31_keychain_unreadable) -OFF_ONE_TEST(secd_32_restore_bad_backup) -ONE_TEST(secd_33_keychain_ctk) -ONE_TEST(secd_33_keychain_backup) -ONE_TEST(secd_35_keychain_migrate_inet) -ONE_TEST(secd_36_ks_encrypt) -ONE_TEST(secd_37_pairing_initial_sync) -ONE_TEST(secd_40_cc_gestalt) -ONE_TEST(secd_50_account) -ONE_TEST(secd_49_manifests) -ONE_TEST(secd_50_message) -ONE_TEST(secd_51_account_inflate) -ONE_TEST(secd_52_account_changed) -ONE_TEST(secd_52_offering_gencount_reset) -DISABLED_ONE_TEST(secd_55_account_circle) -ONE_TEST(secd_55_account_incompatibility) -ONE_TEST(secd_56_account_apply) -ONE_TEST(secd_57_account_leave) -ONE_TEST(secd_57_1_account_last_standing) -ONE_TEST(secd_58_password_change) -ONE_TEST(secd_59_account_cleanup) -ONE_TEST(secd_60_account_cloud_identity) -ONE_TEST(secd_60_account_cloud_exposure) -ONE_TEST(secd_61_account_leave_not_in_kansas_anymore) -ONE_TEST(secd_62_account_backup) -ONE_TEST(secd_63_account_resurrection) -ONE_TEST(secd_64_circlereset) -ONE_TEST(secd_65_account_retirement_reset) -ONE_TEST(secd_66_account_recovery) -ONE_TEST(secd_67_prefixedKeyIDs) -ONE_TEST(secd_70_engine) -ONE_TEST(secd_70_engine_corrupt) -ONE_TEST(secd_70_engine_smash) -ONE_TEST(secd_71_engine_save) -ONE_TEST(secd_68_ghosts) -ONE_TEST(secd_155_otr_negotiation_monitor) - -DISABLED_ONE_TEST(secd_70_otr_remote) -ONE_TEST(secd_74_engine_beer_servers) -OFF_ONE_TEST(secd_75_engine_views) -ONE_TEST(secd_80_views_basic) -ONE_TEST(secd_80_views_alwayson) -#if TARGET_IPHONE_SIMULATOR -OFF_ONE_TEST(secd_81_item_acl_stress) -OFF_ONE_TEST(secd_81_item_acl) -#else -ONE_TEST(secd_81_item_acl_stress) -ONE_TEST(secd_81_item_acl) -#endif -ONE_TEST(secd_82_persistent_ref) -ONE_TEST(secd_83_item_match_policy) -ONE_TEST(secd_83_item_match_valid_on_date) -ONE_TEST(secd_83_item_match_trusted) -ONE_TEST(secd_95_escrow_persistence) -ONE_TEST(secd_154_engine_backoff) -ONE_TEST(secd_100_initialsync) -ONE_TEST(secd_130_other_peer_views) -ONE_TEST(secd_156_timers) -ONE_TEST(secd_200_logstate) -ONE_TEST(secd_201_coders) -ONE_TEST(secd_202_recoverykey) -ONE_TEST(secd_210_keyinterest) -DISABLED_ONE_TEST(secd_230_keybagtable) -#if TARGET_OS_OSX -ONE_TEST(sc_25_soskeygen) -#endif - diff --git a/OSX/sec/securityd/Regressions/securityd_regressions.h b/OSX/sec/securityd/Regressions/securityd_regressions.h deleted file mode 100644 index 0135bbb8..00000000 --- a/OSX/sec/securityd/Regressions/securityd_regressions.h +++ /dev/null @@ -1,7 +0,0 @@ -/* To add a test: - 1) add it here - 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes - */ -#include - -ONE_TEST(sd_10_policytree) diff --git a/OSX/sec/securityd/SFKeychainControlManager.h b/OSX/sec/securityd/SFKeychainControlManager.h deleted file mode 100644 index 52f06c67..00000000 --- a/OSX/sec/securityd/SFKeychainControlManager.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include - -XPC_RETURNS_RETAINED _Nullable xpc_endpoint_t SecServerCreateKeychainControlEndpoint(void); - -#ifdef __OBJC__ - -#import "SFKeychainControl.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SFKeychainControlManager : NSObject - -+ (instancetype)sharedManager; - -- (NSArray*)findCorruptedItemsWithError:(NSError**)error; -- (bool)deleteCorruptedItemsWithError:(NSError**)error; - -- (nullable xpc_endpoint_t)xpcControlEndpoint; - -NS_ASSUME_NONNULL_END - -@end - -#endif diff --git a/OSX/sec/securityd/SFKeychainControlManager.m b/OSX/sec/securityd/SFKeychainControlManager.m deleted file mode 100644 index 89e1ae5c..00000000 --- a/OSX/sec/securityd/SFKeychainControlManager.m +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SFKeychainControlManager.h" -#import "SecCFError.h" -#import "builtin_commands.h" -#import "debugging.h" -#import -#import -#import - -NSString* kSecEntitlementKeychainControl = @"com.apple.private.keychain.keychaincontrol"; - -XPC_RETURNS_RETAINED xpc_endpoint_t SecServerCreateKeychainControlEndpoint(void) -{ - return [[SFKeychainControlManager sharedManager] xpcControlEndpoint]; -} - -@implementation SFKeychainControlManager { - NSXPCListener* _listener; -} - -+ (instancetype)sharedManager -{ - static SFKeychainControlManager* manager = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - manager = [[SFKeychainControlManager alloc] _init]; - }); - - return manager; -} - -- (instancetype)_init -{ - if (self = [super init]) { - _listener = [NSXPCListener anonymousListener]; - _listener.delegate = self; - [_listener resume]; - } - - return self; -} - -- (xpc_endpoint_t)xpcControlEndpoint -{ - return [_listener.endpoint _endpoint]; -} - -- (BOOL)listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection -{ - NSNumber* entitlementValue = [newConnection valueForEntitlement:kSecEntitlementKeychainControl]; - if (![entitlementValue isKindOfClass:[NSNumber class]] || !entitlementValue.boolValue) { - secerror("SFKeychainControl: Client pid (%d) doesn't have entitlement: %@", newConnection.processIdentifier, kSecEntitlementKeychainControl); - return NO; - } - - NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainControl)]; - [interface setClass:[NSError class] forSelector:@selector(rpcFindCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES]; - [interface setClass:[NSError class] forSelector:@selector(rpcDeleteCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES]; - newConnection.exportedInterface = interface; - newConnection.exportedObject = self; - [newConnection resume]; - return YES; -} - -- (NSArray*)findCorruptedItemsWithError:(NSError**)error -{ - NSMutableArray* corruptedItems = [[NSMutableArray alloc] init]; - NSMutableArray* underlyingErrors = [[NSMutableArray alloc] init]; - - CFTypeRef genericPasswords = NULL; - NSDictionary* genericPasswordsQuery = @{ (id)kSecClass : (id)kSecClassGenericPassword, - (id)kSecReturnPersistentRef : @(YES), - (id)kSecUseDataProtectionKeychain : @(YES), - (id)kSecMatchLimit : (id)kSecMatchLimitAll }; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordsQuery, &genericPasswords); - CFErrorRef genericPasswordError = NULL; - if (status != errSecItemNotFound) { - SecError(status, &genericPasswordError, CFSTR("generic password query failed")); - if (genericPasswordError) { - [underlyingErrors addObject:CFBridgingRelease(genericPasswordError)]; - } - } - - CFTypeRef internetPasswords = NULL; - NSDictionary* internetPasswordsQuery = @{ (id)kSecClass : (id)kSecClassInternetPassword, - (id)kSecReturnPersistentRef : @(YES), - (id)kSecUseDataProtectionKeychain : @(YES), - (id)kSecMatchLimit : (id)kSecMatchLimitAll }; - status = SecItemCopyMatching((__bridge CFDictionaryRef)internetPasswordsQuery, &internetPasswords); - CFErrorRef internetPasswordError = NULL; - if (status != errSecItemNotFound) { - SecError(status, &internetPasswordError, CFSTR("internet password query failed")); - if (internetPasswordError) { - [underlyingErrors addObject:CFBridgingRelease(internetPasswordError)]; - } - } - - CFTypeRef keys = NULL; - NSDictionary* keysQuery = @{ (id)kSecClass : (id)kSecClassKey, - (id)kSecReturnPersistentRef : @(YES), - (id)kSecUseDataProtectionKeychain : @(YES), - (id)kSecMatchLimit : (id)kSecMatchLimitAll }; - status = SecItemCopyMatching((__bridge CFDictionaryRef)keysQuery, &keys); - CFErrorRef keyError = NULL; - if (status != errSecItemNotFound) { - if (keyError) { - [underlyingErrors addObject:CFBridgingRelease(keyError)]; - } - } - - CFTypeRef certificates = NULL; - NSDictionary* certificateQuery = @{ (id)kSecClass : (id)kSecClassCertificate, - (id)kSecReturnPersistentRef : @(YES), - (id)kSecUseDataProtectionKeychain : @(YES), - (id)kSecMatchLimit : (id)kSecMatchLimitAll }; - status = SecItemCopyMatching((__bridge CFDictionaryRef)certificateQuery, &certificates); - CFErrorRef certificateError = NULL; - if (status != errSecItemNotFound) { - SecError(status, &certificateError, CFSTR("certificate query failed")); - if (certificateError) { - [underlyingErrors addObject:CFBridgingRelease(certificateError)]; - } - } - - void (^scanArrayForCorruptedItem)(CFTypeRef, NSString*) = ^(CFTypeRef items, NSString* class) { - if ([(__bridge NSArray*)items isKindOfClass:[NSArray class]]) { - NSLog(@"scanning %d %@", (int)CFArrayGetCount(items), class); - for (NSData* persistentRef in (__bridge NSArray*)items) { - NSDictionary* itemQuery = @{ (id)kSecClass : class, - (id)kSecValuePersistentRef : persistentRef, - (id)kSecReturnAttributes : @(YES), - (id)kSecUseDataProtectionKeychain : @(YES) }; - CFTypeRef itemAttributes = NULL; - OSStatus copyStatus = SecItemCopyMatching((__bridge CFDictionaryRef)itemQuery, &itemAttributes); - if (copyStatus != errSecSuccess && status != errSecInteractionNotAllowed) { - [corruptedItems addObject:itemQuery]; - } - } - } - }; - - scanArrayForCorruptedItem(genericPasswords, (id)kSecClassGenericPassword); - scanArrayForCorruptedItem(internetPasswords, (id)kSecClassInternetPassword); - scanArrayForCorruptedItem(keys, (id)kSecClassKey); - scanArrayForCorruptedItem(certificates, (id)kSecClassCertificate); - - if (underlyingErrors.count > 0 && error) { - *error = [NSError errorWithDomain:@"com.apple.security.keychainhealth" code:1 userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"encountered %d errors searching for corrupted items", (int)underlyingErrors.count], NSUnderlyingErrorKey : underlyingErrors.firstObject, @"searchingErrorCount" : @(underlyingErrors.count) }]; - } - - return corruptedItems; -} - -- (bool)deleteCorruptedItemsWithError:(NSError**)error -{ - NSError* findError = nil; - NSArray* corruptedItems = [self findCorruptedItemsWithError:&findError]; - bool success = findError == nil; - - NSMutableArray* deleteErrors = [[NSMutableArray alloc] init]; - for (NSDictionary* corruptedItem in corruptedItems) { - OSStatus status = SecItemDelete((__bridge CFDictionaryRef)corruptedItem); - if (status != errSecSuccess) { - success = false; - CFErrorRef deleteError = NULL; - SecError(status, &deleteError, CFSTR("failed to delete corrupted item")); - [deleteErrors addObject:CFBridgingRelease(deleteError)]; - } - } - - if (error && (findError || deleteErrors.count > 0)) { - *error = [NSError errorWithDomain:@"com.apple.security.keychainhealth" code:2 userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"encountered %@ errors searching for corrupted items and %d errors attempting to delete corrupted items", findError.userInfo[@"searchingErrorCount"], (int)deleteErrors.count]}]; - } - - return success; -} - -- (void)rpcFindCorruptedItemsWithReply:(void (^)(NSArray* corruptedItems, NSError* error))reply -{ - NSError* error = nil; - NSArray* corruptedItems = [self findCorruptedItemsWithError:&error]; - reply(corruptedItems, error); -} - -- (void)rpcDeleteCorruptedItemsWithReply:(void (^)(bool success, NSError* error))reply -{ - NSError* error = nil; - bool success = [self deleteCorruptedItemsWithError:&error]; - reply(success, error); -} - -@end diff --git a/OSX/sec/securityd/SFKeychainServer.h b/OSX/sec/securityd/SFKeychainServer.h deleted file mode 100644 index 771384cb..00000000 --- a/OSX/sec/securityd/SFKeychainServer.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import - -#define kSFKeychainServerServiceName "com.apple.security.sfkeychainserver" - -#if !TARGET_OS_BRIDGE && __OBJC2__ - -#import -#import -#import "SecCDKeychain.h" - -@interface SFKeychainServer : NSObject - -- (instancetype)initWithStorageURL:(NSURL*)persistentStoreURL modelURL:(NSURL*)managedObjectURL encryptDatabase:(bool)encryptDatabase; - -@end - -@interface SecCDKeychainItemTypeCredential : SecCDKeychainItemType -@end - -@interface SFKeychainServerConnection : NSObject - -@property (readonly) NSArray* clientAccessGroups; - -@end - -#endif // !TARGET_OS_BRIDGE && __OBJC2__ - -void SFKeychainServerInitialize(void); diff --git a/OSX/sec/securityd/SFKeychainServer.m b/OSX/sec/securityd/SFKeychainServer.m deleted file mode 100644 index fb9c07b2..00000000 --- a/OSX/sec/securityd/SFKeychainServer.m +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SFKeychainServer.h" -#import - -#if !TARGET_OS_BRIDGE -#if __OBJC2__ - -#import "SecCDKeychain.h" -#import "SecFileLocations.h" -#import "debugging.h" -#import "CloudKitCategories.h" -#import "SecAKSWrappers.h" -#include "securityd_client.h" -#import "server_entitlement_helpers.h" -#import "SecTask.h" -#import "keychain/categories/NSError+UsefulConstructors.h" -#import "SecEntitlements.h" -#import -#import -#import -#import -#import - -static NSString* const SFKeychainItemAttributeLocalizedLabel = @"label"; -static NSString* const SFKeychainItemAttributeLocalizedDescription = @"description"; - -static NSString* const SFCredentialAttributeUsername = @"username"; -static NSString* const SFCredentialAttributePrimaryServiceIdentifier = @"primaryServiceID"; -static NSString* const SFCredentialAttributeSupplementaryServiceIdentifiers = @"supplementaryServiceIDs"; -static NSString* const SFCredentialAttributeCreationDate = @"creationDate"; -static NSString* const SFCredentialAttributeModificationDate = @"modificationDate"; -static NSString* const SFCredentialAttributeCustom = @"customAttributes"; -static NSString* const SFCredentialSecretPassword = @"password"; - -@interface SFCredential (securityd_only) - -- (instancetype)_initWithUsername:(NSString*)username primaryServiceIdentifier:(SFServiceIdentifier*)primaryServiceIdentifier supplementaryServiceIdentifiers:(nullable NSArray*)supplementaryServiceIdentifiers; - -@end - -@interface SFKeychainServerConnection () - -- (instancetype)initWithKeychain:(SecCDKeychain*)keychain xpcConnection:(NSXPCConnection*)connection; - -@end - -@implementation SecCDKeychainItemTypeCredential - -+ (instancetype)itemType -{ - static SecCDKeychainItemTypeCredential* itemType = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - itemType = [[self alloc] _initWithName:@"Credential" version:1 primaryKeys:@[SFCredentialAttributeUsername, SFCredentialAttributePrimaryServiceIdentifier] syncableKeys:nil]; - }); - - return itemType; -} - -@end - -@implementation SFKeychainServer { - SecCDKeychain* _keychain; -} - -- (instancetype)initWithStorageURL:(NSURL*)persistentStoreURL modelURL:(NSURL*)managedObjectURL encryptDatabase:(bool)encryptDatabase -{ - if (self = [super init]) { - _keychain = [[SecCDKeychain alloc] initWithStorageURL:persistentStoreURL modelURL:managedObjectURL encryptDatabase:encryptDatabase]; - } - - return self; -} - -- (BOOL)listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection -{ - NSNumber* keychainDenyEntitlement = [newConnection valueForEntitlement:(__bridge NSString*)kSecEntitlementKeychainDeny]; - if ([keychainDenyEntitlement isKindOfClass:[NSNumber class]] && keychainDenyEntitlement.boolValue == YES) { - secerror("SFKeychainServer: connection denied due to entitlement %@", kSecEntitlementKeychainDeny); - return NO; - } - - // wait a bit for shared function from SecurityFoundation to get to SDK, then addopt that - NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainServerProtocol)]; - [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFServiceIdentifier class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:NO]; - [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFPasswordCredential class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:YES]; - newConnection.exportedInterface = interface; - newConnection.exportedObject = [[SFKeychainServerConnection alloc] initWithKeychain:_keychain xpcConnection:newConnection]; - [newConnection resume]; - return YES; -} - -- (SecCDKeychain*)_keychain -{ - return _keychain; -} - -@end - -@implementation SFKeychainServerConnection { - SecCDKeychain* _keychain; - NSArray* _clientAccessGroups; -} - -@synthesize clientAccessGroups = _clientAccessGroups; - -- (instancetype)initWithKeychain:(SecCDKeychain*)keychain xpcConnection:(NSXPCConnection*)connection -{ - if (self = [super init]) { - _keychain = keychain; - - SecTaskRef task = SecTaskCreateWithAuditToken(NULL, connection.auditToken); - if (task) { - _clientAccessGroups = (__bridge_transfer NSArray*)SecTaskCopyAccessGroups(task); - } - CFReleaseNull(task); - } - - return self; -} - -- (keyclass_t)keyclassForAccessPolicy:(SFAccessPolicy*)accessPolicy -{ - if (accessPolicy.accessibility.mode == SFAccessibleAfterFirstUnlock) { - if (accessPolicy.sharingPolicy == SFSharingPolicyThisDeviceOnly) { - return key_class_cku; - } - else { - return key_class_ck; - } - } - else { - if (accessPolicy.sharingPolicy == SFSharingPolicyThisDeviceOnly) { - return key_class_aku; - } - else { - return key_class_ak; - } - } -} - -- (void)rpcAddCredential:(SFCredential*)credential withAccessPolicy:(SFAccessPolicy*)accessPolicy reply:(void (^)(NSString* persistentIdentifier, NSError* error))reply -{ - if (![credential isKindOfClass:[SFPasswordCredential class]]) { - reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidParameter userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"attempt to add credential to SFCredentialStore that is not a password credential: %@", credential]}]); - return; - } - - NSString* accessGroup = accessPolicy.accessGroup; - if (!accessGroup) { - NSError* error = nil; - accessGroup = self.clientAccessGroups.firstObject; - if (!accessGroup) { - error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorMissingAccessGroup userInfo:@{NSLocalizedDescriptionKey : @"no keychain access group found; ensure that your process has the keychain-access-groups entitlement"}]; - reply(nil, error); - return; - } - } - - SFPasswordCredential* passwordCredential = (SFPasswordCredential*)credential; - - NSError* error = nil; - NSData* primaryServiceIdentifierData = [NSKeyedArchiver archivedDataWithRootObject:passwordCredential.primaryServiceIdentifier requiringSecureCoding:YES error:&error]; - if (!primaryServiceIdentifierData) { - dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ - reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSaveFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to serialize primary service identifier", NSUnderlyingErrorKey : error }]); - }); - return; - } - - NSMutableArray* serializedSupplementaryServiceIdentifiers = [[NSMutableArray alloc] initWithCapacity:passwordCredential.supplementaryServiceIdentifiers.count]; - for (SFServiceIdentifier* serviceIdentifier in passwordCredential.supplementaryServiceIdentifiers) { - NSData* serviceIdentifierData = [NSKeyedArchiver archivedDataWithRootObject:serviceIdentifier requiringSecureCoding:YES error:&error]; - if (serviceIdentifierData) { - [serializedSupplementaryServiceIdentifiers addObject:serviceIdentifierData]; - } - else { - dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ - reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSaveFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to serialize supplementary service identifier", NSUnderlyingErrorKey : error }]); - }); - return; - } - } - - NSDictionary* attributes = @{ SFCredentialAttributeUsername : passwordCredential.username, - SFCredentialAttributePrimaryServiceIdentifier : primaryServiceIdentifierData, - SFCredentialAttributeSupplementaryServiceIdentifiers : serializedSupplementaryServiceIdentifiers, - SFCredentialAttributeCreationDate : [NSDate date], - SFCredentialAttributeModificationDate : [NSDate date], - SFKeychainItemAttributeLocalizedLabel : passwordCredential.localizedLabel, - SFKeychainItemAttributeLocalizedDescription : passwordCredential.localizedDescription, - SFCredentialAttributeCustom : passwordCredential.customAttributes ?: [NSDictionary dictionary] }; - - NSDictionary* secrets = @{ SFCredentialSecretPassword : passwordCredential.password }; - NSUUID* persistentID = [NSUUID UUID]; - - // lookup attributes: - // 1. primaryServiceIdentifier (always) - // 2. username (always) - // 3. label (if present) - // 4. description (if present) - // 5. each of the service identifiers by type, e.g. "domain" - // 6. any custom attributes that fit the requirements (key is string, and value is plist type) - - SecCDKeychainLookupTuple* primaryServiceIdentifierLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFCredentialAttributePrimaryServiceIdentifier value:primaryServiceIdentifierData]; - SecCDKeychainLookupTuple* usernameLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFCredentialAttributeUsername value:passwordCredential.username]; - SecCDKeychainLookupTuple* labelLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFKeychainItemAttributeLocalizedLabel value:passwordCredential.localizedLabel]; - SecCDKeychainLookupTuple* descriptionLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFKeychainItemAttributeLocalizedDescription value:passwordCredential.localizedDescription]; - NSMutableArray* lookupAttributes = [[NSMutableArray alloc] initWithObjects:primaryServiceIdentifierLookup, usernameLookup, nil]; - if (labelLookup) { - [lookupAttributes addObject:labelLookup]; - } - if (descriptionLookup) { - [lookupAttributes addObject:descriptionLookup]; - } - - SFServiceIdentifier* primaryServiceIdentifier = credential.primaryServiceIdentifier; - [lookupAttributes addObject:[SecCDKeychainLookupTuple lookupTupleWithKey:primaryServiceIdentifier.lookupKey value:primaryServiceIdentifier.serviceID]]; - for (SFServiceIdentifier* serviceIdentifier in credential.supplementaryServiceIdentifiers) { - [lookupAttributes addObject:[SecCDKeychainLookupTuple lookupTupleWithKey:serviceIdentifier.lookupKey value:serviceIdentifier.serviceID]]; - } - - [passwordCredential.customAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* customKey, id value, BOOL* stop) { - if ([customKey isKindOfClass:[NSString class]]) { - SecCDKeychainLookupTuple* lookupTuple = [SecCDKeychainLookupTuple lookupTupleWithKey:customKey value:value]; - if (lookupTuple) { - [lookupAttributes addObject:lookupTuple]; - } - else { - // TODO: an error here? - } - } - }]; - - SecCDKeychainAccessControlEntity* owner = [SecCDKeychainAccessControlEntity accessControlEntityWithType:SecCDKeychainAccessControlEntityTypeAccessGroup stringRepresentation:accessGroup]; - keyclass_t keyclass = [self keyclassForAccessPolicy:accessPolicy]; - SecCDKeychainItem* item = [[SecCDKeychainItem alloc] initItemType:[SecCDKeychainItemTypeCredential itemType] withPersistentID:persistentID attributes:attributes lookupAttributes:lookupAttributes secrets:secrets owner:owner keyclass:keyclass]; - [_keychain insertItems:@[item] withConnection:self completionHandler:^(bool success, NSError* insertError) { - if (success && !insertError) { - reply(persistentID.UUIDString, nil); - } - else { - reply(nil, insertError); - } - }]; -} - -- (void)rpcFetchPasswordCredentialForPersistentIdentifier:(NSString*)persistentIdentifier reply:(void (^)(SFPasswordCredential* credential, NSString* password, NSError* error))reply -{ - // TODO: negative testing - NSUUID* persistentID = [[NSUUID alloc] initWithUUIDString:persistentIdentifier]; - if (!persistentID) { - secerror("SFKeychainServer: attempt to fetch credential with invalid persistent identifier; %@", persistentIdentifier); - reply(nil, nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidPersistentIdentifier userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"invalid persistent identifier: %@", persistentIdentifier]}]); - return; - } - - [_keychain fetchItemForPersistentID:persistentID withConnection:self completionHandler:^(SecCDKeychainItem* item, NSError* error) { - NSError* localError = error; - SFPasswordCredential* credential = nil; - if (item && !error) { - credential = [self passwordCredentialForItem:item error:&localError]; - } - - if (credential) { - reply(credential, credential.password, nil); - } - else { - reply(nil, nil, localError); - } - }]; -} - -- (void)rpcLookupCredentialsForServiceIdentifiers:(nullable NSArray*)serviceIdentifiers reply:(void (^)(NSArray* _Nullable results, NSError* _Nullable error))reply -{ - __block NSMutableDictionary* resultsDict = [[NSMutableDictionary alloc] init]; - __block NSError* resultError = nil; - - void (^processFetchedItems)(NSArray*) = ^(NSArray* fetchedItems) { - for (SecCDKeychainItemMetadata* item in fetchedItems) { - if ([item.itemType isKindOfClass:[SecCDKeychainItemTypeCredential class]]) { - SFPasswordCredential* credential = [self passwordCredentialForItemMetadata:item error:&resultError]; - if (credential) { - resultsDict[item.persistentID] = credential; - } - else { - resultsDict = nil; // got an error - } - } - } - }; - - if (!serviceIdentifiers) { - // TODO: lookup everything - } - else { - for (SFServiceIdentifier* serviceIdentifier in serviceIdentifiers) { - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - // TODO: this is lamé; make fetchItemsWithValue take an array and get rid of the semaphore crap - [_keychain fetchItemsWithValue:serviceIdentifier.serviceID forLookupKey:serviceIdentifier.lookupKey ofType:SecCDKeychainLookupValueTypeString withConnection:self completionHandler:^(NSArray* items, NSError* error) { - if (items && !error) { - processFetchedItems(items); - } - else { - resultsDict = nil; - resultError = error; - } - - dispatch_semaphore_signal(semaphore); - }]; - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); - } - } - - reply(resultsDict.allValues, resultError); -} - -- (void)rpcRemoveCredentialWithPersistentIdentifier:(NSString*)persistentIdentifier reply:(void (^)(BOOL success, NSError* _Nullable error))reply -{ - NSUUID* persistentID = [[NSUUID alloc] initWithUUIDString:persistentIdentifier]; - if (!persistentID) { - secerror("SFKeychainServer: attempt to remove credential with invalid persistent identifier; %@", persistentIdentifier); - reply(false, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidPersistentIdentifier userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"invalid persistent identifier: %@", persistentIdentifier]}]); - return; - } - - [_keychain deleteItemWithPersistentID:persistentID withConnection:self completionHandler:^(bool success, NSError* error) { - reply(success, error); - }]; -} - -- (void)rpcReplaceOldCredential:(SFCredential*)oldCredential withNewCredential:(SFCredential*)newCredential reply:(void (^)(NSString* newPersistentIdentifier, NSError* _Nullable error))reply -{ - // TODO: implement - reply(nil, nil); -} - -- (SFPasswordCredential*)passwordCredentialForItem:(SecCDKeychainItem*)item error:(NSError**)error -{ - SFPasswordCredential* credential = [self passwordCredentialForItemMetadata:item.metadata error:error]; - if (credential) { - credential.password = item.secrets[SFCredentialSecretPassword]; - if (!credential.password) { - if (error) { - *error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{NSLocalizedDescriptionKey : @"failed to get password for SFCredential"}]; - } - return nil; - } - } - - return credential; -} - -- (SFPasswordCredential*)passwordCredentialForItemMetadata:(SecCDKeychainItemMetadata*)metadata error:(NSError**)error -{ - NSDictionary* attributes = metadata.attributes; - NSString* username = attributes[SFCredentialAttributeUsername]; - - NSError* localError = nil; - SFServiceIdentifier* primaryServiceIdentifier = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFServiceIdentifier class] fromData:attributes[SFCredentialAttributePrimaryServiceIdentifier] error:&localError]; - - NSArray* serializedSupplementaryServiceIdentifiers = attributes[SFCredentialAttributeSupplementaryServiceIdentifiers]; - NSMutableArray* supplementaryServiceIdentifiers = [[NSMutableArray alloc] initWithCapacity:serializedSupplementaryServiceIdentifiers.count]; - for (NSData* serializedServiceIdentifier in serializedSupplementaryServiceIdentifiers) { - if ([serializedServiceIdentifier isKindOfClass:[NSData class]]) { - SFServiceIdentifier* serviceIdentifier = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFServiceIdentifier class] fromData:serializedServiceIdentifier error:&localError]; - if (serviceIdentifier) { - [supplementaryServiceIdentifiers addObject:serviceIdentifier]; - } - else { - supplementaryServiceIdentifiers = nil; - break; - } - } - else { - supplementaryServiceIdentifiers = nil; - localError = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{NSLocalizedDescriptionKey : @"malformed supplementary service identifiers array in SecCDKeychainItem"}]; - break; - } - } - - if (username && primaryServiceIdentifier && supplementaryServiceIdentifiers) { - SFPasswordCredential* credential = [[SFPasswordCredential alloc] _initWithUsername:username primaryServiceIdentifier:primaryServiceIdentifier supplementaryServiceIdentifiers:supplementaryServiceIdentifiers]; - credential.creationDate = attributes[SFCredentialAttributeCreationDate]; - credential.modificationDate = attributes[SFCredentialAttributeModificationDate]; - credential.localizedLabel = attributes[SFKeychainItemAttributeLocalizedLabel]; - credential.localizedDescription = attributes[SFKeychainItemAttributeLocalizedDescription]; - credential.persistentIdentifier = metadata.persistentID.UUIDString; - credential.customAttributes = attributes[SFCredentialAttributeCustom]; - return credential; - } - else { - if (error) { - *error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to deserialize SFCredential", NSUnderlyingErrorKey : localError }]; - } - return nil; - } -} - -@end - -#endif // ___OBJC2__ - -void SFKeychainServerInitialize(void) -{ - static dispatch_once_t once; - static SFKeychainServer* server; - static NSXPCListener* listener; - - dispatch_once(&once, ^{ - @autoreleasepool { - NSURL* persistentStoreURL = (__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"CDKeychain"); - NSBundle* resourcesBundle = [NSBundle bundleWithPath:@"/System/Library/Keychain/KeychainResources.bundle"]; - NSURL* managedObjectModelURL = [resourcesBundle URLForResource:@"KeychainModel" withExtension:@"momd"]; - server = [[SFKeychainServer alloc] initWithStorageURL:persistentStoreURL modelURL:managedObjectModelURL encryptDatabase:true]; - listener = [[NSXPCListener alloc] initWithMachServiceName:@(kSFKeychainServerServiceName)]; - listener.delegate = server; - [listener resume]; - } - }); -} - -#else // !TARGET_OS_BRIDGE - -void SFKeychainServerInitialize(void) {} - -#endif - diff --git a/OSX/sec/securityd/SOSCloudCircleServer.h b/OSX/sec/securityd/SOSCloudCircleServer.h deleted file mode 100644 index 581c87b0..00000000 --- a/OSX/sec/securityd/SOSCloudCircleServer.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef _SECURITY_SOSCLOUDCIRCLESERVER_H_ -#define _SECURITY_SOSCLOUDCIRCLESERVER_H_ - -#import -#include "keychain/SecureObjectSync/SOSRing.h" -#import -#import - -__BEGIN_DECLS - -// -// MARK: Server versions of our SPI -// -bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error); -bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error); -bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error); -bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error); - -bool SOSCCCanAuthenticate_Server(CFErrorRef *error); -bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error); - -SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error); -bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error); -bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); -bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error); -bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); - -bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error); -bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); -bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error); -bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error); -bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error); -bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error); -bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error); - - -bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error); -bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error); -SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error); -CF_RETURNS_RETAINED CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error); -bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error); - - -CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error); -bool SOSCCValidateUserPublic_Server(CFErrorRef* error); - -CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error); -bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error); -bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error); - -SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error); - -CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error); -CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error); -bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error); -bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error); -bool SOSCCAccountSetToNew_Server(CFErrorRef *error); -bool SOSCCResetToOffering_Server(CFErrorRef* error); -bool SOSCCResetToEmpty_Server(CFErrorRef* error); -bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); - -CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error); - -SOSViewResultCode SOSCCView_Server(CFStringRef view, SOSViewActionCode action, CFErrorRef *error); -bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent); -bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews); - -CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error); -enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error); -bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error); - -bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error); - -CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error); -SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error); - -SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error); -bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef backupSlice, bool setupV0Only, CFErrorRef *error); - -bool SOSCCWaitForInitialSync_Server(CFErrorRef*); -bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); -CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef*); - -bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error); - -SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error); -CF_RETURNS_RETAINED CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error); - -// -// MARK: Internal kicks. -// -CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates); - - -// Expected to be called when the data source changes. -void SOSCCRequestSyncWithPeer(CFStringRef peerID); -void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs); -void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs); -void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId); -bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error); - -void SOSCCEnsurePeerRegistration(void); -typedef void (^SOSAccountSyncablePeersBlock)(CFArrayRef trustedPeers, CFArrayRef addedPeers, CFArrayRef removedPeers); - -dispatch_queue_t SOSCCGetAccountQueue(void); - -CFTypeRef GetSharedAccountRef(void); // returns SOSAccount* but this header is imported by C files, so we cast through CFTypeRef - -// -// MARK: Internal access to local account for tests. -// -CFTypeRef SOSKeychainAccountGetSharedAccount(void); -// -// MARK: Internal SPIs for testing -// - -void SOSCCSetGestalt_Server(CFStringRef name, CFStringRef version, CFStringRef model, CFStringRef serial); -CFStringRef SOSCCCopyOSVersion(void); -CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error); -CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error); -bool SOSCCDeleteEngineState_Server(CFErrorRef* error); -bool SOSCCDeleteAccountState_Server(CFErrorRef* error); - - -// -// MARK: Testing operations, dangerous to call in normal operation. -// -bool SOSKeychainSaveAccountDataAndPurge(CFErrorRef *error); - -// -// MARK: Constants for where we store persistent information in the keychain -// - -extern CFStringRef kSOSAccountLabel; -extern CFStringRef kSOSPeerDataLabel; - -CFDataRef SOSItemCopy(CFStringRef label, CFErrorRef* error); -bool SOSItemUpdateOrAdd(CFStringRef label, CFStringRef accessibility, CFDataRef data, CFErrorRef *error); - -bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error); -CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error); -bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error); -CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error); - -CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error); - -SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error); -CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error); -bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); -CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error); -bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error); - -bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error); -bool SOSCCAccountIsNew_Server(CFErrorRef *error); -bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error); - -void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization); - -bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); -bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); - -void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivKey, CFErrorRef error)); -void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error)); -void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error)); -void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error)); -void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error)); -void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error)); -void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error)); -void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey, - CFDataRef signingPublicKey, CFDataRef encryptionPublicKey, - SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef, - void (^action)(CFErrorRef error)); - -void SOSCCResetOTRNegotiation_Server(CFStringRef peerid); -void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup); - -__END_DECLS - -#endif diff --git a/OSX/sec/securityd/SOSCloudCircleServer.m b/OSX/sec/securityd/SOSCloudCircleServer.m deleted file mode 100644 index dafc9991..00000000 --- a/OSX/sec/securityd/SOSCloudCircleServer.m +++ /dev/null @@ -1,2568 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include - -#import "keychain/SecureObjectSync/SOSAccountTransaction.h" - -#include -#include -#include - -#include "keychain/SecureObjectSync/SOSCircle.h" -#include "keychain/SecureObjectSync/SOSAccount.h" -#include "keychain/SecureObjectSync/SOSAccountPriv.h" -#include "keychain/SecureObjectSync/SOSAccountGhost.h" - -#include "keychain/SecureObjectSync/SOSTransport.h" -#include "keychain/SecureObjectSync/SOSFullPeerInfo.h" -#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" -#include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" -#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" -#include "keychain/SecureObjectSync/SOSInternal.h" -#include "keychain/SecureObjectSync/SOSUserKeygen.h" -#include "keychain/SecureObjectSync/SOSMessage.h" -#include "keychain/SecureObjectSync/SOSBackupInformation.h" -#include "keychain/SecureObjectSync/SOSDataSource.h" -#include "keychain/SecureObjectSync/SOSKVSKeys.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" -#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" -#import "keychain/SecureObjectSync/SOSAuthKitHelpers.h" -#import "keychain/ot/OTManager.h" -#import "NSError+UsefulConstructors.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include - -#if TARGET_OS_IPHONE -#include -#else -#include -#endif - -#define SOSCKCSCOPE "sync" -#define RUN_AS_ROOT_ERROR 550 - -#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -#import - -#include - -static int64_t getTimeDifference(time_t start); -CFStringRef const SOSAggdSyncCompletionKey = CFSTR("com.apple.security.sos.synccompletion"); -CFStringRef const SOSAggdSyncTimeoutKey = CFSTR("com.apple.security.sos.timeout"); - -typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(void); - -static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL; - - - -// -// Forward declared -// - -static void do_with_account(void (^action)(SOSAccountTransaction* txn)); - -// -// Constants -// - -CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data"); - -CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count"); - -CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date"); - -static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData) -{ - return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrService, service, - kSecAttrAccessGroup, kSOSInternalAccessGroup, - kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse, - NULL); -} - -CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error) -{ - CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true); - - CFDataRef result = NULL; - - OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result); - - CFReleaseNull(query); - - if (copyResult != noErr) { - SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service); - CFReleaseNull(result); - return NULL; - } - - if (!isData(result)) { - SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service); - CFReleaseNull(result); - return NULL; - } - - return result; -} - -static CFDataRef SOSKeychainCopySavedAccountData() -{ - CFErrorRef error = NULL; - CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error); - if (!accountData) { - secnotice("account", "Failed to load account: %@", error); - secerror("Failed to load account: %@", error); - } - CFReleaseNull(error); - - return accountData; -} - -bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error) -{ - CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false); - - CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecValueData, data, - kSecAttrAccessible, accessibility, - NULL); - OSStatus saveStatus = SecItemUpdate(query, update); - - if (errSecItemNotFound == saveStatus) { - CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query); - CFDictionaryForEach(update, ^(const void *key, const void *value) { - CFDictionaryAddValue(add, key, value); - }); - saveStatus = SecItemAdd(add, NULL); - CFReleaseNull(add); - } - - CFReleaseNull(query); - CFReleaseNull(update); - - return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service); -} - -static void SOSKeychainAccountEnsureSaved(CFDataRef accountAsData) -{ - static CFDataRef sLastSavedAccountData = NULL; - - CFErrorRef saveError = NULL; - require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit); - - if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, accountAsData, &saveError)) { - secerror("Can't save account: %@", saveError); - goto exit; - } - - CFAssignRetained(sLastSavedAccountData, CFRetainSafe(accountAsData)); - -exit: - CFReleaseNull(saveError); -} - -static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt) -{ - secdebug("account", "Created account"); - - CFDataRef savedAccount = SOSKeychainCopySavedAccountData(); - SOSAccount* account = NULL; - - SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride() - : SecItemDataSourceFactoryGetDefault(); - - require_quiet(factory, done); - - if (savedAccount) { - NSError* inflationError = NULL; - - account = [SOSAccount accountFromData:(__bridge NSData*) savedAccount - factory:factory - error:&inflationError]; - - if (account){ - [account.trust updateGestalt:account newGestalt:our_gestalt]; - } else { - secerror("Got error inflating account: %@", inflationError); - } - - } - CFReleaseNull(savedAccount); - - if (!account) { - account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory); - - if (!account) - secerror("Got NULL creating account"); - } - -done: - CFReleaseNull(savedAccount); - return account; -} - -// -// Mark: Gestalt Handling -// - -CFStringRef SOSGestaltVersion = NULL; -CFStringRef SOSGestaltModel = NULL; -CFStringRef SOSGestaltDeviceName = NULL; - -void -SOSCCSetGestalt_Server(CFStringRef deviceName, - CFStringRef version, - CFStringRef model, - CFStringRef serial) -{ - SOSGestaltDeviceName = CFRetainSafe(deviceName); - SOSGestaltVersion = CFRetainSafe(version); - SOSGestaltModel = CFRetainSafe(model); - SOSGestaltSerial = CFRetainSafe(serial); -} - -CFStringRef SOSCCCopyOSVersion(void) -{ - static dispatch_once_t once; - dispatch_once(&once, ^{ - if (SOSGestaltVersion == NULL) { - CFDictionaryRef versions = _CFCopySystemVersionDictionary(); - if (versions) { - CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey); - if (isString(versionValue)) - SOSGestaltVersion = CFRetainSafe((CFStringRef) versionValue); - } - - CFReleaseNull(versions); - if (SOSGestaltVersion == NULL) { - SOSGestaltVersion = CFSTR("Unknown model"); - } - } - }); - return CFRetainSafe(SOSGestaltVersion); -} - - -static CFStringRef CopyModelName(void) -{ - static dispatch_once_t once; - dispatch_once(&once, ^{ - if (SOSGestaltModel == NULL) { -#if TARGET_OS_IPHONE - SOSGestaltModel = MGCopyAnswer(kMGQDeviceName, NULL); -#else - SOSGestaltModel = ASI_CopyComputerModelName(FALSE); -#endif - if (SOSGestaltModel == NULL) - SOSGestaltModel = CFSTR("Unknown model"); - } - }); - return CFStringCreateCopy(kCFAllocatorDefault, SOSGestaltModel); -} - -static CFStringRef CopyComputerName(SCDynamicStoreRef store) -{ - if (SOSGestaltDeviceName == NULL) { - CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL); - if (deviceName == NULL) { - deviceName = CFSTR("Unknown name"); - } - return deviceName; - } - return SOSGestaltDeviceName; -} - -static bool _EngineMessageProtocolV2Enabled(void) -{ -#if DEBUG - //sudo rhr - static dispatch_once_t onceToken; - static bool v2_enabled = false; - dispatch_once(&onceToken, ^{ - CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - - if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) { - v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref); - secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled"); - } - CFReleaseSafe(v2Pref); - }); - - return v2_enabled; -#else - return false; -#endif -} - - -static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context) -{ - CFStringRef modelName = CopyModelName(); - CFStringRef computerName = CopyComputerName(store); - CFStringRef osVersion = SOSCCCopyOSVersion(); - - SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0; - CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version); - - CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kPIUserDefinedDeviceNameKey, computerName, - kPIDeviceModelNameKey, modelName, - kPIMessageProtocolVersionKey, protocolVersion, - kPIOSVersionKey, osVersion, - NULL); - CFReleaseSafe(osVersion); - CFReleaseSafe(modelName); - CFReleaseSafe(computerName); - CFReleaseSafe(protocolVersion); - - return gestalt; -} - -static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context) -{ - do_with_account(^(SOSAccountTransaction* txn) { - if(txn.account){ - CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context); - if ([txn.account.trust updateGestalt:txn.account newGestalt:gestalt]) { - secnotice("circleOps", "Changed our peer's gestalt information. This is not a circle change."); - } - CFReleaseSafe(gestalt); - } - }); -} - - -static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info) -{ - SCDynamicStoreContext context = { .info = info }; - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context); - CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL); - CFArrayRef keys = NULL; - CFDictionaryRef gestalt = NULL; - - if (store == NULL || computerKey == NULL) { - goto done; - } - keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks); - if (keys == NULL) { - goto done; - } - gestalt = CreateDeviceGestaltDictionary(store, keys, info); - SCDynamicStoreSetNotificationKeys(store, keys, NULL); - SCDynamicStoreSetDispatchQueue(store, queue); - -done: - if (store) CFRelease(store); - if (computerKey) CFRelease(computerKey); - if (keys) CFRelease(keys); - return gestalt; -} - -os_state_block_t accountStateBlock = ^os_state_data_t(os_state_hints_t hints) { - os_state_data_t retval = NULL; - CFDataRef savedAccount = NULL; - if(hints->osh_api != OS_STATE_API_REQUEST) return NULL; - - /* Get account DER */ - savedAccount = SOSKeychainCopySavedAccountData(); - require_quiet(savedAccount, errOut); - - /* make a os_state_data_t object to return. */ - size_t statelen = CFDataGetLength(savedAccount); - retval = (os_state_data_t)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen)); - require_quiet(retval, errOut); - - retval->osd_type = OS_STATE_DATA_PROTOCOL_BUFFER; - memcpy(retval->osd_data, CFDataGetBytePtr(savedAccount), statelen); - retval->osd_size = statelen; - strlcpy(retval->osd_title, "CloudCircle Account Object", sizeof(retval->osd_title)); - -errOut: - CFReleaseNull(savedAccount); - return retval; -}; - -#define FOR_EXISTING_ACCOUNT 1 -#define CREATE_ACCOUNT_IF_NONE 0 - -static SOSAccount* GetSharedAccount(bool onlyIfItExists) { - static SOSAccount* sSharedAccount = NULL; - static dispatch_once_t onceToken; - -#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - if(geteuid() == 0){ - secerror("Cannot inflate account object as root"); - return NULL; - } -#endif - - if(onlyIfItExists) { - return sSharedAccount; - } - - dispatch_once(&onceToken, ^{ - secdebug("account", "Account Creation start"); - - CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - - if (!gestalt) { -#if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR - gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); -#else - secerror("Didn't get machine gestalt! This is going to be ugly."); -#endif - } - - sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt); - - SOSAccountAddChangeBlock(sSharedAccount, ^(SOSAccount *account, SOSCircleRef circle, - CFSetRef peer_additions, CFSetRef peer_removals, - CFSetRef applicant_additions, CFSetRef applicant_removals) { - CFErrorRef pi_error = NULL; - SOSPeerInfoRef me = account.peerInfo; - if(!me) { - secinfo("circleOps", "Change block called with no peerInfo"); - return; - } - - if(!SOSCircleHasPeer(circle, me, NULL)) { - secinfo("circleOps", "Change block called while not in circle"); - return; - } - - // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer. - if (CFSetGetCount(peer_additions) != 0) { - secnotice("updates", "Requesting Ensure Peer Registration."); - SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - } else { - secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed"); - } - - if (CFSetContainsValue(peer_additions, me)) { - // TODO: Potentially remove from here and move this to the engine - // TODO: We also need to do this when our views change. - CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault); - CFSetRemoveValue(peers, me); - if (!CFSetIsEmpty(peers)) { - SOSCCRequestSyncWithPeers(peers); - } - CFReleaseNull(peers); - } - - CFReleaseNull(pi_error); - - if (CFSetGetCount(peer_additions) != 0 || - CFSetGetCount(peer_removals) != 0 || - CFSetGetCount(applicant_additions) != 0 || - CFSetGetCount(applicant_removals) != 0) { - - if(CFSetGetCount(peer_removals) != 0) - { - CFErrorRef localError = NULL; - CFMutableArrayRef removed = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetForEach(peer_removals, ^(const void *value) { - CFArrayAppendValue(removed, value); - }); - SOSAccountRemoveBackupPeers(account, removed, &localError); - if(localError) - secerror("Had trouble removing: %@, error: %@", removed, localError); - CFReleaseNull(localError); - CFReleaseNull(removed); - } - secnotice("circleOps", "peer counts changed, posting kSOSCCCircleChangedNotification"); - account.notifyCircleChangeOnExit = true; - } - }); - - SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) { - CFRetainSafe(changes); - __block CFMutableArrayRef handledKeys = NULL; - do_with_account(^(SOSAccountTransaction* txn) { - CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false); - secdebug(SOSCKCSCOPE, "Received: %@", changeDescription); - CFReleaseSafe(changeDescription); - - CFErrorRef error = NULL; - handledKeys = SOSTransportDispatchMessages(txn, changes, &error); - if (!handledKeys || error) { - secerror("Error handling updates: %@", error); - } - CFReleaseNull(error); - }); - CFReleaseSafe(changes); - return handledKeys; - }); - CFReleaseSafe(gestalt); - - sSharedAccount.saveBlock = ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) { - if (flattenedAccount) { - SOSKeychainAccountEnsureSaved(flattenedAccount); - } else { - secerror("Failed to transform account into data, error: %@", flattenFailError); - } - }; - // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call - SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - - // provide state handler to sysdiagnose and logging - os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock); - - [sSharedAccount ghostBustSchedule]; - - }); - - return sSharedAccount; -} - -CFTypeRef GetSharedAccountRef(void) -{ - return (__bridge CFTypeRef)GetSharedAccount(FOR_EXISTING_ACCOUNT); -} - -static void do_with_account(void (^action)(SOSAccountTransaction* txn)) { - @autoreleasepool { - SOSAccount* account = GetSharedAccount(CREATE_ACCOUNT_IF_NONE); - - if(account){ - [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - action(txn); - }]; - } - } -} - -static bool isValidUser(CFErrorRef* error) { -#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - if(geteuid() == 0){ - secerror("Cannot inflate account object as root"); - SOSErrorCreate(kSOSErrorUnsupported, error, NULL, CFSTR("Cannot inflate account object as root")); - return false; - } -#endif - - return true; -} - -static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action) -{ -#if TARGET_OS_SIMULATOR - action(); - return true; -#else - bool beenUnlocked = false; - require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail); - - require_action_quiet(beenUnlocked, fail, - SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL, - CFSTR("Keybag never unlocked, ask after first unlock"))); - - action(); - - return true; - -fail: - return false; -#endif -} - -static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) -{ - __block bool action_result = false; - - return isValidUser(error) && do_if_after_first_unlock(error, ^{ - do_with_account(^(SOSAccountTransaction* txn) { - action_result = action(txn, error); - }); - - }) && action_result; -} - -static bool isAssertionLockAcquireError(CFErrorRef error) { - return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain)); -} - -static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) -{ - bool result = false; - - CFErrorRef statusError = NULL; - - __block bool action_result = false; - __block bool attempted_action = false; - __block CFErrorRef localError = NULL; - - - if(!isValidUser(error)){ - if (error && !*error && localError) { - CFTransferRetained(*error, localError); - } - CFReleaseNull(localError); - CFReleaseNull(statusError); - - return result; - } - - result = SecAKSDoWithUserBagLockAssertion(&localError, ^{ - // SOSAccountGhostBustingOptions need to be retrieved from RAMP while not holding the account queue - // yet we only want to request RAMP info if it's "time" to ghostbust. - -#if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX) - __block bool ghostbustnow = false; - __block SOSAccountGhostBustingOptions gbOptions = 0; - - // Avoid mutual deadlock for just checking date. - SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT); - if(tmpAccount && [tmpAccount isInCircle:(NULL)]) { - if(tmpAccount.settings) { - ghostbustnow = [tmpAccount ghostBustCheckDate]; - } - - if(ghostbustnow) { - gbOptions = [SOSAccount ghostBustGetRampSettings]; - } - } - -#endif - - do_with_account(^(SOSAccountTransaction* txn) { - SOSAccount *account = txn.account; - if ([account isInCircle:(NULL)] && [SOSAuthKitHelpers accountIsHSA2]) { - if(![SOSAuthKitHelpers peerinfoHasMID: account]) { - // This is the first good opportunity to update our FullPeerInfo and - // push the resulting circle. - [SOSAuthKitHelpers updateMIDInPeerInfo: account]; - } - } -#if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX) - if(ghostbustnow) { - [account ghostBustPeriodic:gbOptions complete:^(bool ghostBusted, NSError *error) { - secnotice("ghostbust", "GhostBusting: %@", ghostBusted ? CFSTR("true"): CFSTR("false")); - }]; - } -#endif - attempted_action = true; - action_result = action(txn, error); - }); - }); - - - - // For 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked - // If we fail with an error attempting to get an assertion while someone else has one and the system is unlocked, it must be trying to lock. - // we assume our caller will hold the lock assertion for us to finsh our job. - // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again. - - if(result || !isAssertionLockAcquireError(localError)){ - if (error && !*error && localError) { - CFTransferRetained(*error, localError); - } - CFReleaseNull(localError); - CFReleaseNull(statusError); - - return (result && action_result); - } - if(attempted_action){ - if (error && !*error && localError) { - CFTransferRetained(*error, localError); - } - CFReleaseNull(localError); - CFReleaseNull(statusError); - - return (result && action_result); - } - - bool isUnlocked = false; - (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError); - if(!isUnlocked){ - secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError); - if (error && !*error && localError) { - CFTransferRetained(*error, localError); - } - CFReleaseNull(localError); - CFReleaseNull(statusError); - - return result && action_result; - } - - CFReleaseNull(localError); - - secnotice("while-unlocked-hack", "Trying action while unlocked without assertion"); - - result = true; - do_with_account(^(SOSAccountTransaction* txn) { - action_result = action(txn, &localError); - }); - - secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError); - - if (error && !*error && localError) { - CFTransferRetained(*error, localError); - } - CFReleaseNull(localError); - CFReleaseNull(statusError); - - return result && action_result; -} - - - -CFTypeRef SOSKeychainAccountGetSharedAccount() -{ - __block SOSAccount* result = NULL; - result = GetSharedAccount(FOR_EXISTING_ACCOUNT); - - if(!result) { - secnotice("secAccount", "Failed request for account object"); - } - return (__bridge CFTypeRef)result; -} - -// -// Mark: Credential processing -// - - -SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) { - __block SOSViewResultCode status = kSOSCCGeneralViewError; - - do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - bool retval = false; - - switch(action) { - case kSOSCCViewQuery: - status = [txn.account.trust viewStatus:txn.account name:viewname err:error]; - retval = true; - break; - case kSOSCCViewEnable: - status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; - retval = true; - break; - - case kSOSCCViewDisable: - status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; - retval = true; - break; - default: - secnotice("views", "Bad SOSViewActionCode - %d", (int) action); - retval = false; - break; - } - return retval; - }); - return status; -} - -bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) { - __block bool status = false; - - do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent]; - return true; - }); - return status; -} - - -bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) { - return SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, NULL); -} - - -void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){ - - dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - - secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait"); - - SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { - if (sync_error) { - secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error); - } else { - secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues); - } - - dispatch_semaphore_signal(wait_for); - }); - - if(waitForeverForSynchronization) - dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - else - dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC)); - - wait_for = nil; -} - -#define kWAIT2MINID "EFRESH" - -static bool SyncKVSAndWait(CFErrorRef *error) { - dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - - __block bool success = false; - - secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait"); - - os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { - SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) { - secnotice("fresh", "EFP returned, callback error: %@", sync_error); - - success = (sync_error == NULL); - if (error) { - CFRetainAssign(*error, sync_error); - } - - dispatch_semaphore_signal(wait_for); - }); - - - dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL); - }); - - return success; -} - -static bool Flush(CFErrorRef *error) { - __block bool success = false; - - dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - secnotice("flush", "Starting"); - - SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { - success = (sync_error == NULL); - if (error) { - CFRetainAssign(*error, sync_error); - } - - dispatch_semaphore_signal(wait_for); - }); - - dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - - secnotice("flush", "Returned %s", success? "Success": "Failure"); - - return success; -} - -bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { - secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label); - - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { - SOSAccountAssertDSID(txn.account, dsid); - } - return true; - }); - - require_quiet(result, done); - - require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has - require_quiet(Flush(error), done); // And processed it already...before asserting - - result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { - return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error); - }); - - require_quiet(result, done); - require_quiet(Flush(error), done); - -done: - return result; -} - -static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { - secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); - - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { - SOSAccountAssertDSID(txn.account, dsid); - } - return true; - }); - - require_quiet(result, done); - - require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has - require_quiet(Flush(error), done); // And processed it already...before asserting - - result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { - return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); - }); - - require_quiet(result, done); - require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature - - result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountGenerationSignatureUpdate(txn.account, error); - }); - - secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", - dsid, user_label, result, error ? *error : NULL); -done: - return result; -} - -static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) { - secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); - - NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; - - SFSignInAnalytics *syncAndWaitEvent = nil; - SFSignInAnalytics *flushEvent = nil; - SFSignInAnalytics *secondFlushEvent = nil; - SFSignInAnalytics *generationSignatureUpdateEvent = nil; - - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { - SOSAccountAssertDSID(txn.account, dsid); - } - return true; - }); - - require_quiet(result, done); - syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"]; - require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has - [syncAndWaitEvent stopWithAttributes:nil]; - - flushEvent = [parent newSubTaskForEvent:@"flushEvent"]; - require_quiet(Flush(error), done); // And processed it already...before asserting - [flushEvent stopWithAttributes:nil]; - - result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { - return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); - }); - - require_quiet(result, done); - secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"]; - require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature - [secondFlushEvent stopWithAttributes:nil]; - - generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; - result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountGenerationSignatureUpdate(txn.account, error); - }); - [generationSignatureUpdateEvent stopWithAttributes:nil]; - - -done: - if(syncAndWaitEvent){ - [syncAndWaitEvent stopWithAttributes:nil]; - } - if(flushEvent){ - [flushEvent stopWithAttributes:nil]; - } - if(secondFlushEvent){ - [secondFlushEvent stopWithAttributes:nil]; - } - if(generationSignatureUpdateEvent){ - [generationSignatureUpdateEvent stopWithAttributes:nil]; - } - secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", - dsid, user_label, result, error ? *error : NULL); - - return result; -} - -bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) -{ - // TODO: Return error if DSID is NULL to insist our callers provide one? - return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error); -} - -bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error) -{ - return SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error); -} -bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error) -{ - return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error); -} - -bool SOSCCCanAuthenticate_Server(CFErrorRef *error) -{ - bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet. - // - SOSAccountRestartPrivateCredentialTimer(txn.account); - return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL; - }); - - if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) { - CFIndex code = CFErrorGetCode(*error); - if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) { - CFReleaseNull(*error); - } - } - - return result; -} - -bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error) -{ - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSAccountPurgePrivateCredential(txn.account); - return true; - }); -} - -SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error) -{ - __block SOSCCStatus status; - - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - status = [txn.account getCircleStatus:block_error]; - - return true; - }) ? status : kSOSCCError; -} - -bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) -{ - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountJoinCircles(txn, block_error); - return result; - }); -} - -bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) -{ - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); - return result; - }); -} - -bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) -{ - __block bool result = true; - __block CFErrorRef localError = NULL; - - bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountHasPublicKey(txn.account, &localError); - return result; - }); - - if(error != NULL && localError != NULL) - *error = localError; - - return hasPublicKey; -} - -bool SOSCCAccountIsNew_Server(CFErrorRef *error) -{ - __block bool result = true; - __block CFErrorRef localError = NULL; - - (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountIsNew(txn.account, &localError); - return result; - }); - - if(error != NULL && localError != NULL) - *error = localError; - - return result; -} -bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) -{ - __block bool result = true; - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSAccountEnsurePeerRegistration(txn.account, block_error); - result = SOSAccountJoinCirclesAfterRestore(txn, block_error); - return result; - }); - return returned; - -} - -bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) -{ - __block bool result = true; - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; - - SFSignInAnalytics *ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"]; - SOSAccountEnsurePeerRegistration(txn.account, block_error); - if(block_error && *block_error){ - NSError* blockError = (__bridge NSError*)*block_error; - if(blockError){ - [ensurePeerRegistrationEvent logRecoverableError:blockError]; - secerror("ensure peer registration error: %@", blockError); - } - } - [ensurePeerRegistrationEvent stopWithAttributes:nil]; - result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); - return result; - }); - return returned; - -} - -bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error) -{ - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SyncKVSAndWait(block_error); - }); - if (returned) { - returned = Flush(error); - } - return returned; -} - -bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){ - __block bool result = true; - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; - SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; - - if(fpi && ring) { - result = SOSRingApply(ring, txn.account.accountKey, fpi , error); - } - CFReleaseNull(ring); - return result; - }); - return returned; -} - -bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){ - __block bool result = true; - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; - SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; - if(fpi && ring) { - result = SOSRingWithdraw(ring, txn.account.accountKey, fpi , error); - } - CFReleaseNull(ring); - return result; - }); - return returned; -} - -bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){ - __block bool result = true; - bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; - SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; - if(fpi && ring) { - result = SOSRingResetToOffering(ring, NULL, fpi, error); - } - CFReleaseNull(ring); - return result; - }); - return returned; -} - -CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){ - __block CFMutableDictionaryRef result = NULL; - __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); - - (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - SOSAccountForEachRing(txn.account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { - CFStringAppendFormat(description, NULL, CFSTR("%@\n"), ring); - return NULL; - }); - if(result) - return true; - return false; - }); - - return description; -} - -SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){ - __block bool result = true; - SOSRingStatus returned; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; - SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); - - SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; - if(myPeer && ring) { - result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer)); - } - CFReleaseNull(ring); - - return result; - }); - return returned; -} - -bool SOSCCAccountSetToNew_Server(CFErrorRef *error) -{ - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSAccountSetToNew(txn.account); - return true; - }); -} - -bool SOSCCResetToOffering_Server(CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); - if (!user_key) - return false; - return [txn.account.trust resetToOffering:txn key:user_key err:block_error]; - }); - -} - -bool SOSCCResetToEmpty_Server(CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (!SOSAccountHasPublicKey(txn.account, error)) - return false; - return [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error]; - }); - -} - -bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (!SOSAccountHasPublicKey(txn.account, error)) - return false; - return [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error]; - }); - -} - -bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error]; - }); -} - -bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return [txn.account.trust leaveCircle:txn.account err:block_error]; - }); -} - -bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); - }); -} - -bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error); - }); -} - -bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - secnotice("circleOps", "Signed out of account!"); - - bool waitForeverForSynchronization = true; - - bool result = [txn.account.trust leaveCircle:txn.account err:block_error]; - - [txn restart]; // Make sure this gets finished before we set to new. - - sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); - - SOSAccountSetToNew(txn.account); - - return result; - }); -} - -bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - bool waitForeverForSynchronization = false; - - bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error); - - [txn restart]; // Make sure this gets finished before we set to new. - - sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); - - return result; - }); - -} - -CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyApplicants(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyGeneration(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - @autoreleasepool { - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - @autoreleasepool { - result = SOSAccountCopyValidPeers(txn.account, block_error); - } - return result != NULL; - }); - } - - return result; -} - -bool SOSCCValidateUserPublic_Server(CFErrorRef* error) -{ - __block bool result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSValidateUserPublic(txn.account, block_error); - return result; - }); - - return result; -} - -CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyNotValidPeers(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyRetired(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyViewUnaware(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error) -{ - CFArrayRef result = NULL; - SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); - if (ds) { - SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); - result = SOSEngineCopyPeerConfirmedDigests(engine, error); - SOSDataSourceRelease(ds, error); - } - - return result; -} - -static int64_t getTimeDifference(time_t start) -{ - time_t stop; - int64_t duration; - - stop = time(NULL); - - duration = stop - start; - - return SecBucket1Significant(duration); -} - -static uint64_t initialSyncTimeoutFromDefaultsWrite(void) -{ - uint64_t timeout = 10; - - //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true - CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - - if (isNumber(initialSyncTimeout)) { - CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout); - } - CFReleaseNull(initialSyncTimeout); - return timeout; -} - -bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { - __block dispatch_semaphore_t inSyncSema = NULL; - __block bool result = false; - __block bool synced = false; - bool timed_out = false; - __block CFStringRef inSyncCallID = NULL; - __block time_t start; - __block CFBooleanRef shouldUseInitialSyncV0 = false; - SFSignInAnalytics* syncingEvent = nil; - - NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; - - secnotice("initial sync", "Wait for initial sync start!"); - - result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error); - bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account)); - - if (!alreadyInSync) { - start = time(NULL); - inSyncSema = dispatch_semaphore_create(0); - - SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"]; - inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) { - synced = true; - - if(inSyncSema){ - dispatch_semaphore_signal(inSyncSema); - NSDictionary* attributes = @{@"finishedSyncing" : @YES}; - [syncingEvent stopWithAttributes:attributes]; - } - return true; - }); - NSDictionary* attributes = @{}; - [callWhenInSyncEvent stopWithAttributes:attributes]; - } - else{ - synced = true; - } - return true; - }); - - require_quiet(result, fail); - - - if(inSyncSema){ - syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"]; - if(shouldUseInitialSyncV0){ - secnotice("piggy","setting initial sync timeout to 5 minutes"); - timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC)); - } - else{ - uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite(); - secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite); - timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC)); - } - } - if (timed_out && shouldUseInitialSyncV0) { - do_with_account(^(SOSAccountTransaction* txn) { - if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) { - if(inSyncSema){ - inSyncSema = NULL; // We've canceled the timeout so we must be the last. - } - } - }); - NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}]; - [syncingEvent logUnrecoverableError:error]; - NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES}; - [syncingEvent stopWithAttributes:attributes]; - } - - require_quiet(result, fail); - - if(result) - { - SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start)); - } - else if(!result) - { - SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1); - } - - secnotice("initial sync", "Finished!: %d", result); - -fail: - CFReleaseNull(inSyncCallID); - return result; -} - -bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { - - __block dispatch_semaphore_t inSyncSema = NULL; - __block bool result = false; - __block bool synced = false; - bool timed_out = false; - __block CFStringRef inSyncCallID = NULL; - __block time_t start; - __block CFBooleanRef shouldUseInitialSyncV0 = false; - - secnotice("initial sync", "Wait for initial sync start!"); - - result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error); - bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account)); - - if (!alreadyInSync) { - start = time(NULL); - inSyncSema = dispatch_semaphore_create(0); - - inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) { - synced = true; - - if(inSyncSema){ - dispatch_semaphore_signal(inSyncSema); - - } - return true; - }); - } - else{ - synced = true; - } - return true; - }); - - require_quiet(result, fail); - - if(inSyncSema){ - if(shouldUseInitialSyncV0){ - secnotice("piggy","setting initial sync timeout to 5 minutes"); - timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC)); - } - else{ - uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite(); - secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite); - timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC)); - } - } - if (timed_out && shouldUseInitialSyncV0) { - do_with_account(^(SOSAccountTransaction* txn) { - if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) { - if(inSyncSema){ - inSyncSema = NULL; // We've canceled the timeout so we must be the last. - } - } - }); - } - - require_quiet(result, fail); - - if(result) - { - SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start)); - } - else if(!result) - { - SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1); - } - - secnotice("initial sync", "Finished!: %d", result); - -fail: - CFReleaseNull(inSyncCallID); - return result; -} - - -static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccount* account, CFErrorRef *error) { - __block CFArrayRef result = NULL; - - CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error); - if (valueFetched == kCFBooleanTrue) { - SOSPeerInfoRef myPI = account.peerInfo; - if (myPI) { - SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) { - result = CFSetCopyValues(enabled); - }); - } - } else if (isSet(valueFetched)) { - result = CFSetCopyValues((CFSetRef)valueFetched); - } - - if (result == NULL) { - result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); - } - - return result; -} - -CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) { - - __block CFArrayRef views = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - views = SOSAccountCopyYetToSyncViews(txn.account, error); - - return true; - }); - - return views; -} - -bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error) { - CFErrorRef localerror = NULL; - SOSBackupSliceKeyBagRef bskb = SOSBackupSliceKeyBagForView(viewName, &localerror); - - if(bskbEncoded && bskb) { - *bskbEncoded = SOSBSKBCopyEncoded(bskb, &localerror); - } - - if(output) { - *output = SOSWrapToBackupSliceKeyBag(bskb, input, &localerror); - } - - if(error) { - *error = localerror; - } - return localerror == NULL; -} - -SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){ - __block SOSBackupSliceKeyBagRef bskb = NULL; - (void) do_with_account(^ (SOSAccountTransaction* txn) { - bskb = SOSAccountBackupSliceKeyBagForView(txn.account, viewName, error); - }); - return bskb; -} - -CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error) { - CFDataRef encrypted = NULL; - bskb_keybag_handle_t bskb_handle = 0; - - require_quiet(bskb, exit); - - bskb_handle = SOSBSKBLoadLocked(bskb, error); - require_quiet(bskb_handle, exit); - - SecAccessControlRef access = NULL; - require_quiet(access = SecAccessControlCreate(kCFAllocatorDefault, error), exit); - require_quiet(SecAccessControlSetProtection(access, kSecAttrAccessibleWhenUnlocked, error), exit); - - // ks_encrypt_data takes a dictionary as its plaintext. - CFMutableDictionaryRef plaintext = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(plaintext, CFSTR("data"), input); - - require_quiet(ks_encrypt_data_legacy(bskb_handle, access, NULL, plaintext, NULL, &encrypted, false, error), exit); - -exit: - CFReleaseNull(bskb); - if(bskb_handle != 0) { - ks_close_keybag(bskb_handle, error); - } - if(error && *error) { - secnotice("backup", "Failed to wrap to a BKSB: %@", *error); - } - return encrypted; - -} - -CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){ - - __block CFDictionaryRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - CFErrorRef localError = NULL; - SOSCCStatus status = [txn.account getCircleStatus:&localError]; - - CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); - CFDictionaryRef escrowRecords = NULL; - CFDictionaryRef record = NULL; - switch(status) { - case kSOSCCInCircle: - //get the escrow record in the peer info! - escrowRecords = SOSPeerInfoCopyEscrowRecord(txn.account.peerInfo); - if(escrowRecords){ - record = CFDictionaryGetValue(escrowRecords, dsid); - if(record) - result = CFRetainSafe(record); - } - CFReleaseNull(escrowRecords); - break; - case kSOSCCRequestPending: - //set the escrow record in the peer info/application? - break; - case kSOSCCNotInCircle: - case kSOSCCCircleAbsent: - //set the escrow record in the account expansion! - escrowRecords = SOSAccountGetValue(txn.account, kSOSEscrowRecord, error); - if(escrowRecords){ - record = CFDictionaryGetValue(escrowRecords, dsid); - if(record) - result = CFRetainSafe(record); - } - break; - default: - secdebug("account", "no circle status!"); - break; - } - return true; - }); - - return result; -} - -CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error) { - __block CFDictionaryRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - result = SOSBackupInformation(txn, error); - return true; - }); - return result; -} - -bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){ - - if (escrow_label == NULL) { - return false; - } - - __block bool result = true; - __block CFErrorRef block_error = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - SOSCCStatus status = [txn.account getCircleStatus:&block_error]; - - CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); - - CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); - - withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { - CFStringAppend(timeDescription, decription); - }); - CFStringAppend(timeDescription, CFSTR("]")); - - CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries); - - CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts); - CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription); - - CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries); - - switch(status) { - case kSOSCCInCircle: - //set the escrow record in the peer info! - if(!SOSFullPeerInfoAddEscrowRecord(txn.account.fullPeerInfo, dsid, escrowRecord, error)){ - secdebug("accout", "Could not set escrow record in the full peer info"); - result = false; - } - break; - case kSOSCCRequestPending: - //set the escrow record in the peer info/application? - break; - case kSOSCCNotInCircle: - case kSOSCCCircleAbsent: - //set the escrow record in the account expansion! - - if(!SOSAccountAddEscrowRecords(txn.account, dsid, escrowRecord, error)) { - secdebug("account", "Could not set escrow record in expansion data"); - result = false; - } - break; - default: - secdebug("account", "no circle status!"); - break; - } - CFReleaseNull(attempts); - CFReleaseNull(timeDescription); - CFReleaseNull(escrowTimeAndTries); - CFReleaseNull(escrowRecord); - - return true; - }); - - return result; -} - -bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountAcceptApplicants(txn.account, applicants, block_error); - }); - -} - -bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error) -{ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRejectApplicants(txn.account, applicants, block_error); - }); -} - -CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyPeers(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error) -{ - __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyConcurringPeers(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error) -{ - __block SOSPeerInfoRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // Create a copy to be DERed/sent back to client - result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); - return result != NULL; - }); - - return result; -} - -CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error) -{ - __block CFDataRef accountState = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // Copy account state from the keychain - accountState = SOSAccountCopyAccountStateFromKeychain(block_error); - return accountState != NULL; - }); - - return accountState; -} - -bool SOSCCDeleteAccountState_Server(CFErrorRef* error) -{ - __block bool result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // Delete account state from the keychain - result = SOSAccountDeleteAccountStateFromKeychain(block_error); - return result; - }); - - return result; -} - -CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error) -{ - __block CFDataRef engineState = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // Copy engine state from the keychain - engineState = SOSAccountCopyEngineStateFromKeychain(block_error); - return engineState != NULL; - }); - - return engineState; -} - -bool SOSCCDeleteEngineState_Server(CFErrorRef* error) -{ - __block bool result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - // Delete engine state from the keychain - result = SOSAccountDeleteEngineStateFromKeychain(block_error); - return result; - }); - - return result; -} - - - -SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){ - __block SOSPeerInfoRef result = NULL; - - secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock"); - (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquired account lock"); - if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){ - secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set in account"); - [txn restart]; // Finish the transaction to update any changes to the peer info. - - // Create a copy to be DERed/sent back to client - result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); - secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set and pushed"); - } - else - { - secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, could not set new public backup"); - } - return result != NULL; - }); - - return result; -} - -bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error); - }); -} - -CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error) -{ - __block CFStringRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountCopyIncompatibilityInfo(txn.account, block_error); - return result != NULL; - }); - - return result; -} - -bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error) { - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountIsLastBackupPeer(txn.account, block_error); - }); - return result; -} - -enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error) -{ - __block enum DepartureReason result = kSOSDepartureReasonError; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountGetLastDepartureReason(txn.account, block_error); - return result != kSOSDepartureReasonError; - }); - - return result; -} - -bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){ - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSAccountSetLastDepartureReason(txn.account, reason); - return true; - }); -} - -bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error) -{ - secnotice("updates", "Request for registering peers"); - return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountEnsurePeerRegistration(txn.account, error); - }); -} - -CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) { - __block CFSetRef result = NULL; - if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error); - return result != NULL; - })) { - // Be sure we don't return a result if we got an error - CFReleaseNull(result); - } - - return result; -} - -SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error) -{ - /* - #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked - #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked - */ - __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess; - - CFErrorRef action_error = NULL; - - if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRequestSyncWithAllPeers(txn, block_error); - })) { - if (action_error) { - if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) { - secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know"); - result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks - CFReleaseNull(action_error); - } else { - secerror("Unexpected error: %@", action_error); - } - } - - SecErrorPropagate(action_error, error); - } - - return result; -} - -// -// Sync requesting -// - -void SOSCCRequestSyncWithPeer(CFStringRef peerID) { - CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL); - - SOSCCRequestSyncWithPeersList(peers); - - CFReleaseNull(peers); -} - -void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) { - CFMutableArrayRef peerIDArray = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - CFSetForEach(peerIDs, ^(const void *value) { - if (isString(value)) { - CFArrayAppendValue(peerIDArray, value); - } else if (isSOSPeerInfo(value)) { - SOSPeerInfoRef peer = asSOSPeerInfo(value); - CFArrayAppendValue(peerIDArray, SOSPeerInfoGetPeerID(peer)); - } else { - secerror("Bad element, skipping: %@", value); - } - }); - - SOSCCRequestSyncWithPeersList(peerIDArray); - - CFReleaseNull(peerIDArray); -} - -void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) { - os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { - CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); - - CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) { - secnotice("syncwith", "Request Sync With: %@", description); - }); - - SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty, - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - CFReleaseNull(empty); - }); -} - -void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId) { - os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { - CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); - CFArrayRef backupPeerList = CFArrayCreateForCFTypes(kCFAllocatorDefault, backupPeerId, NULL); - - CFStringArrayPerformWithDescription(backupPeerList, ^(CFStringRef description) { - secnotice("syncwith", "Request backup sync With: %@", description); - }); - - SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerList, - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - - CFReleaseNull(empty); - CFReleaseNull(backupPeerList); - }); -} - -bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) { - return false; -} - -void SOSCCEnsurePeerRegistration(void) -{ - os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { - - SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); - - }); -} - -CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) -{ - CFArrayRef result = NULL; - SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set - - (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault)); - return result; -} - -SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) { - __block SOSPeerInfoRef application = NULL; - do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - application = SOSAccountCopyApplication(txn.account, error); - return application != NULL; - }); - return application; -} - -bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) { - bool result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountCleanupAllKVSKeys(txn.account, error); - }); - if(result && error && *error) { - CFReleaseNull(*error); - } - return result; -} - -bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error) -{ - __block bool result = false; - do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountPopulateKVSWithBadKeys(txn.account, error); - }); - return result; -} -CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) { - __block CFDataRef pbblob = NULL; - do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error); - return pbblob != NULL; - }); - return pbblob; -} - -CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error) { - __block CFDataRef pbblob = NULL; - do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - pbblob = SOSAccountCopyInitialSyncData(txn.account, error); - return pbblob != NULL; - }); - return pbblob; -} - -bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { - return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error); - }); - -} - -CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) { - __block CFBooleanRef result = NULL; - do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error); - return result != NULL; - }); - - return result; -} - -bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){ - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) - return SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); - else - return SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); - }); -} - -CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){ - - __block CFDataRef result = NULL; - do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - result = SOSAccountCopyRecoveryPublicKey(txn, error); - return result != NULL; - }); - - return result; -} - -bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountMessageFromPeerIsPending(txn, peer, error); - }); -} - -bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountSendToPeerIsPending(txn, peer, error); - }); -} - -void SOSCCResetOTRNegotiation_Server(CFStringRef peerid) -{ - CFErrorRef localError = NULL; - do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - SOSAccountResetOTRNegotiationCoder(txn.account, peerid); - return true; - }); - if(localError) - { - secerror("error resetting otr negotation: %@", localError); - } -} - -void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup) -{ - CFErrorRef localError = NULL; - do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup); - return true; - }); - if(localError) - { - secerror("error sending next message: %@", localError); - } -} - -void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivSigningKey, CFErrorRef error)) -{ - CFErrorRef error = NULL; - do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; - SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err); - CFErrorRef errorArg = err ? *err : NULL; - action(signingKey, errorArg); - CFReleaseNull(signingKey); - return true; - }); - CFReleaseNull(error); -} - -void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error)) -{ - CFErrorRef error = NULL; - do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; - SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, err); - CFErrorRef errorArg = err ? *err : NULL; - action(signingKey, errorArg); - CFReleaseNull(signingKey); - return true; - }); - CFReleaseNull(error); -} - -void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error)) -{ - CFErrorRef error = NULL; - do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; - SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, err); - CFErrorRef errorArg = err ? *err : NULL; - action(signingKey, errorArg); - CFReleaseNull(signingKey); - return true; - }); - CFReleaseNull(error); -} - -void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error)) -{ - CFErrorRef error = NULL; - do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; - SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, err); - CFErrorRef errorArg = err ? *err : NULL; - action(signingKey, errorArg); - CFReleaseNull(signingKey); - return true; - }); - CFReleaseNull(error); -} - -void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error)) -{ - CFErrorRef localError = NULL; - do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - SecKeyRef encryptionKey = NULL; - SecKeyRef signingKey = NULL; - CFErrorRef errorArg = err ? *err : NULL; - - SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; - require_action_quiet(fpi, fail, secerror("device does not have a peer"); SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, &errorArg)); - - signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, &errorArg); - require_action_quiet(signingKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys signing key error: %@", errorArg)); - CFReleaseNull(errorArg); - - encryptionKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, &errorArg); - require_action_quiet(encryptionKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys encryption key error: %@", errorArg)); - - action(encryptionKey, signingKey, errorArg); - CFReleaseNull(signingKey); - CFReleaseNull(encryptionKey); - CFReleaseNull(errorArg); - return true; - fail: - action(NULL, NULL, errorArg); - CFReleaseNull(errorArg); - CFReleaseNull(signingKey); - CFReleaseNull(encryptionKey); - return true; - }); - CFReleaseNull(localError); -} - -static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, int keySize, SecKeyRef octagonPublicKey, NSError** error) { - NSError* localerror = nil; - - CFDataRef publicKeyHash = SecKeyCopyPublicKeyHash(octagonPublicKey); - - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC, - (id)kSecAttrKeyClass : (id)kSecAttrKeyClassPrivate, - (id)kSecAttrAccessGroup : (id)kSOSInternalAccessGroup, - (id)kSecAttrLabel : keyLabel, - (id)kSecAttrApplicationLabel : (__bridge NSData*)(publicKeyHash), - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecValueData : keyDataToSave, - } mutableCopy]; - - CFTypeRef result = NULL; - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &result); - - if(status == errSecSuccess) { - CFReleaseNull(publicKeyHash); - return true; - } - if(status == errSecDuplicateItem) { - // Add every primary key attribute to this find dictionary - NSMutableDictionary* findQuery = [[NSMutableDictionary alloc] init]; - findQuery[(id)kSecClass] = query[(id)kSecClass]; - findQuery[(id)kSecAttrKeyType] = query[(id)kSecAttrKeyTypeEC]; - findQuery[(id)kSecAttrKeyClass] = query[(id)kSecAttrKeyClassPrivate]; - findQuery[(id)kSecAttrAccessGroup] = query[(id)kSecAttrAccessGroup]; - findQuery[(id)kSecAttrLabel] = query[(id)kSecAttrLabel]; - findQuery[(id)kSecAttrApplicationLabel] = query[(id)kSecAttrApplicationLabel]; - findQuery[(id)kSecUseDataProtectionKeychain] = query[(id)kSecUseDataProtectionKeychain]; - - NSMutableDictionary* updateQuery = [query mutableCopy]; - updateQuery[(id)kSecClass] = nil; - - status = SecItemUpdate((__bridge CFDictionaryRef)findQuery, (__bridge CFDictionaryRef)updateQuery); - - if(status) { - localerror = [NSError - errorWithDomain:NSOSStatusErrorDomain - code:status - description:[NSString stringWithFormat:@"SecItemUpdate: %d", (int)status]]; - } - } else { - localerror = [NSError - errorWithDomain:NSOSStatusErrorDomain - code:status - description:[NSString stringWithFormat:@"SecItemAdd: %d", (int)status]]; - } - if(localerror && error) { - *error = localerror; - } - - CFReleaseNull(publicKeyHash); - - return (status == errSecSuccess); -} - -static NSString* createKeyLabel(NSDictionary *gestalt, NSString* circleName, NSString* prefix) -{ - NSString *keyName = [NSString stringWithFormat:@"ID for %@-%@",SOSPeerGestaltGetName((__bridge CFDictionaryRef)(gestalt)), circleName]; - - NSString* octagonSigningKeyName = [prefix stringByAppendingString: keyName]; - - return octagonSigningKeyName; -} - -static NSError* saveKeysToKeychain(SOSAccount* account, NSData* octagonSigningFullKey, NSData* octagonEncryptionFullKey, SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef) -{ - NSError* saveToKeychainError = nil; - - NSString* circleName = (__bridge NSString*)(SOSCircleGetName(account.trust.trustedCircle)); - NSString* signingPrefix = @"Octagon Peer Signing "; - NSString* encryptionPrefix = @"Octagon Peer Encryption "; - NSString* octagonSigningKeyName = createKeyLabel(account.gestalt, circleName, signingPrefix); - NSString* octagonEncryptionKeyName = createKeyLabel(account.gestalt, circleName, encryptionPrefix); - - /* behavior mimics GeneratePermanentFullECKey_internal */ - saveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError); - if(saveToKeychainError) { - secerror("octagon: could not save signing key: %@", saveToKeychainError); - return saveToKeychainError; - } - saveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError); - if(saveToKeychainError) { - secerror("octagon: could not save encryption key: %@", saveToKeychainError); - return saveToKeychainError; - } - - return nil; -} - -void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey, - CFDataRef signingPublicKey, CFDataRef encryptionPublicKey, - SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef, - void (^action)(CFErrorRef error)) -{ - CFErrorRef localError = NULL; - do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { - CFErrorRef updateOctagonKeysError = NULL; - bool updatedPeerInfo = SOSAccountUpdatePeerInfoAndPush(txn.account, CFSTR("Updating Octagon Keys in SOS"), &updateOctagonKeysError, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) { - - //save octagon key set to the keychain - NSError* saveError = nil; - saveError = saveKeysToKeychain(txn.account, (__bridge NSData*)octagonSigningFullKey, (__bridge NSData*)octagonEncryptionFullKey, - octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef); - - if(saveError) { - secerror("octagon: failed to save Octagon keys to the keychain: %@", saveError); - action((__bridge CFErrorRef)saveError); - return false; - } - - //now update the peer info to contain octagon keys - if(pi){ - CFErrorRef setError = NULL; - SOSPeerInfoSetOctagonKeysInDescription(pi, octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef, &setError); - if(setError) { - secerror("octagon: Failed to set Octagon Keys in peerInfo: %@", setError); - action(setError); - return false; - } - } else { - secnotice("octagon", "No peer info to update?"); - NSError *noPIError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorPeerNotFound userInfo:@{NSLocalizedDescriptionKey : @"Device has no full peer info"}]; - action((__bridge CFErrorRef)noPIError); - return false; - } - - secnotice("octagon", "Success! Upated Octagon keys in SOS!"); - - action(nil); - return true; - }); - return updatedPeerInfo; - }); - CFReleaseNull(localError); -} - -void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error)) -{ - CFErrorRef cfAccountError = NULL; - do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) { - CFSetRef sosPeerSet = [txn.account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) { - return true; - }]; - - CFErrorRef errorArg = cferror ? *cferror : NULL; - action(sosPeerSet, errorArg); - CFReleaseNull(sosPeerSet); - return true; - }); - CFReleaseNull(cfAccountError); -} - -void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error)) -{ - CFErrorRef cfAccountError = NULL; - do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) { - SOSAccount* account = txn.account; - NSString* peerID = nil; - CFErrorRef localError = nil; - - if([account getCircleStatus:nil] == kSOSCCInCircle){ - peerID = [txn.account peerID]; - } - else{ - SOSErrorCreate(kSOSErrorNoCircle, &localError, NULL, CFSTR("Not in circle")); - } - action((__bridge CFStringRef)peerID, localError); - CFReleaseNull(localError); - return true; - }); - CFReleaseNull(cfAccountError); -} diff --git a/OSX/sec/securityd/SecAKSObjCWrappers.h b/OSX/sec/securityd/SecAKSObjCWrappers.h deleted file mode 100644 index d7bf4e94..00000000 --- a/OSX/sec/securityd/SecAKSObjCWrappers.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import -#import "SecKeybagSupport.h" -#include - -#define BridgeCFErrorToNSErrorOut(nsErrorOut, CFErr) \ -{ \ - if (nsErrorOut) { \ - *nsErrorOut = CFBridgingRelease(CFErr); \ - CFErr = NULL; \ - } \ - else { \ - CFReleaseNull(CFErr); \ - } \ -} - -NS_ASSUME_NONNULL_BEGIN - -@interface SecAKSObjCWrappers : NSObject -+ (bool)aksEncryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass plaintext:(NSData*)plaintext - outKeyclass:(keyclass_t* _Nullable)outKeyclass ciphertext:(NSMutableData*)ciphertext error:(NSError**)error; - -+ (bool)aksDecryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass ciphertext:(NSData*)ciphertext - outKeyclass:(keyclass_t* _Nullable)outKeyclass plaintext:(NSMutableData*)plaintext error:(NSError**)error; -@end - -NS_ASSUME_NONNULL_END diff --git a/OSX/sec/securityd/SecAKSObjCWrappers.m b/OSX/sec/securityd/SecAKSObjCWrappers.m deleted file mode 100644 index 68eb3d6a..00000000 --- a/OSX/sec/securityd/SecAKSObjCWrappers.m +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SecAKSObjCWrappers.h" - -@implementation SecAKSObjCWrappers - -+ (bool)aksEncryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass plaintext:(NSData*)plaintext - outKeyclass:(keyclass_t*)outKeyclass ciphertext:(NSMutableData*)ciphertext error:(NSError**)error -{ - CFErrorRef cfError = NULL; - bool result = ks_crypt(kAKSKeyOpEncrypt, keybag, keyclass, (uint32_t)plaintext.length, plaintext.bytes, outKeyclass, (__bridge CFMutableDataRef)ciphertext, &cfError); - BridgeCFErrorToNSErrorOut(error, cfError); - return result; -} - -+ (bool)aksDecryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass ciphertext:(NSData*)ciphertext - outKeyclass:(keyclass_t*)outKeyclass plaintext:(NSMutableData*)plaintext error:(NSError**)error -{ - CFErrorRef cfError = NULL; - bool result = ks_crypt(kAKSKeyOpDecrypt, keybag, keyclass, (uint32_t)ciphertext.length, ciphertext.bytes, outKeyclass, (__bridge CFMutableDataRef)plaintext, &cfError); - BridgeCFErrorToNSErrorOut(error, cfError); - return result; -} - -@end diff --git a/OSX/sec/securityd/SecCAIssuerCache.c b/OSX/sec/securityd/SecCAIssuerCache.c deleted file mode 100644 index 5921de5b..00000000 --- a/OSX/sec/securityd/SecCAIssuerCache.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/* - * SecCAIssuerCache.c - securityd - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utilities/sqlutils.h" -#include "utilities/iOSforOSX.h" - -#include -#include -#include - -static const char expireSQL[] = "DELETE FROM issuers WHERE expires PATH_MAX) - return SQLITE_CANTOPEN; - memcpy(pathbuf, path, len); - for (pos = len-1; pos > 0; --pos) - { - /* Search backwards for trailing '/'. */ - if (pathbuf[pos] == '/') - { - pathbuf[pos] = '\0'; - /* Attempt to create parent directories of the database. */ - if (!mkdir(pathbuf, 0777)) - break; - else - { - int err = errno; - if (err == EEXIST) - return 0; - if (err == ENOTDIR) - return SQLITE_CANTOPEN; - if (err == EROFS) - return SQLITE_READONLY; - if (err == EACCES) - return SQLITE_PERM; - if (err == ENOSPC || err == EDQUOT) - return SQLITE_FULL; - if (err == EIO) - return SQLITE_IOERR; - - /* EFAULT || ELOOP | ENAMETOOLONG || something else */ - return SQLITE_INTERNAL; - } - } - } - return SQLITE_OK; -} - -static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h, - bool create_path) -{ - int s3e; - s3e = sqlite3_open(db_name, s3h); - if (s3e == SQLITE_CANTOPEN && create_path) { - /* Make sure the path to db_name exists and is writable, then - try again. */ - s3e = sec_create_path(db_name); - if (!s3e) - s3e = sqlite3_open(db_name, s3h); - } - - return s3e; -} - -static int sec_sqlite3_reset(sqlite3_stmt *stmt, int s3e) { - int s3e2; - if (s3e == SQLITE_ROW || s3e == SQLITE_DONE) - s3e = SQLITE_OK; - s3e2 = sqlite3_reset(stmt); - if (s3e2 && !s3e) - s3e = s3e2; - s3e2 = sqlite3_clear_bindings(stmt); - if (s3e2 && !s3e) - s3e = s3e2; - return s3e; -} - -static int SecCAIssuerCacheEnsureTxn(SecCAIssuerCacheRef this) { - int s3e, s3e2; - - if (this->in_transaction) - return SQLITE_OK; - - s3e = sqlite3_step(this->beginTxn); - if (s3e == SQLITE_DONE) { - this->in_transaction = true; - s3e = SQLITE_OK; - } else { - secdebug("caissuercache", "sqlite3_step returned [%d]: %s", s3e, - sqlite3_errmsg(this->s3h)); - } - s3e2 = sqlite3_reset(this->beginTxn); - if (s3e2 && !s3e) - s3e = s3e2; - - return s3e; -} - -static int SecCAIssuerCacheCommitTxn(SecCAIssuerCacheRef this) { - int s3e, s3e2; - - if (!this->in_transaction) - return SQLITE_OK; - - s3e = sqlite3_step(this->endTxn); - if (s3e == SQLITE_DONE) { - this->in_transaction = false; - s3e = SQLITE_OK; - } else { - secdebug("caissuercache", "sqlite3_step returned [%d]: %s", s3e, - sqlite3_errmsg(this->s3h)); - } - s3e2 = sqlite3_reset(this->endTxn); - if (s3e2 && !s3e) - s3e = s3e2; - - return s3e; -} - -static SecCAIssuerCacheRef SecCAIssuerCacheCreate(const char *db_name) { - SecCAIssuerCacheRef this; - int s3e = SQLITE_OK; - bool create = true; - - require(this = (SecCAIssuerCacheRef)calloc(sizeof(struct __SecCAIssuerCache), 1), errOut); - require_action_quiet((this->queue = dispatch_queue_create("caissuercache", 0)), errOut, s3e = errSecAllocate); - require_noerr(s3e = sec_sqlite3_open(db_name, &this->s3h, create), errOut); - this->in_transaction = false; - - s3e = sqlite3_prepare_v2(this->s3h, beginTxnSQL, sizeof(beginTxnSQL), - &this->beginTxn, NULL); - require_noerr(s3e, errOut); - s3e = sqlite3_prepare_v2(this->s3h, endTxnSQL, sizeof(endTxnSQL), - &this->endTxn, NULL); - require_noerr(s3e, errOut); - - s3e = sqlite3_prepare_v2(this->s3h, expireSQL, sizeof(expireSQL), - &this->expire, NULL); - if (create && s3e == SQLITE_ERROR) { - s3e = SecCAIssuerCacheEnsureTxn(this); - require_noerr(s3e, errOut); - - /* sqlite3_prepare returns SQLITE_ERROR if the table we are - compiling this statement for doesn't exist. */ - char *errmsg = NULL; - s3e = sqlite3_exec(this->s3h, - "CREATE TABLE issuers(" - "uri BLOB PRIMARY KEY," - "expires DOUBLE NOT NULL," - "certificate BLOB NOT NULL" - ");" - "CREATE INDEX iexpires ON issuers(expires);" - , NULL, NULL, &errmsg); - if (errmsg) { - secerror("caissuer db CREATE TABLES: %s", errmsg); - sqlite3_free(errmsg); - } - require_noerr(s3e, errOut); - s3e = sqlite3_prepare_v2(this->s3h, expireSQL, sizeof(expireSQL), - &this->expire, NULL); - } - require_noerr(s3e, errOut); - s3e = sqlite3_prepare_v2(this->s3h, insertIssuerSQL, sizeof(insertIssuerSQL), - &this->insertIssuer, NULL); - require_noerr(s3e, errOut); - s3e = sqlite3_prepare_v2(this->s3h, selectIssuerSQL, sizeof(selectIssuerSQL), - &this->selectIssuer, NULL); - require_noerr(s3e, errOut); - - return this; - -errOut: - if (s3e != SQLITE_OK) { - TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationCreate, TAFatalError, s3e); - } - if (this) { - if (this->queue) - dispatch_release(this->queue); - if (this->s3h) - sqlite3_close(this->s3h); - free(this); - } - - return NULL; -} - -static void SecCAIssuerCacheInit(void) { -#if TARGET_OS_IPHONE - WithPathInKeychainDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { - kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); - }); -#else - /* macOS caches should be in user cache dir */ - WithPathInUserCacheDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { - kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); - }); -#endif - - if (kSecCAIssuerCache) - atexit(SecCAIssuerCacheGC); -} - -static CF_RETURNS_RETAINED CFDataRef convertArrayOfCertsToData(CFArrayRef certificates) { - if (!certificates || CFArrayGetCount(certificates) == 0) { - return NULL; - } - - CFMutableDataRef output = CFDataCreateMutable(NULL, 0); - CFArrayForEach(certificates, ^(const void *value) { - CFDataRef certData = SecCertificateCopyData((SecCertificateRef)value); - if (certData) { - CFDataAppend(output, certData); - } - CFReleaseNull(certData); - }); - - return output; -} - -static CF_RETURNS_RETAINED CFArrayRef convertDataToArrayOfCerts(uint8_t *data, size_t dataLen) { - if (!data || dataLen == 0) { - return NULL; - } - - CFMutableArrayRef output = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - uint8_t *nextCertPtr = data; - size_t remainingDataLen = dataLen; - while (nextCertPtr < data + dataLen) { - SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, nextCertPtr, remainingDataLen); - if (cert) { - CFArrayAppendValue(output, cert); - nextCertPtr += SecCertificateGetLength(cert); - remainingDataLen -= SecCertificateGetLength(cert); - CFReleaseNull(cert); - } else { - /* We don't know where the next cert starts, so we should just stop */ - break; - } - } - - if (CFArrayGetCount(output) < 1) { - CFReleaseNull(output); - } - return output; -} - -/* Instance implemenation. */ - -static void _SecCAIssuerCacheAddCertificates(SecCAIssuerCacheRef this, - CFArrayRef certificates, - CFURLRef uri, CFAbsoluteTime expires) { - int s3e; - CFDataRef certsData = NULL; - CFDataRef uriData = NULL; - - secdebug("caissuercache", "adding certificate from %@", uri); - require_noerr(s3e = SecCAIssuerCacheEnsureTxn(this), errOut); - - /* issuer.uri */ - require_action(uriData = CFURLCreateData(kCFAllocatorDefault, uri, - kCFStringEncodingUTF8, false), errOut, s3e = SQLITE_NOMEM); - s3e = sqlite3_bind_blob_wrapper(this->insertIssuer, 1, - CFDataGetBytePtr(uriData), CFDataGetLength(uriData), SQLITE_TRANSIENT); - CFRelease(uriData); - - /* issuer.expires */ - if (!s3e) s3e = sqlite3_bind_double(this->insertIssuer, 2, expires); - - /* issuer.certificate */ - require_action(certsData = convertArrayOfCertsToData(certificates), errOut, - s3e = SQLITE_NOMEM); - if (!s3e) { - s3e = sqlite3_bind_blob_wrapper(this->insertIssuer, 3, - CFDataGetBytePtr(certsData), - CFDataGetLength(certsData), SQLITE_TRANSIENT); - } - CFReleaseNull(certsData); - - /* Execute the insert statement. */ - if (!s3e) s3e = sqlite3_step(this->insertIssuer); - require_noerr(s3e = sec_sqlite3_reset(this->insertIssuer, s3e), errOut); - -errOut: - if (s3e != SQLITE_OK) { - secerror("caissuer cache add failed: %s", sqlite3_errmsg(this->s3h)); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); - /* TODO: Blow away the cache and create a new db. */ - } -} - -static CFArrayRef _SecCAIssuerCacheCopyMatching(SecCAIssuerCacheRef this, - CFURLRef uri) { - CFArrayRef certificates = NULL; - int s3e = SQLITE_OK; - - CFDataRef uriData = NULL; - require(uriData = CFURLCreateData(kCFAllocatorDefault, uri, - kCFStringEncodingUTF8, false), errOut); - s3e = sqlite3_bind_blob_wrapper(this->selectIssuer, 1, CFDataGetBytePtr(uriData), - CFDataGetLength(uriData), SQLITE_TRANSIENT); - CFRelease(uriData); - - if (!s3e) s3e = sqlite3_step(this->selectIssuer); - if (s3e == SQLITE_ROW) { - /* Found an entry! */ - secdebug("caissuercache", "found cached response for %@", uri); - - const void *respData = sqlite3_column_blob(this->selectIssuer, 0); - int respLen = sqlite3_column_bytes(this->selectIssuer, 0); - certificates = convertDataToArrayOfCerts((uint8_t *)respData, respLen); - } - - require_noerr(s3e = sec_sqlite3_reset(this->selectIssuer, s3e), errOut); - -errOut: - if (s3e != SQLITE_OK) { - if (s3e != SQLITE_DONE) { - secerror("caissuer cache lookup failed: %s", sqlite3_errmsg(this->s3h)); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationRead, TAFatalError, s3e); - /* TODO: Blow away the cache and create a new db. */ - } - - if (certificates) { - CFRelease(certificates); - certificates = NULL; - } - } - - secdebug("caissuercache", "returning %s for %@", (certificates ? "cached response" : "NULL"), uri); - return certificates; -} - -static void _SecCAIssuerCacheGC(void *context) { - SecCAIssuerCacheRef this = context; - int s3e; - - require_noerr(s3e = SecCAIssuerCacheEnsureTxn(this), errOut); - secdebug("caissuercache", "expiring stale responses"); - s3e = sqlite3_bind_double(this->expire, 1, CFAbsoluteTimeGetCurrent()); - if (!s3e) s3e = sqlite3_step(this->expire); - require_noerr(s3e = sec_sqlite3_reset(this->expire, s3e), errOut); - require_noerr(s3e = SecCAIssuerCacheCommitTxn(this), errOut); - -errOut: - if (s3e != SQLITE_OK) { - secerror("caissuer cache expire failed: %s", sqlite3_errmsg(this->s3h)); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); - /* TODO: Blow away the cache and create a new db. */ - } -} - -static void _SecCAIssuerCacheFlush(void *context) { - SecCAIssuerCacheRef this = context; - int s3e; - - secdebug("caissuercache", "flushing pending changes"); - s3e = SecCAIssuerCacheCommitTxn(this); - - if (s3e != SQLITE_OK) { - secerror("caissuer cache flush failed: %s", sqlite3_errmsg(this->s3h)); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); - /* TODO: Blow away the cache and create a new db. */ - } -} - -/* Public API */ - -void SecCAIssuerCacheAddCertificates(CFArrayRef certificates, - CFURLRef uri, CFAbsoluteTime expires) { - dispatch_once(&kSecCAIssuerCacheOnce, ^{ - SecCAIssuerCacheInit(); - }); - if (!kSecCAIssuerCache) - return; - - dispatch_sync(kSecCAIssuerCache->queue, ^{ - _SecCAIssuerCacheAddCertificates(kSecCAIssuerCache, certificates, uri, expires); - _SecCAIssuerCacheFlush(kSecCAIssuerCache); - }); -} - -CFArrayRef SecCAIssuerCacheCopyMatching(CFURLRef uri) { - dispatch_once(&kSecCAIssuerCacheOnce, ^{ - SecCAIssuerCacheInit(); - }); - __block CFArrayRef certs = NULL; - if (kSecCAIssuerCache) - dispatch_sync(kSecCAIssuerCache->queue, ^{ - certs = _SecCAIssuerCacheCopyMatching(kSecCAIssuerCache, uri); - }); - return certs; -} - -/* This should be called on a normal non emergency exit. This function - effectively does a SecCAIssuerCacheFlush. - Currently this is called from our atexit handeler. - This function expires any records that are stale and commits. - - Idea for future cache management policies: - Expire old cache entires from database if: - - The time to do so has arrived based on the nextExpire date in the - policy table. - - If the size of the database exceeds the limit set in the maxSize field - in the policy table, vacuum the db. If the database is still too - big, expire records on a LRU basis. - */ -void SecCAIssuerCacheGC(void) { - if (kSecCAIssuerCache) - dispatch_sync(kSecCAIssuerCache->queue, ^{ - _SecCAIssuerCacheGC(kSecCAIssuerCache); - }); -} diff --git a/OSX/sec/securityd/SecCAIssuerCache.h b/OSX/sec/securityd/SecCAIssuerCache.h deleted file mode 100644 index 152035d8..00000000 --- a/OSX/sec/securityd/SecCAIssuerCache.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/*! - @header SecCAIssuerCache - The functions provided in SecCAIssuerCache.h provide an interface to - an CAIssuer caching module. - */ - -#ifndef _SECURITY_SECCAISSUERCACHE_H_ -#define _SECURITY_SECCAISSUERCACHE_H_ - -#include -#include -#include -#include - -__BEGIN_DECLS - - -void SecCAIssuerCacheAddCertificates(CFArrayRef certificates, - CFURLRef uri, CFAbsoluteTime expires); - -CFArrayRef SecCAIssuerCacheCopyMatching(CFURLRef uri); - -/* This should be called on a normal non emergency exit. */ -void SecCAIssuerCacheGC(void); - -__END_DECLS - -#endif /* _SECURITY_SECCAISSUERCACHE_H_ */ diff --git a/OSX/sec/securityd/SecCAIssuerRequest.h b/OSX/sec/securityd/SecCAIssuerRequest.h deleted file mode 100644 index 61ea4dc4..00000000 --- a/OSX/sec/securityd/SecCAIssuerRequest.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include - -bool SecCAIssuerCopyParents(SecCertificateRef certificate, void *context, void (*callback)(void *, CFArrayRef)); diff --git a/OSX/sec/securityd/SecCAIssuerRequest.m b/OSX/sec/securityd/SecCAIssuerRequest.m deleted file mode 100644 index b7b31d41..00000000 --- a/OSX/sec/securityd/SecCAIssuerRequest.m +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2009-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecCAIssuerRequest.m - asynchronous CAIssuer request fetching engine. - */ - - -#include "SecCAIssuerRequest.h" -#include "SecCAIssuerCache.h" - -#import -#import -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_CA_ISSUERS 3 -#define CA_ISSUERS_REQUEST_THRESHOLD 10 - -typedef void (*CompletionHandler)(void *context, CFArrayRef parents); - -/* CA Issuer lookup code. */ -@interface CAIssuerDelegate: TrustURLSessionDelegate -@property (assign) CompletionHandler callback; -@end - -static NSArray *certificatesFromData(NSData *data) { - /* RFC5280 4.2.2.1: - "accessLocation MUST be a uniformResourceIdentifier and the URI - MUST point to either a single DER encoded certificate as speci- - fied in [RFC2585] or a collection of certificates in a BER or - DER encoded "certs-only" CMS message as specified in [RFC2797]." */ - - /* DER-encoded certificate */ - SecCertificateRef parent = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); - if (parent) { - NSArray *result = @[(__bridge id)parent]; - CFReleaseNull(parent); - return result; - } - - /* "certs-only" CMS Message */ - CFArrayRef certificates = SecCMSCertificatesOnlyMessageCopyCertificates((__bridge CFDataRef)data); - if (certificates) { - return CFBridgingRelease(certificates); - } - - /* Retry in case the certificate is in PEM format. Some CAs - incorrectly return a PEM encoded cert, despite RFC 5280 4.2.2.1 */ - parent = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data); - if (parent) { - NSArray *result = @[(__bridge id)parent]; - CFReleaseNull(parent); - return result; - } - return nil; -} - -@implementation CAIssuerDelegate -- (BOOL)fetchNext:(NSURLSession *)session { - SecPathBuilderRef builder = (SecPathBuilderRef)self.context; - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - - BOOL result = false; - if (!(result = [super fetchNext:session]) && analytics) { - analytics->ca_issuer_fetches++; - } - return result; -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - /* call the superclass's method to set taskTime and expiration */ - [super URLSession:session task:task didCompleteWithError:error]; - - __block SecPathBuilderRef builder =(SecPathBuilderRef)self.context; - if (!builder) { - /* We already returned to the PathBuilder state machine. */ - return; - } - - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - __block NSArray *parents = nil; - if (error) { - /* Log the error */ - secnotice("caissuer", "Failed to download issuer %@, with error %@", task.originalRequest.URL, error); - if (analytics) { - analytics->ca_issuer_fetch_failed++; - } - } else if (self.response) { - /* Get the parent cert from the data */ - parents = certificatesFromData(self.response); - if (analytics && !parents) { - analytics->ca_issuer_unsupported_data = true; - } else if (analytics && [parents count] > 1) { - analytics->ca_issuer_multiple_certs = true; - } - } - - if (parents) { - /* Found some parents, add to cache, close session, and return to SecPathBuilder */ - secdebug("caissuer", "found parents for %@", task.originalRequest.URL); - SecCAIssuerCacheAddCertificates((__bridge CFArrayRef)parents, (__bridge CFURLRef)task.originalRequest.URL, self.expiration); - self.context = nil; // set the context to NULL before we call back because the callback may free the builder - [session invalidateAndCancel]; - dispatch_async(SecPathBuilderGetQueue(builder), ^{ - self.callback(builder, (__bridge CFArrayRef)parents); - }); - } else { - secdebug("caissuer", "no parents for %@", task.originalRequest.URL); - if ([self fetchNext:session]) { // Try the next CAIssuer URI - /* no fetch scheduled, close this session and jump back into the state machine on the builder's queue */ - secdebug("caissuer", "no more fetches. returning to builder"); - self.context = nil; // set the context to NULL before we call back because the callback may free the builder - [session invalidateAndCancel]; - dispatch_async(SecPathBuilderGetQueue(builder), ^{ - self.callback(builder, NULL); - }); - } - } -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)taskMetrics { - secdebug("caissuer", "got metrics with task interval %f", taskMetrics.taskInterval.duration); - SecPathBuilderRef builder =(SecPathBuilderRef)self.context; - if (builder) { - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - if (analytics) { - analytics->ca_issuer_fetch_time += (uint64_t)(taskMetrics.taskInterval.duration * NSEC_PER_SEC); - } - } -} -@end - -/* Releases parent unconditionally, and return a CFArrayRef containing - parent if the normalized subject of parent matches the normalized issuer - of certificate. */ -static CF_RETURNS_RETAINED CFArrayRef SecCAIssuerConvertToParents(SecCertificateRef certificate, CFArrayRef CF_CONSUMED putativeParents) { - CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); - NSMutableArray *parents = [NSMutableArray array]; - NSArray *possibleParents = CFBridgingRelease(putativeParents); - for (id parent in possibleParents) { - CFDataRef parent_nic = SecCertificateGetNormalizedSubjectContent((__bridge SecCertificateRef)parent); - if (nic && parent_nic && CFEqual(nic, parent_nic)) { - [parents addObject:parent]; - } - } - - if ([parents count] > 0) { - return CFBridgingRetain(parents); - } else { - return nil; - } -} - -static CFArrayRef SecCAIssuerRequestCacheCopyParents(SecCertificateRef cert, - CFArrayRef issuers) { - CFIndex ix = 0, ex = CFArrayGetCount(issuers); - for (;ix < ex; ++ix) { - CFURLRef issuer = CFArrayGetValueAtIndex(issuers, ix); - CFStringRef scheme = CFURLCopyScheme(issuer); - if (scheme) { - if (CFEqual(CFSTR("http"), scheme)) { - CFArrayRef parents = SecCAIssuerConvertToParents(cert, - SecCAIssuerCacheCopyMatching(issuer)); - if (parents) { - secdebug("caissuer", "cache hit, for %@. no request issued", issuer); - CFRelease(scheme); - return parents; - } - } - CFRelease(scheme); - } - } - return NULL; -} - -bool SecCAIssuerCopyParents(SecCertificateRef certificate, void *context, void (*callback)(void *, CFArrayRef)) { - @autoreleasepool { - CFArrayRef issuers = CFRetainSafe(SecCertificateGetCAIssuers(certificate)); - NSArray *nsIssuers = CFBridgingRelease(issuers); - if (!issuers) { - /* certificate has no caissuer urls, we're done. */ - callback(context, NULL); - return true; - } - - SecPathBuilderRef builder = (SecPathBuilderRef)context; - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - CFArrayRef parents = SecCAIssuerRequestCacheCopyParents(certificate, (__bridge CFArrayRef)nsIssuers); - if (parents) { - if (analytics) { - /* We found parents in the cache */ - analytics->ca_issuer_cache_hit = true; - } - callback(context, parents); - CFReleaseSafe(parents); - return true; - } - if (analytics) { - /* We're going to have to make a network call */ - analytics->ca_issuer_network = true; - } - - NSInteger count = [nsIssuers count]; - if (count >= CA_ISSUERS_REQUEST_THRESHOLD) { - secnotice("caissuer", "too many caIssuer entries (%ld)", (long)count); - callback(context, NULL); - return true; - } - - NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; - config.timeoutIntervalForResource = TrustURLSessionGetResourceTimeout(); - config.HTTPAdditionalHeaders = @{@"User-Agent" : @"com.apple.trustd/2.0"}; - - NSData *auditToken = CFBridgingRelease(SecPathBuilderCopyClientAuditToken(builder)); - if (auditToken) { - config._sourceApplicationAuditTokenData = auditToken; - } - - CAIssuerDelegate *delegate = [[CAIssuerDelegate alloc] init]; - delegate.context = context; - delegate.callback = callback; - delegate.URIs = nsIssuers; - delegate.URIix = 0; - - NSOperationQueue *queue = [[NSOperationQueue alloc] init]; - - NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; - secdebug("caissuer", "created URLSession for %@", certificate); - - bool result = false; - if ((result = [delegate fetchNext:session])) { - /* no fetch scheduled, close the session */ - [session invalidateAndCancel]; - } - return result; - } -} - diff --git a/OSX/sec/securityd/SecCertificateServer.c b/OSX/sec/securityd/SecCertificateServer.c deleted file mode 100644 index 39e8ee37..00000000 --- a/OSX/sec/securityd/SecCertificateServer.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecCertificateServer.c - SecCertificate and SecCertificatePathVC types - * with additonal validation context. - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -// MARK: - -// MARK: SecCertificateVC -/******************************************************** - ************* SecCertificateVC object *************** - ********************************************************/ - -struct SecCertificateVC { - CFRuntimeBase _base; - SecCertificateRef certificate; - CFArrayRef usageConstraints; - CFNumberRef revocationReason; - bool optionallyEV; - bool isWeakHash; - bool require_revocation_response; -}; -CFGiblisWithHashFor(SecCertificateVC) - -static void SecCertificateVCDestroy(CFTypeRef cf) { - SecCertificateVCRef cvc = (SecCertificateVCRef) cf; - CFReleaseNull(cvc->certificate); - CFReleaseNull(cvc->usageConstraints); - CFReleaseNull(cvc->revocationReason); -} - -static Boolean SecCertificateVCCompare(CFTypeRef cf1, CFTypeRef cf2) { - SecCertificateVCRef cv1 = (SecCertificateVCRef) cf1; - SecCertificateVCRef cv2 = (SecCertificateVCRef) cf2; - if (!CFEqual(cv1->certificate, cv2->certificate)) { - return false; - } - /* CertificateVCs are the same if either does not have usage constraints. */ - if (cv1->usageConstraints && cv2->usageConstraints && - !CFEqual(cv1->usageConstraints, cv2->usageConstraints)) { - return false; - } - - return true; -} - -static CFHashCode SecCertificateVCHash(CFTypeRef cf) { - SecCertificateVCRef cvc = (SecCertificateVCRef) cf; - CFHashCode hashCode = 0; - hashCode += CFHash(cvc->certificate); - if (cvc->usageConstraints) { - hashCode += CFHash(cvc->usageConstraints); - } - return hashCode; -} - -static CFStringRef SecCertificateVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - SecCertificateVCRef cvc = (SecCertificateVCRef)cf; - return CFCopyDescription(cvc->certificate); -} - -static bool SecCertificateVCCouldBeEV(SecCertificateRef certificate) { - CFMutableDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - bool isEV = false; - - /* 3. Subscriber Certificate. */ - - /* (a) certificate Policies */ - const SecCECertificatePolicies *cp; - cp = SecCertificateGetCertificatePolicies(certificate); - require_quiet(cp && cp->numPolicies > 0, notEV); - /* Now find at least one policy in here that has a qualifierID of id-qt 2 - and a policyQualifier that is a URI to the CPS and an EV policy OID. */ - uint32_t ix = 0; - bool found_ev_anchor_for_leaf_policy = false; - for (ix = 0; ix < cp->numPolicies; ++ix) { - if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) { - found_ev_anchor_for_leaf_policy = true; - } - } - require_quiet(found_ev_anchor_for_leaf_policy, notEV); - - /* (b) cRLDistributionPoint - (c) authorityInformationAccess - BRv1.3.4: MUST be present with OCSP Responder unless stapled response. - */ - - /* (d) basicConstraints - If present, the cA field MUST be set false. */ - const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); - if (bc) { - require_action_quiet(bc->isCA == false, notEV, - secnotice("ev", "Leaf has invalid basic constraints")); - } - - /* (e) keyUsage. */ - SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); - if (ku) { - require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV, - secnotice("ev", "Leaf has invalid key usage %u", ku)); - } - -#if 0 - /* The EV Cert Spec errata specifies this, though this is a check for SSL - not specifically EV. */ - - /* (e) extKeyUsage - - Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */ - SecCertificateCopyExtendedKeyUsage(certificate); -#endif - - /* 6.1.5 Key Sizes */ - CFAbsoluteTime jan2014 = 410227200; - require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); - require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); - if (SecCertificateNotValidBefore(certificate) < jan2014) { - /* At least RSA 1024 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "Leaf's public key is too small for issuance before 2014")); - } else { - /* At least RSA 2028 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "Leaf's public key is too small for issuance after 2013")); - } - - /* 6.3.2 Validity Periods */ - // Will be checked by the policy server (see SecPolicyCheckValidityPeriodMaximums) - - /* 7.1.3 Algorithm Object Identifiers */ - CFAbsoluteTime jan2016 = 473299200; - if (SecCertificateNotValidBefore(certificate) > jan2016) { - /* SHA-2 only */ - require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, - notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015")); - } - - isEV = true; - -notEV: - CFReleaseNull(rsaSize); - CFReleaseNull(ecSize); - CFReleaseNull(keySizes); - return isEV; -} - - -SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageConstraints) { - if (!certificate) { return NULL; } - CFIndex size = sizeof(struct SecCertificateVC); - SecCertificateVCRef result = - (SecCertificateVCRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, - SecCertificateVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - result->certificate = CFRetainSafe(certificate); - result->isWeakHash = SecCertificateIsWeakHash(certificate); - result->optionallyEV = SecCertificateVCCouldBeEV(certificate); - - CFArrayRef emptyArray = NULL; - if (!usageConstraints) { - require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); - usageConstraints = emptyArray; - } - result->usageConstraints = CFRetainSafe(usageConstraints); -exit: - CFReleaseNull(emptyArray); - return result; -} - -// MARK: - -// MARK: SecCertificatePathVC -/******************************************************** - ************* SecCertificatePathVC object *************** - ********************************************************/ -struct SecCertificatePathVC { - CFRuntimeBase _base; - CFIndex count; - - /* Index of next parent source to search for parents. */ - CFIndex nextParentSource; - - /* Index of last certificate in chain whose signature has been verified. - 0 means nothing has been checked. 1 means the leaf has been verified - against its issuer, etc. */ - CFIndex lastVerifiedSigner; - - /* Index of first self issued certificate in the chain. -1 mean there is - none. 0 means the leaf is self signed. */ - CFIndex selfIssued; - - /* True iff cert at index selfIssued does in fact self verify. */ - bool isSelfSigned; - - /* True if the root of this path is an anchor. Trustedness of the - * anchor is determined by the PVC. */ - bool isAnchored; - - policy_tree_t policy_tree; - uint8_t policy_tree_verification_result; - - bool isEV; - bool isCT; - bool is_allowlisted; - bool hasStrongHashes; - - void * rvcs; - CFIndex rvcCount; - - /* This is the score of the path after determining acceptance. */ - CFIndex score; - - bool pathValidated; - - /* If checkedIssuers is true, then the value of unknownCAIndex contains - * the index of the first CA which violates known-only constraints, or - * -1 if all CA certificates are either known or not constrained. */ - bool checkedIssuers; - CFIndex unknownCAIndex; - - /* Enumerated value to determine whether CT is required for the leaf - * certificate (because a CA in the path has a require-ct constraint). - * If non-zero, CT is required; value indicates overridable status. */ - SecPathCTPolicy requiresCT; - - /* Issuance time, as determined by earliest SCT timestamp for leaf. */ - CFAbsoluteTime issuanceTime; - - SecCertificateVCRef certificates[]; -}; -CFGiblisWithHashFor(SecCertificatePathVC) - -static void SecCertificatePathVCPrunePolicyTree(SecCertificatePathVCRef certificatePath) { - if (certificatePath->policy_tree) { - policy_tree_prune(&certificatePath->policy_tree); - } -} - -void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path) { - if (path->rvcs) { - CFIndex certIX, certCount = path->rvcCount; - for (certIX = 0; certIX < certCount; ++certIX) { - SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; - SecRVCDelete(rvc); - } - free(path->rvcs); - path->rvcs = NULL; - } -} - -static void SecCertificatePathVCDestroy(CFTypeRef cf) { - SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; - CFIndex ix; - SecCertificatePathVCDeleteRVCs(certificatePath); - SecCertificatePathVCPrunePolicyTree(certificatePath); - for (ix = 0; ix < certificatePath->count; ++ix) { - CFReleaseNull(certificatePath->certificates[ix]); - } -} - -static Boolean SecCertificatePathVCCompare(CFTypeRef cf1, CFTypeRef cf2) { - SecCertificatePathVCRef cp1 = (SecCertificatePathVCRef) cf1; - SecCertificatePathVCRef cp2 = (SecCertificatePathVCRef) cf2; - if (cp1->count != cp2->count) - return false; - CFIndex ix; - for (ix = 0; ix < cp1->count; ++ix) { - if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix])) - return false; - } - - return true; -} - -static CFHashCode SecCertificatePathVCHash(CFTypeRef cf) { - SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; - CFHashCode hashCode = 0; - CFIndex ix; - for (ix = 0; ix < certificatePath->count; ++ix) { - hashCode += CFHash(certificatePath->certificates[ix]); - } - return hashCode; -} - -static CFStringRef SecCertificatePathVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; - CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0); - CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf)); - CFStringAppendFormat(desc, NULL, - CFSTR("<%@ certs: "), typeStr); - CFRelease(typeStr); - CFIndex ix; - for (ix = 0; ix < certificatePath->count; ++ix) { - if (ix > 0) { - CFStringAppend(desc, CFSTR(", ")); - } - CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]); - CFStringAppend(desc, str); - CFRelease(str); - } - CFStringAppend(desc, CFSTR(" >")); - - return desc; -} - -/* Create a new certificate path from an old one. */ -SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, - SecCertificateRef certificate, CFArrayRef usageConstraints) { - CFAllocatorRef allocator = kCFAllocatorDefault; - check(certificate); - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - if (path) { - count = path->count + 1; - lastVerifiedSigner = path->lastVerifiedSigner; - selfIssued = path->selfIssued; - isSelfSigned = path->isSelfSigned; - } else { - count = 1; - lastVerifiedSigner = 0; - selfIssued = -1; - isSelfSigned = false; - } - - CFIndex size = sizeof(struct SecCertificatePathVC) + - count * sizeof(SecCertificateRef); - SecCertificatePathVCRef result = - (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - memset((char*)result + sizeof(result->_base), 0, - sizeof(*result) - sizeof(result->_base)); - - result->count = count; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - CFIndex ix; - for (ix = 0; ix < count - 1; ++ix) { - result->certificates[ix] = path->certificates[ix]; - CFRetain(result->certificates[ix]); - } - - SecCertificateVCRef cvc = SecCertificateVCCreate(certificate, usageConstraints); - result->certificates[count - 1] = cvc; - - return result; -} - -SecCertificatePathVCRef SecCertificatePathVCCopyFromParent( - SecCertificatePathVCRef path, CFIndex skipCount) { - CFAllocatorRef allocator = kCFAllocatorDefault; - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - - /* Ensure we are at least returning a path of length 1. */ - if (skipCount < 0 || path->count < 1 + skipCount) - return NULL; - - count = path->count - skipCount; - lastVerifiedSigner = path->lastVerifiedSigner > skipCount - ? path->lastVerifiedSigner - skipCount : 0; - selfIssued = path->selfIssued >= skipCount - ? path->selfIssued - skipCount : -1; - isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false; - - CFIndex size = sizeof(struct SecCertificatePathVC) + - count * sizeof(SecCertificateRef); - SecCertificatePathVCRef result = - (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - memset((char*)result + sizeof(result->_base), 0, - sizeof(*result) - sizeof(result->_base)); - - result->count = count; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - result->isAnchored = path->isAnchored; - CFIndex ix; - for (ix = 0; ix < count; ++ix) { - CFIndex pathIX = ix + skipCount; - result->certificates[ix] = path->certificates[pathIX]; - CFRetain(result->certificates[ix]); - } - - return result; -} - -SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, - SecCertificateRef leaf) { - CFAllocatorRef allocator = kCFAllocatorDefault; - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - - /* First make sure the new leaf is signed by path's current leaf. */ - SecKeyRef issuerKey = SecCertificatePathVCCopyPublicKeyAtIndex(path, 0); - if (!issuerKey) - return NULL; - OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey); - CFRelease(issuerKey); - if (status) - return NULL; - - count = path->count + 1; - lastVerifiedSigner = path->lastVerifiedSigner + 1; - selfIssued = path->selfIssued; - isSelfSigned = path->isSelfSigned; - - CFIndex size = sizeof(struct SecCertificatePathVC) + - count * sizeof(SecCertificateRef); - SecCertificatePathVCRef result = - (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - memset((char*)result + sizeof(result->_base), 0, - sizeof(*result) - sizeof(result->_base)); - - result->count = count; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - result->isAnchored = path->isAnchored; - - CFIndex ix; - for (ix = 1; ix < count; ++ix) { - result->certificates[ix] = path->certificates[ix - 1]; - CFRetain(result->certificates[ix]); - } - SecCertificateVCRef leafVC = SecCertificateVCCreate(leaf, NULL); - result->certificates[0] = leafVC; - - return result; -} - -CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path) { - CFMutableArrayRef outCerts = NULL; - size_t count = path->count; - require_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit); - SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) { - CFArrayAppendValue(outCerts, cert); - }); -exit: - return outCerts; -} - -CFArrayRef SecCertificatePathVCCreateSerialized(SecCertificatePathVCRef path) { - CFMutableArrayRef serializedCerts = NULL; - require_quiet(path, exit); - size_t count = path->count; - require_quiet(serializedCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit); - SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) { - CFDataRef certData = SecCertificateCopyData(cert); - if (certData) { - CFArrayAppendValue(serializedCerts, certData); - CFRelease(certData); - } - }); -exit: - return serializedCerts; -} - - -/* Record the fact that we found our own root cert as our parent - certificate. */ -void SecCertificatePathVCSetSelfIssued( - SecCertificatePathVCRef certificatePath) { - if (certificatePath->selfIssued >= 0) { - secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath, - certificatePath->selfIssued); - return; - } - secdebug("trust", "%@ is self issued", certificatePath); - certificatePath->selfIssued = certificatePath->count - 1; - - /* now check that the selfIssued cert was actually self-signed */ - if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) { - SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->selfIssued]; - Boolean isSelfSigned = false; - OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); - if ((status == errSecSuccess) && isSelfSigned) { - certificatePath->isSelfSigned = true; - } else { - certificatePath->selfIssued = -1; - } - } -} - -void SecCertificatePathVCSetIsAnchored( - SecCertificatePathVCRef certificatePath) { - secdebug("trust", "%@ is anchored", certificatePath); - certificatePath->isAnchored = true; - - /* Now check if that anchor (last cert) was actually self-signed. - * In the non-anchor case, this is handled by SecCertificatePathVCSetSelfIssued. - * Because anchored chains immediately go into the candidate bucket in the trust - * server, we need to ensure that the self-signed/self-issued members are set - * for the purposes of scoring. */ - if (!certificatePath->isSelfSigned && certificatePath->count > 0) { - SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->count - 1]; - Boolean isSelfSigned = false; - OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); - if ((status == errSecSuccess) && isSelfSigned) { - certificatePath->isSelfSigned = true; - if (certificatePath->selfIssued == -1) { - certificatePath->selfIssued = certificatePath->count - 1; - } - } - } -} - -/* Return the index of the first non anchor certificate in the chain that is - self signed counting from the leaf up. Return -1 if there is none. */ -CFIndex SecCertificatePathVCSelfSignedIndex( - SecCertificatePathVCRef certificatePath) { - if (certificatePath->isSelfSigned) - return certificatePath->selfIssued; - return -1; -} - -Boolean SecCertificatePathVCIsAnchored( - SecCertificatePathVCRef certificatePath) { - return certificatePath->isAnchored; -} - - -void SecCertificatePathVCSetNextSourceIndex( - SecCertificatePathVCRef certificatePath, CFIndex sourceIndex) { - certificatePath->nextParentSource = sourceIndex; -} - -CFIndex SecCertificatePathVCGetNextSourceIndex( - SecCertificatePathVCRef certificatePath) { - return certificatePath->nextParentSource; -} - -CFIndex SecCertificatePathVCGetCount( - SecCertificatePathVCRef certificatePath) { - check(certificatePath); - return certificatePath ? certificatePath->count : 0; -} - -SecCertificateRef SecCertificatePathVCGetCertificateAtIndex( - SecCertificatePathVCRef certificatePath, CFIndex ix) { - if (!certificatePath || ix < 0 || ix >= certificatePath->count) { - return NULL; - } - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - return cvc ? cvc->certificate : NULL; -} - -void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)) { - bool stop = false; - CFIndex ix, count = path->count; - for (ix = 0; ix < count; ++ix) { - SecCertificateVCRef cvc = path->certificates[ix]; - operation(cvc->certificate, &stop); - if (stop) { break; } - } -} - -CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, - SecCertificateRef certificate) { - CFIndex ix, count = path->count; - for (ix = 0; ix < count; ++ix) { - SecCertificateVCRef cvc = path->certificates[ix]; - if (CFEqual(cvc->certificate, certificate)) - return ix; - } - return kCFNotFound; -} - -/* Return the root certificate for certificatePath. Note that root is just - the top of the path as far as it is constructed. It may or may not be - trusted or self signed. */ -SecCertificateRef SecCertificatePathVCGetRoot( - SecCertificatePathVCRef certificatePath) { - return SecCertificatePathVCGetCertificateAtIndex(certificatePath, - SecCertificatePathVCGetCount(certificatePath) - 1); -} - -SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex( - SecCertificatePathVCRef certificatePath, CFIndex ix) { - SecCertificateRef certificate = - SecCertificatePathVCGetCertificateAtIndex(certificatePath, ix); - return SecCertificateCopyKey(certificate); -} - -CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex( - SecCertificatePathVCRef certificatePath, CFIndex ix) { - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - return cvc->usageConstraints; -} - -void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, - CFArrayRef newConstraints, CFIndex ix) { - CFArrayRef emptyArray = NULL; - if (!newConstraints) { - require_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit); - newConstraints = emptyArray; - } - - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - cvc->usageConstraints = CFRetainSafe(newConstraints); -exit: - CFReleaseNull(emptyArray); - return; -} - -SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath) { - check(certificatePath); - if (!certificatePath) - return kSecPathVerifyFailed; - for (; - certificatePath->lastVerifiedSigner < certificatePath->count - 1; - ++certificatePath->lastVerifiedSigner) { - SecKeyRef issuerKey = - SecCertificatePathVCCopyPublicKeyAtIndex(certificatePath, - certificatePath->lastVerifiedSigner + 1); - if (!issuerKey) - return kSecPathVerifiesUnknown; - SecCertificateVCRef cvc = certificatePath->certificates[certificatePath->lastVerifiedSigner]; - OSStatus status = SecCertificateIsSignedBy(cvc->certificate, - issuerKey); - CFRelease(issuerKey); - if (status) { - return kSecPathVerifyFailed; - } - } - - return kSecPathVerifySuccess; -} - -/* Is the the issuer of the last cert a subject of a previous cert in the chain.See . */ -bool SecCertificatePathVCIsCycleInGraph(SecCertificatePathVCRef path) { - bool isCircle = false; - CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(SecCertificatePathVCGetRoot(path)); - if (!issuer) { return isCircle; } - CFIndex ix = path->count - 2; - for (; ix >= 0; ix--) { - SecCertificateVCRef cvc = path->certificates[ix]; - CFDataRef subject = SecCertificateGetNormalizedSubjectContent(cvc->certificate); - if (subject && CFEqual(issuer, subject)) { - isCircle = true; - break; - } - } - return isCircle; -} - -bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) { - __block bool result = true; - SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { - if (!SecCertificateIsValid(certificate, verifyTime)) { - result = false; - } - }); - return result; -} - -bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath) { - CFIndex ix, count = certificatePath->count; - - if (certificatePath->hasStrongHashes) { - return false; - } - - if (SecCertificatePathVCIsAnchored(certificatePath)) { - /* For anchored paths, don't check the hash algorithm of the anchored cert, - * since we already decided to trust it. */ - count--; - } - for (ix = 0; ix < count; ++ix) { - if (certificatePath->certificates[ix]->isWeakHash) { - return true; - } - } - certificatePath->hasStrongHashes = true; - return false; -} - -bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath) { - __block CFDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - __block bool result = false; - - /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */ - require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut); - require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut); - const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; - const void *values[] = { rsaSize, ecSize }; - require(keySizes = CFDictionaryCreate(NULL, keys, values, 2, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { - if (!SecCertificateIsAtLeastMinKeySize(certificate, keySizes)) { - result = true; - *stop = true; - } - }); - -errOut: - CFReleaseSafe(keySizes); - CFReleaseSafe(rsaSize); - CFReleaseSafe(ecSize); - return result; -} - -/* Return a score for this certificate chain. */ -CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) { - CFIndex score = 0; - - /* Paths that don't verify score terribly.c */ - if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) { - secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex, - certificatePath->lastVerifiedSigner, certificatePath->count); - score -= 100000; - } - - if (certificatePath->isAnchored) { - /* Anchored paths for the win! */ - score += 10000; - } - - if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) { - /* Chains that terminate in a self-signed certificate are preferred, - even if they don't end in an anchor. */ - score += 1000; - /* Shorter chains ending in a self-signed cert are preferred. */ - score -= 1 * certificatePath->count; - } else { - /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */ - score += 1 * certificatePath->count; - } - - if (SecCertificatePathVCIsValid(certificatePath, verifyTime)) { - score += 100; - } - - if (!SecCertificatePathVCHasWeakHash(certificatePath)) { - score += 10; - } - - if (!SecCertificatePathVCHasWeakKeySize(certificatePath)) { - score += 10; - } - - return score; -} - -CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return 0; } - return certificatePath->score; -} - -void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score) { - /* We may "score" the same path twice -- if we "accept" a path but then - * decide to keep looking for a better one, we we process the same path - * again in "reject" which creates a lower score. Don't replace a higher - * score with a lower score. Use reset below to post-reject a path. */ - if (score > certificatePath->score) { - certificatePath->score = score; - } -} - -void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath) { - certificatePath->score = 0; -} - -void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix) { - if (ix >= certificatePath->rvcCount) { - return NULL; - } - return &((SecRVCRef)certificatePath->rvcs)[ix]; -} - -bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath) { - return (bool)certificatePath->rvcs; -} - -void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount) { - certificatePath->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount); - certificatePath->rvcCount = certCount; -} - -/* Return 0 if any certs revocation checking failed, or the earliest date on - which one of the used revocation validation tokens (ocsp response or - crl) expires. */ -/* This function returns 0 to indicate revocation checking was not completed - for this certificate chain, otherwise returns the date at which the first - piece of revocation checking info we used expires. */ -CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path) { - CFIndex certIX, certCount = path->count; - CFAbsoluteTime enu = NULL_TIME; - if (certCount <= 1 || !path->rvcs) { - return enu; - } - - for (certIX = 0; certIX < path->rvcCount; ++certIX) { - SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; - CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc); - if (thisCertNextUpdate == 0) { - if (certIX > 0) { - /* We allow for CA certs to not be revocation checked if they - have no ocspResponders to check against, but the leaf - must be checked in order for us to claim we did revocation - checking. */ - SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX); - CFArrayRef ocspResponders = NULL; - ocspResponders = SecCertificateGetOCSPResponders(cert); - if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) { - /* We can't check this cert so we don't consider it a soft - failure that we didn't. */ - continue; - } - } - /* Make sure to always skip roots for whom we can't check revocation */ - if (certIX == certCount - 1) { - continue; - } - secdebug("rvc", "revocation checking soft failure for cert: %ld", - certIX); - enu = thisCertNextUpdate; - break; - } - if (enu == 0 || thisCertNextUpdate < enu) { - enu = thisCertNextUpdate; - } - } - - secdebug("rvc", "revocation valid until: %lg", enu); - return enu; -} - -void SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix, CFNumberRef revocationReason) { - if (ix > certificatePath->count - 1) { return; } - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - cvc->revocationReason = CFRetainSafe(revocationReason); -} - -CFNumberRef SecCertificatePathVCGetRevocationReason(SecCertificatePathVCRef certificatePath) { - for (CFIndex ix = 0; ix < certificatePath->count; ix++) { - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - if (cvc->revocationReason) { - return cvc->revocationReason; - } - } - return NULL; -} - -bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix) { - if (ix > certificatePath->count - 1) { return false; } - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - return cvc->require_revocation_response; -} - -void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix) { - if (ix > certificatePath->count - 1) { return; } - SecCertificateVCRef cvc = certificatePath->certificates[ix]; - cvc->require_revocation_response = true; -} - -bool SecCertificatePathVCCheckedIssuers(SecCertificatePathVCRef certificatePath) { - return certificatePath->checkedIssuers; -} - -void SecCertificatePathVCSetCheckedIssuers(SecCertificatePathVCRef certificatePath, bool checked) { - certificatePath->checkedIssuers = checked; -} - -CFIndex SecCertificatePathVCUnknownCAIndex(SecCertificatePathVCRef certificatePath) { - return certificatePath->unknownCAIndex; -} - -void SecCertificatePathVCSetUnknownCAIndex(SecCertificatePathVCRef certificatePath, CFIndex index) { - certificatePath->unknownCAIndex = index; -} - -bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return false; } - return certificatePath->pathValidated; -} - -void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath) { - certificatePath->pathValidated = true; -} - -bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return false; } - return certificatePath->isEV; -} - -void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV) { - certificatePath->isEV = isEV; -} - -bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return false; } - return certificatePath->certificates[0]->optionallyEV; -} - -bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return false; } - return certificatePath->isCT; -} - -void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT) { - certificatePath->isCT = isCT; -} - -SecPathCTPolicy SecCertificatePathVCRequiresCT(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return kSecPathCTNotRequired; } - return certificatePath->requiresCT; -} - -void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath, SecPathCTPolicy requiresCT) { - if (certificatePath->requiresCT > requiresCT) { - return; /* once set, CT policy may be only be changed to a more strict value */ - } - certificatePath->requiresCT = requiresCT; -} - -CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return 0; } - return certificatePath->issuanceTime; -} - -void SecCertificatePathVCSetIssuanceTime(SecCertificatePathVCRef certificatePath, CFAbsoluteTime issuanceTime) { - certificatePath->issuanceTime = issuanceTime; -} - -bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath) { - if (!certificatePath) { return false; } - return certificatePath->is_allowlisted; -} - -void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted) { - certificatePath->is_allowlisted = isAllowlisted; -} - -/* MARK: policy_tree path verification */ -struct policy_tree_add_ctx { - oid_t p_oid; - policy_qualifier_t p_q; -}; - -/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ -static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) { - struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; - policy_set_t policy_set; - for (policy_set = node->expected_policy_set; - policy_set; - policy_set = policy_set->oid_next) { - if (oid_equal(policy_set->oid, info->p_oid)) { - policy_tree_add_child(node, &info->p_oid, info->p_q); - return true; - } - } - return false; -} - -/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ -static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) { - struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; - if (oid_equal(node->valid_policy, oidAnyPolicy)) { - policy_tree_add_child(node, &info->p_oid, info->p_q); - return true; - } - return false; -} - -/* Return true iff node has a child with a valid_policy equal to oid. */ -static bool policy_tree_has_child_with_oid(policy_tree_t node, - const oid_t *oid) { - policy_tree_t child; - for (child = node->children; child; child = child->siblings) { - if (oid_equal(child->valid_policy, (*oid))) { - return true; - } - } - return false; -} - -/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */ -static bool policy_tree_add_expected(policy_tree_t node, void *ctx) { - policy_qualifier_t p_q = (policy_qualifier_t)ctx; - policy_set_t policy_set; - bool added_node = false; - for (policy_set = node->expected_policy_set; - policy_set; - policy_set = policy_set->oid_next) { - if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) { - policy_tree_add_child(node, &policy_set->oid, p_q); - added_node = true; - } - } - return added_node; -} - -/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ -static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) { - /* Can't map oidAnyPolicy. */ - if (oid_equal(node->valid_policy, oidAnyPolicy)) - return false; - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - policy_set_t policy_set = NULL; - /* Generate the policy_set of sdps for matching idp */ - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { - policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set)); - p_node->oid = mapping->subjectDomainPolicy; - p_node->oid_next = policy_set ? policy_set : NULL; - policy_set = p_node; - } - } - if (policy_set) { - policy_tree_set_expected_policy(node, policy_set); - return true; - } - return false; -} - -/* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows: - (i) set the valid_policy to ID-P; - (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and - (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ -static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) { - if (!oid_equal(node->valid_policy, oidAnyPolicy)) { - return false; - } - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - CFMutableDictionaryRef mappings = NULL; - CFDataRef idp = NULL; - CFDataRef sdp = NULL; - require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), - errOut); - /* First we need to walk the mappings to generate the dictionary idp->sdps */ - for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) { - oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy; - oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy; - idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull); - sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull); - CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); - if (sdps) { - CFArrayAppendValue(sdps, sdp); - } else { - require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks), errOut); - CFArrayAppendValue(sdps, sdp); - CFDictionarySetValue(mappings, idp, sdps); - CFRelease(sdps); - } - CFReleaseNull(idp); - CFReleaseNull(sdp); - } - - /* Now we use the dictionary to generate the new nodes */ - CFDictionaryForEach(mappings, ^(const void *key, const void *value) { - CFDataRef idp = key; - CFArrayRef sdps = value; - - /* (i) set the valid_policy to ID-P; */ - oid_t p_oid; - p_oid.data = (uint8_t *)CFDataGetBytePtr(idp); - p_oid.length = CFDataGetLength(idp); - - /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */ - policy_qualifier_t p_q = node->qualifier_set; - - /* (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ - __block policy_set_t p_expected = NULL; - CFArrayForEach(sdps, ^(const void *value) { - policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected)); - p_node->oid.data = (void *)CFDataGetBytePtr(value); - p_node->oid.length = CFDataGetLength(value); - p_node->oid_next = p_expected ? p_expected : NULL; - p_expected = p_node; - }); - - policy_tree_add_sibling(node, &p_oid, p_q, p_expected); - }); - CFReleaseNull(mappings); - return true; - -errOut: - CFReleaseNull(mappings); - CFReleaseNull(idp); - CFReleaseNull(sdp); - return false; -} - -static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) { - /* Can't map oidAnyPolicy. */ - if (oid_equal(node->valid_policy, oidAnyPolicy)) - return false; - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - /* If this node matches any of the idps, delete it. */ - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { - policy_tree_remove_node(&node); - break; - } - } - return true; -} - -bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix) { - /* The SecCertificatePath only tells us the last self-issued cert. - * The chain may have more than one self-issued cert, so we need to - * do the comparison. */ - bool result = false; - SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, ix); - CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert); - CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert); - if (issuer && subject && CFEqual(issuer, subject)) { - result = true; - } - CFReleaseNull(issuer); - CFReleaseNull(subject); - return result; -} - -enum { - kSecPolicyTreeVerificationUnknown = 0, - kSecPolicyTreeVerificationFalse, - kSecPolicyTreeVerificationTrue, -}; - -/* RFC 5280 policy tree processing */ -bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted) { - if (!path) { return false; } - if (path->policy_tree_verification_result != kSecPolicyTreeVerificationUnknown) { - return (path->policy_tree_verification_result == kSecPolicyTreeVerificationTrue); - } - - /* Path Validation initialization */ - bool result = false; - path->policy_tree_verification_result = kSecPolicyTreeVerificationFalse; - bool initial_policy_mapping_inhibit = false; - bool initial_explicit_policy = false; - bool initial_any_policy_inhibit = false; - - SecCertificatePathVCPrunePolicyTree(path); - path->policy_tree = policy_tree_create(&oidAnyPolicy, NULL); - - assert((unsigned long)path->count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ - uint32_t n = (uint32_t)path->count; - if (anchor_trusted) { - n--; - } - - uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1; - uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1; - uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1; - - SecCertificateRef cert = NULL; - uint32_t i; - for (i = 1; i <= n; ++i) { - /* Process Cert */ - cert = SecCertificatePathVCGetCertificateAtIndex(path, n - i); - bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(path, n - i); - - /* (d) */ - if (path->policy_tree) { - const SecCECertificatePolicies *cp = - SecCertificateGetCertificatePolicies(cert); - size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; - for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { - const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; - oid_t p_oid = policy->policyIdentifier; - policy_qualifier_t p_q = &policy->policyQualifiers; - struct policy_tree_add_ctx ctx = { p_oid, p_q }; - if (!oid_equal(p_oid, oidAnyPolicy)) { - if (!policy_tree_walk_depth(path->policy_tree, i - 1, - policy_tree_add_if_match, &ctx)) { - policy_tree_walk_depth(path->policy_tree, i - 1, - policy_tree_add_if_any, &ctx); - } - } - } - /* The certificate policies extension includes the policy - anyPolicy with the qualifier set AP-Q and either - (a) inhibit_anyPolicy is greater than 0 or - (b) i < n and the certificate is self-issued. */ - if (inhibit_any_policy > 0 || (i < n && is_self_issued)) { - for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { - const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; - oid_t p_oid = policy->policyIdentifier; - policy_qualifier_t p_q = &policy->policyQualifiers; - if (oid_equal(p_oid, oidAnyPolicy)) { - policy_tree_walk_depth(path->policy_tree, i - 1, - policy_tree_add_expected, (void *)p_q); - } - } - } - - policy_tree_prune_childless(&path->policy_tree, i - 1); - /* (e) */ - if (!cp) { - SecCertificatePathVCPrunePolicyTree(path); - } - } - - /* (f) Verify that either explicit_policy is greater than 0 or the - valid_policy_tree is not equal to NULL. */ - if (!path->policy_tree && explicit_policy == 0) { - /* valid_policy_tree is empty and explicit policy is 0, illegal. */ - secnotice("policy", "policy tree failure on cert %u", n - i); - goto errOut; - } - /* If Last Cert in Path */ - if (i == n) - break; - - /* Prepare for Next Cert */ - /* (a) verify that anyPolicy does not appear as an - issuerDomainPolicy or a subjectDomainPolicy */ - const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert); - if (pm && pm->present) { - size_t mapping_ix, mapping_count = pm->numMappings; - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy) - || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) { - /* Policy mapping uses anyPolicy, illegal. */ - secnotice("policy", "policy mapping anyPolicy failure %u", n - i); - goto errOut; - } - } - - /* (b) */ - /* (1) If the policy_mapping variable is greater than 0 */ - if (policy_mapping > 0 && path->policy_tree) { - if (!policy_tree_walk_depth(path->policy_tree, i, - policy_tree_map_if_match, (void *)pm)) { - /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1. */ - policy_tree_walk_depth(path->policy_tree, i, policy_tree_map_if_any, (void *)pm); - } - } else if (path->policy_tree) { - /* (i) delete each node of depth i in the valid_policy_tree - where ID-P is the valid_policy. */ - policy_tree_walk_depth(path->policy_tree, i, - policy_tree_map_delete_if_match, (void *)pm); - /* (ii) If there is a node in the valid_policy_tree of depth - i-1 or less without any child nodes, delete that - node. Repeat this step until there are no nodes of - depth i-1 or less without children. */ - policy_tree_prune_childless(&path->policy_tree, i - 1); - } - } - - /* (h) */ - if (!is_self_issued) { - if (explicit_policy) - explicit_policy--; - if (policy_mapping) - policy_mapping--; - if (inhibit_any_policy) - inhibit_any_policy--; - } - /* (i) */ - const SecCEPolicyConstraints *pc = - SecCertificateGetPolicyConstraints(cert); - if (pc) { - if (pc->requireExplicitPolicyPresent - && pc->requireExplicitPolicy < explicit_policy) { - explicit_policy = pc->requireExplicitPolicy; - } - if (pc->inhibitPolicyMappingPresent - && pc->inhibitPolicyMapping < policy_mapping) { - policy_mapping = pc->inhibitPolicyMapping; - } - } - /* (j) */ - const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert); - if (iap && iap->skipCerts < inhibit_any_policy) { - inhibit_any_policy = iap->skipCerts; - } - - } /* end of path for loop */ - - /* Wrap up */ - cert = SecCertificatePathVCGetCertificateAtIndex(path, 0); - /* (a) */ - if (explicit_policy) - explicit_policy--; - /* (b) */ - const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert); - if (pc) { - if (pc->requireExplicitPolicyPresent - && pc->requireExplicitPolicy == 0) { - explicit_policy = 0; - } - } - - /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */ - - if (path->policy_tree) { -#if !defined(NDEBUG) - policy_tree_dump(path->policy_tree); -#endif - /* (g3c4) */ - //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1); - } - - /* If either (1) the value of explicit_policy variable is greater than - zero or (2) the valid_policy_tree is not NULL, then path processing - has succeeded. */ - if (!path->policy_tree && explicit_policy == 0) { - /* valid_policy_tree is empty and explicit policy is 0, illegal. */ - secnotice("policy", "policy tree failure on leaf"); - goto errOut; - } - - path->policy_tree_verification_result = kSecPolicyTreeVerificationTrue; - result = true; - -errOut: - return result; -} diff --git a/OSX/sec/securityd/SecCertificateServer.h b/OSX/sec/securityd/SecCertificateServer.h deleted file mode 100644 index 96b3b44b..00000000 --- a/OSX/sec/securityd/SecCertificateServer.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecCertificateServer.h - SecCertificate and SecCertificatePath types - * with additonal validation context. - */ - - -#ifndef _SECURITY_SECCERTIFICATESERVER_H_ -#define _SECURITY_SECCERTIFICATESERVER_H_ - -#include - -#include - -#include "securityd/policytree.h" - - -typedef struct SecCertificateVC *SecCertificateVCRef; - -SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageContraints); - -typedef struct SecCertificatePathVC *SecCertificatePathVCRef; - -/* Create a new certificate path from an old one. */ -SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, - SecCertificateRef certificate, CFArrayRef usageConstraints); - -SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, - SecCertificateRef leaf); - -/* Return a new certificate path without the first skipCount certificates. */ -SecCertificatePathVCRef SecCertificatePathVCCopyFromParent(SecCertificatePathVCRef path, CFIndex skipCount); - -/* Create an array of SecCertificateRefs from a certificate path. */ -CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path); - -/* Create an array of CFDataRefs from a certificate path. */ -CFArrayRef SecCertificatePathVCCreateSerialized(SecCertificatePathVCRef path); - -/* Record the fact that we found our own root cert as our parent - certificate. */ -void SecCertificatePathVCSetSelfIssued(SecCertificatePathVCRef certificatePath); -bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix); - -void SecCertificatePathVCSetIsAnchored(SecCertificatePathVCRef certificatePath); - -/* Return the index of the first non anchor certificate in the chain that is - self signed counting from the leaf up. Return -1 if there is none. */ -CFIndex SecCertificatePathVCSelfSignedIndex(SecCertificatePathVCRef certificatePath); - -Boolean SecCertificatePathVCIsAnchored(SecCertificatePathVCRef certificatePath); - -void SecCertificatePathVCSetNextSourceIndex(SecCertificatePathVCRef certificatePath, CFIndex sourceIndex); - -CFIndex SecCertificatePathVCGetNextSourceIndex(SecCertificatePathVCRef certificatePath); - -CFIndex SecCertificatePathVCGetCount(SecCertificatePathVCRef certificatePath); - -SecCertificateRef SecCertificatePathVCGetCertificateAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); - -void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)); - -/* Return the index of certificate in path or kCFNotFound if certificate is - not in path. */ -CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, - SecCertificateRef certificate); - -/* Return the root certificate for certificatePath. Note that root is just - the top of the path as far as it is constructed. It may or may not be - trusted or self signed. */ -SecCertificateRef SecCertificatePathVCGetRoot(SecCertificatePathVCRef certificatePath); - -CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); - -void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, - CFArrayRef newConstraints, CFIndex ix); - -SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); - -typedef CFIndex SecPathVerifyStatus; -enum { - kSecPathVerifiesUnknown = -1, - kSecPathVerifySuccess = 0, - kSecPathVerifyFailed = 1 -}; - -SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath); - -bool SecCertificatePathVCIsCycleInGraph(SecCertificatePathVCRef path); - -bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime); - -bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath); - -bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath); - -/* Score */ -CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, - CFAbsoluteTime verifyTime); -CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score); // only sets score if new score is higher -void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath); // reset score to 0 - -/* Revocation */ -void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path); -bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount); -CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path); -void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); // Returns a SecRVCRef -bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix); -void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix); -void SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(SecCertificatePathVCRef certificatePath, - CFIndex ix, CFNumberRef revocationReason); -CFNumberRef SecCertificatePathVCGetRevocationReason(SecCertificatePathVCRef certificatePath); // returns first revocation reason found - -bool SecCertificatePathVCCheckedIssuers(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetCheckedIssuers(SecCertificatePathVCRef certificatePath, bool checked); -CFIndex SecCertificatePathVCUnknownCAIndex(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetUnknownCAIndex(SecCertificatePathVCRef certificatePath, CFIndex index); - -/* Did we already validate this path (setting EV, CT, RVC, etc.) */ -bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath); - -/* EV */ -bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV); -bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath); - -/* CT */ -typedef CFIndex SecPathCTPolicy; -enum { - kSecPathCTNotRequired = 0, - kSecPathCTRequiredOverridable = 1, - kSecPathCTRequired = 2 -}; -bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT); -SecPathCTPolicy SecCertificatePathVCRequiresCT(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath, SecPathCTPolicy requiresCT); -CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetIssuanceTime(SecCertificatePathVCRef certificatePath, CFAbsoluteTime issuanceTime); - -/* Allowlist */ -bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath); -void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted); - -/* Policy Tree */ -bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted); - -#endif /* _SECURITY_SECCERTIFICATESERVER_H_ */ diff --git a/OSX/sec/securityd/SecCertificateSource.c b/OSX/sec/securityd/SecCertificateSource.c deleted file mode 100644 index 26464069..00000000 --- a/OSX/sec/securityd/SecCertificateSource.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecCertificateSource.c - certificate sources for trust evaluation engine - * - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "OTATrustUtilities.h" -#include "SecCertificateSource.h" - -/******************************************************** - ***************** OTA Trust support ******************** - ********************************************************/ - - -//#ifndef SECITEM_SHIM_OSX - -static CFArrayRef subject_to_anchors(CFDataRef nic); -static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets); - -static CFArrayRef subject_to_anchors(CFDataRef nic) -{ - CFArrayRef result = NULL; - - if (NULL == nic) - { - return result; - } - - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) - { - return result; - } - - CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref); - CFRelease(otapkiref); - - if (NULL == lookupTable) - { - return result; - } - - unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH]; - memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH); - - (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest); - CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull); - - - result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest); - CFReleaseSafe(lookupTable); - CFReleaseSafe(sha1Digest); - - return result; -} - -static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets) -{ - CFMutableArrayRef result = NULL; - - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiref) - { - return result; - } - - const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref); - if (NULL == anchorTable) - { - CFReleaseSafe(otapkiref); - return result; - } - - CFIndex num_offsets = CFArrayGetCount(offsets); - - result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - - for (CFIndex idx = 0; idx < num_offsets; idx++) - { - CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx); - uint32_t offset_value = 0; - if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value)) - { - char* pDataPtr = (char *)(anchorTable + offset_value); - //int32_t record_length = *((int32_t * )pDataPtr); - //record_length = record_length; - pDataPtr += sizeof(uint32_t); - - int32_t cert_data_length = *((int32_t * )pDataPtr); - pDataPtr += sizeof(uint32_t); - - CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr, - cert_data_length, kCFAllocatorNull); - if (NULL != cert_data) - { - CFArrayAppendValue(result, cert_data); - CFReleaseSafe(cert_data); - } - } - } - CFReleaseSafe(otapkiref); - return result; -} - -static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets) -{ - CFMutableArrayRef result = NULL; - - CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets); - - if (NULL != cert_data_array) - { - result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFIndex num_cert_datas = CFArrayGetCount(cert_data_array); - for (CFIndex idx = 0; idx < num_cert_datas; idx++) - { - CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx); - if (NULL != cert_data) - { - SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data); - if (NULL != cert) - { - CFArrayAppendValue(result, cert); - CFRelease(cert); - } - } - } - CFRelease(cert_data_array); - } - return result; - -} -//#endif // SECITEM_SHIM_OSX - -/******************************************************** - *************** END OTA Trust support ****************** - ********************************************************/ - -/******************************************************** - ************ SecCertificateSource object *************** - ********************************************************/ - -bool SecCertificateSourceCopyParents(SecCertificateSourceRef source, - SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - return source->copyParents(source, certificate, context, callback); -} - -CFArrayRef SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source, - SecCertificateRef certificate) { - if (source->copyUsageConstraints) { - return source->copyUsageConstraints(source, certificate); - } else { - return NULL; - } -} - -bool SecCertificateSourceContains(SecCertificateSourceRef source, - SecCertificateRef certificate) { - return source->contains(source, certificate); -} - -// MARK: - -// MARK: SecItemCertificateSource -/******************************************************** - *********** SecItemCertificateSource object ************ - ********************************************************/ -struct SecItemCertificateSource { - struct SecCertificateSource base; - CFArrayRef accessGroups; -}; -typedef struct SecItemCertificateSource *SecItemCertificateSourceRef; - -static CF_RETURNS_RETAINED CFArrayRef _Nullable SecItemCertificateSourceResultsPost(CFTypeRef raw_results) { - CFMutableArrayRef result = NULL; - if (isArray(raw_results)) { - result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); - CFArrayForEach(raw_results, ^(const void *value) { - SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value); - if (cert) { - CFArrayAppendValue(result, cert); - CFRelease(cert); - } - }); - } else if (isData(raw_results)) { - result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); - SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results); - if (cert) { - CFArrayAppendValue(result, cert); - CFRelease(cert); - } - } - return result; -} - -static bool SecItemCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; - CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); - - CFErrorRef localError = NULL; - CFArrayRef results = SecItemCopyParentCertificates_ios(normalizedIssuer, msource->accessGroups, &localError); - if (!results) { - if (localError && (CFErrorGetCode(localError) != errSecItemNotFound)) { - secdebug("trust", "SecItemCopyParentCertificates_ios: %@", localError); - } - CFReleaseSafe(localError); - } - CFArrayRef certs = SecItemCertificateSourceResultsPost(results); - CFReleaseSafe(results); - callback(context, certs); - CFReleaseSafe(certs); - return true; -} - -static bool SecItemCertificateSourceContains(SecCertificateSourceRef source, - SecCertificateRef certificate) { - SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; - /* Look up a certificate by issuer and serial number. */ - CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); - CFRetainSafe(normalizedIssuer); - CFErrorRef localError = NULL; - CFDataRef serialNumber = SecCertificateCopySerialNumberData(certificate, &localError); - bool result = SecItemCertificateExists(normalizedIssuer, serialNumber, msource->accessGroups, &localError); - if (localError) { - if (CFErrorGetCode(localError) != errSecItemNotFound) { - secdebug("trust", "SecItemCertificateExists_ios: %@", localError); - } - CFReleaseSafe(localError); - } - CFReleaseSafe(serialNumber); - CFReleaseSafe(normalizedIssuer); - return result; -} - -SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) { - SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result)); - result->base.copyParents = SecItemCertificateSourceCopyParents; - result->base.copyUsageConstraints = NULL; - result->base.contains = SecItemCertificateSourceContains; - result->accessGroups = accessGroups; - CFRetainSafe(accessGroups); - return (SecCertificateSourceRef)result; -} - -void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) { - SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; - CFReleaseSafe(msource->accessGroups); - free(msource); -} - -// MARK: - -// MARK: SecSystemAnchorSource -/******************************************************** - *********** SecSystemAnchorSource object ************ - ********************************************************/ - -static bool SecSystemAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - CFArrayRef parents = NULL; - CFArrayRef anchors = NULL; - - CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); - /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor. - It does not matter since we would be returning the wrong anchors */ - assert((unsigned long)CFDataGetLength(nic)subjects, - normalizedIssuer) : NULL; - /* FIXME filter parents by subjectID if certificate has an - authorityKeyIdentifier. */ - secdebug("trust", "%@ parents -> %@", certificate, parents); - callback(context, parents); - return true; -} - -static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source, - SecCertificateRef certificate) { - SecMemoryCertificateSourceRef msource = - (SecMemoryCertificateSourceRef)source; - return CFSetContainsValue(msource->certificates, certificate); -} - -static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict, - const void *key, const void *value) { - if (!key) - return; - - CFMutableArrayRef values = - (CFMutableArrayRef)CFDictionaryGetValue(dict, key); - if (!values) { - values = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks); - CFDictionaryAddValue(dict, key, values); - CFRelease(values); - } - - if (values) - CFArrayAppendValue(values, value); -} - -static void SecMemoryCertificateSourceApplierFunction(const void *value, void *context) { - SecMemoryCertificateSourceRef msource = - (SecMemoryCertificateSourceRef)context; - SecCertificateRef certificate = (SecCertificateRef)value; - - /* CFSet's API has no way to combine these 2 operations into 1 sadly. */ - if (CFSetContainsValue(msource->certificates, certificate)) - return; - CFSetAddValue(msource->certificates, certificate); - - CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate); - dictAddValueToArrayForKey(msource->subjects, key, value); -} - -SecCertificateSourceRef SecMemoryCertificateSourceCreate(CFArrayRef certificates) { - SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef) - malloc(sizeof(*result)); - result->base.copyParents = SecMemoryCertificateSourceCopyParents; - result->base.copyUsageConstraints = NULL; - result->base.contains = SecMemoryCertificateSourceContains; - CFIndex count = CFArrayGetCount(certificates); - result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count, - &kCFTypeSetCallBacks); - result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault, - count, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFRange range = { 0, count }; - CFArrayApplyFunction(certificates, range, - SecMemoryCertificateSourceApplierFunction, result); - - return (SecCertificateSourceRef)result; -} - -void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source) { - SecMemoryCertificateSourceRef msource = - (SecMemoryCertificateSourceRef)source; - CFRelease(msource->certificates); - CFRelease(msource->subjects); - free(msource); -} - -// MARK: - -// MARK: SecCAIssuerCertificateSource -/******************************************************** - ********* SecCAIssuerCertificateSource object ********** - ********************************************************/ -static bool SecCAIssuerCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - /* Some expired certs have dead domains. Let's not check them. */ - SecPathBuilderRef builder = (SecPathBuilderRef)context; - CFAbsoluteTime verifyDate = SecPathBuilderGetVerifyTime(builder); - if (SecPathBuilderHasTemporalParentChecks(builder) && !SecCertificateIsValid(certificate, verifyDate)) { - secinfo("async", "skipping CAIssuer fetch for expired %@", certificate); - callback(context, NULL); - return true; - } - return SecCAIssuerCopyParents(certificate, context, callback); -} - -static bool SecCAIssuerCertificateSourceContains(SecCertificateSourceRef source, SecCertificateRef certificate) { - return false; -} - -struct SecCertificateSource _kSecCAIssuerSource = { - SecCAIssuerCertificateSourceCopyParents, - NULL, - SecCAIssuerCertificateSourceContains -}; - -const SecCertificateSourceRef kSecCAIssuerSource = &_kSecCAIssuerSource; - -#if TARGET_OS_OSX -#include -// MARK: - -// MARK: SecLegacyCertificateSource -/******************************************************** - ********** SecLegacyCertificateSource object *********** - ********************************************************/ - -static bool SecLegacyCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); - callback(context, parents); - CFReleaseSafe(parents); - return true; -} - -static bool SecLegacyCertificateSourceContains(SecCertificateSourceRef source, SecCertificateRef certificate) { - SecCertificateRef cert = SecItemCopyStoredCertificate(certificate, NULL); - bool result = (cert) ? true : false; - CFReleaseSafe(cert); - return result; -} - -struct SecCertificateSource _kSecLegacyCertificateSource = { - SecLegacyCertificateSourceCopyParents, - NULL, - SecLegacyCertificateSourceContains -}; - -const SecCertificateSourceRef kSecLegacyCertificateSource = &_kSecLegacyCertificateSource; - -#endif /* SecLegacyCertificateSource */ - -#if TARGET_OS_OSX -// MARK: - -// MARK: SecLegacyAnchorSource -/******************************************************** - ************ SecLegacyAnchorSource object ************** - ********************************************************/ - -static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback) { - CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); - CFArrayRef trusted = NULL; - if (parents == NULL) { - goto finish; - } - /* Get the custom anchors which have been trusted in the user and admin domains. - * We don't need system domain roots here, since SecSystemAnchorSource provides those. - */ - OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted); - if (status == errSecSuccess && trusted) { - CFIndex index, count = CFArrayGetCount(parents); - for (index = 0; index < count; index++) { - SecCertificateRef parent = (SecCertificateRef)CFArrayGetValueAtIndex(parents, index); - if (parent && CFArrayContainsValue(trusted, CFRangeMake(0, CFArrayGetCount(trusted)), parent)) { - CFArrayAppendValue(anchors, parent); - } - } - } - -finish: - callback(context, anchors); - CFReleaseSafe(anchors); - CFReleaseSafe(parents); - CFReleaseSafe(trusted); - return true; -} - -static CFArrayRef SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source, - SecCertificateRef certificate) { - CFArrayRef result = NULL; - CFArrayRef userTrustSettings = NULL, adminTrustSettings = NULL; - - OSStatus status = SecTrustSettingsCopyTrustSettings(certificate, - kSecTrustSettingsDomainUser, - &userTrustSettings); - if ((status == errSecSuccess) && (userTrustSettings != NULL)) { - result = CFRetain(userTrustSettings); - } - - status = SecTrustSettingsCopyTrustSettings(certificate, - kSecTrustSettingsDomainAdmin, - &adminTrustSettings); - /* user trust settings overrule admin trust settings */ - if ((status == errSecSuccess) && (adminTrustSettings != NULL) && (result == NULL)) { - result = CFRetain(adminTrustSettings); - } - - CFReleaseNull(userTrustSettings); - CFReleaseNull(adminTrustSettings); - return result; -} - -static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source, - SecCertificateRef certificate) { - if (certificate == NULL) { - return false; - } - CFArrayRef trusted = NULL; - bool result = false; - OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted); - if ((status == errSecSuccess) && (trusted != NULL)) { - CFIndex index, count = CFArrayGetCount(trusted); - for (index = 0; index < count; index++) { - SecCertificateRef anchor = (SecCertificateRef)CFRetainSafe(CFArrayGetValueAtIndex(trusted, index)); - if (anchor && (CFGetTypeID(anchor) != CFGetTypeID(certificate))) { - /* This should only happen if trustd and the Security framework are using different SecCertificate TypeIDs. - * This occurs in TrustTests where we rebuild SecCertificate.c for code coverage purposes, so we end up with - * two registered SecCertificate types. So we'll make a SecCertificate of our type. */ - SecCertificateRef temp = SecCertificateCreateWithBytes(NULL, SecCertificateGetBytePtr(anchor), SecCertificateGetLength(anchor)); - CFAssignRetained(anchor, temp); - } - if (anchor && CFEqual(anchor, certificate)) { - result = true; - } - CFReleaseNull(anchor); - if (result) { - break; - } - } - } - CFReleaseSafe(trusted); - return result; -} - -struct SecCertificateSource _kSecLegacyAnchorSource = { - SecLegacyAnchorSourceCopyParents, - SecLegacyAnchorSourceCopyUsageConstraints, - SecLegacyAnchorSourceContains -}; - -const SecCertificateSourceRef kSecLegacyAnchorSource = &_kSecLegacyAnchorSource; - -#endif /* SecLegacyAnchorSource */ diff --git a/OSX/sec/securityd/SecCertificateSource.h b/OSX/sec/securityd/SecCertificateSource.h deleted file mode 100644 index c2c99907..00000000 --- a/OSX/sec/securityd/SecCertificateSource.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecCertificateSource.h - certificate sources for trust evaluation engine - * - */ - -#ifndef _SECURITY_SECCERTIFICATESOURCE_H_ -#define _SECURITY_SECCERTIFICATESOURCE_H_ - -#include -#include - -/******************************************************** - ************ SecCertificateSource object *************** - ********************************************************/ -typedef struct SecCertificateSource *SecCertificateSourceRef; - -typedef void(*SecCertificateSourceParents)(void *, CFArrayRef); - -typedef bool(*CopyParents)(SecCertificateSourceRef source, - SecCertificateRef certificate, - void *context, SecCertificateSourceParents); - -typedef CFArrayRef(*CopyConstraints)(SecCertificateSourceRef source, - SecCertificateRef certificate); - -typedef bool(*Contains)(SecCertificateSourceRef source, - SecCertificateRef certificate); - -struct SecCertificateSource { - CopyParents copyParents; - CopyConstraints copyUsageConstraints; - Contains contains; -}; - -bool SecCertificateSourceCopyParents(SecCertificateSourceRef source, - SecCertificateRef certificate, - void *context, SecCertificateSourceParents callback); - -CFArrayRef SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source, - SecCertificateRef certificate); - -bool SecCertificateSourceContains(SecCertificateSourceRef source, - SecCertificateRef certificate); - -/******************************************************** - ********************** Sources ************************* - ********************************************************/ - -/* SecItemCertificateSource */ -SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups); -void SecItemCertificateSourceDestroy(SecCertificateSourceRef source); - -/* SecMemoryCertificateSource*/ -SecCertificateSourceRef SecMemoryCertificateSourceCreate(CFArrayRef certificates); -void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source); - -/* SecSystemAnchorSource */ -extern const SecCertificateSourceRef kSecSystemAnchorSource; - -#if TARGET_OS_IPHONE -/* SecUserAnchorSource */ -extern const SecCertificateSourceRef kSecUserAnchorSource; -#endif - -/* SecCAIssuerCertificateSource */ -extern const SecCertificateSourceRef kSecCAIssuerSource; - -#if TARGET_OS_OSX -/* SecLegacyCertificateSource */ -extern const SecCertificateSourceRef kSecLegacyCertificateSource; - -/* SecLegacyAnchorSource */ -extern const SecCertificateSourceRef kSecLegacyAnchorSource; -#endif - -#endif /* _SECURITY_SECCERTIFICATESOURCE_H_ */ diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto b/OSX/sec/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto deleted file mode 100644 index e2f4dbad..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto +++ /dev/null @@ -1,40 +0,0 @@ -syntax = "proto2"; - -option objc_class_naming = "extended"; - -// Maintain identity consistency by including this in key and bag messages -message SecDbBackupBagIdentity { - optional bytes baguuid = 1; - optional bytes baghash = 2; -} - -// Insert into backupkeyclasssigningkeys table, v12_keyClassSigningKey column -message SecDbBackupKeyClassSigningKey { - optional int32 keyClass = 1; - optional bytes publicKey = 3; - optional bytes aksRefKey = 4; // Contains bag identity as authenticated data - optional bytes aksWrappedKey = 5; // SFECIESKeyPair wrapped by AKS ref key - optional bytes backupWrappedKey = 6; // SFECIESKeyPair wrapped by KCSKSecret in RecoverySet. Also authenticates bag identity -} - -// Insert into metadatakeys table, v12_metadatakeydata column -message SecDbBackupMetadataClassKey { - optional int32 keyClass = 1; - optional bytes backupWrappedMetadataKey = 2; // wrapped by appropriate backup keyclass for recovery -// optional bytes aksWrappedMetadataKey = 3; // wrapped by device bag for daily use. Not in use right now. -} - -// Insert into backuprecoverysets table, v12_recoverySet column -message SecDbBackupRecoverySet { - optional int32 recoveryType = 1; - optional SecDbBackupBagIdentity bagIdentity = 2; - optional bytes wrappedBagSecret = 3; // 'passphrase' to unlock backup bag's private keys - optional bytes wrappedKCSKSecret = 4; // recovers KCSKs to verify authenticity of IKs and MCKs - optional bytes wrappedRecoveryKey = 5; // wraps the above two secrets -} - -// Insert into backupbags table, v12_backupBag column -message SecDbBackupBag { - optional SecDbBackupBagIdentity bagIdentity = 1; - optional bytes keybag = 2; -} diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h deleted file mode 100644 index b4568c2c..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h +++ /dev/null @@ -1,42 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import -#import - -@class SecDbBackupBagIdentity; - -#ifdef __cplusplus -#define SECDBBACKUPBAG_FUNCTION extern "C" -#else -#define SECDBBACKUPBAG_FUNCTION extern -#endif - -/** Insert into backupbags table, v12_backupBag column */ -@interface SecDbBackupBag : PBCodable -{ - SecDbBackupBagIdentity *_bagIdentity; - NSData *_keybag; -} - - -@property (nonatomic, readonly) BOOL hasBagIdentity; -@property (nonatomic, retain) SecDbBackupBagIdentity *bagIdentity; - -@property (nonatomic, readonly) BOOL hasKeybag; -@property (nonatomic, retain) NSData *keybag; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbBackupBag *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbBackupBag *)other; - -SECDBBACKUPBAG_FUNCTION BOOL SecDbBackupBagReadFrom(__unsafe_unretained SecDbBackupBag *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m deleted file mode 100644 index 01ab3770..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m +++ /dev/null @@ -1,177 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import "SecDbBackupBag.h" -#import -#import -#import - -#import "SecDbBackupBagIdentity.h" - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbBackupBag - -- (BOOL)hasBagIdentity -{ - return _bagIdentity != nil; -} -@synthesize bagIdentity = _bagIdentity; -- (BOOL)hasKeybag -{ - return _keybag != nil; -} -@synthesize keybag = _keybag; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_bagIdentity) - { - [dict setObject:[_bagIdentity dictionaryRepresentation] forKey:@"bagIdentity"]; - } - if (self->_keybag) - { - [dict setObject:self->_keybag forKey:@"keybag"]; - } - return dict; -} - -BOOL SecDbBackupBagReadFrom(__unsafe_unretained SecDbBackupBag *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* bagIdentity */: - { - SecDbBackupBagIdentity *new_bagIdentity = [[SecDbBackupBagIdentity alloc] init]; - self->_bagIdentity = new_bagIdentity; - PBDataReaderMark mark_bagIdentity; - BOOL markError = !PBReaderPlaceMark(reader, &mark_bagIdentity); - if (markError) - { - return NO; - } - BOOL inError = !SecDbBackupBagIdentityReadFrom(new_bagIdentity, reader); - if (inError) - { - return NO; - } - PBReaderRecallMark(reader, &mark_bagIdentity); - } - break; - case 2 /* keybag */: - { - NSData *new_keybag = PBReaderReadData(reader); - self->_keybag = new_keybag; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbBackupBagReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* bagIdentity */ - { - if (self->_bagIdentity != nil) - { - PBDataWriterWriteSubmessage(writer, self->_bagIdentity, 1); - } - } - /* keybag */ - { - if (self->_keybag) - { - PBDataWriterWriteDataField(writer, self->_keybag, 2); - } - } -} - -- (void)copyTo:(SecDbBackupBag *)other -{ - if (_bagIdentity) - { - other.bagIdentity = _bagIdentity; - } - if (_keybag) - { - other.keybag = _keybag; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbBackupBag *copy = [[[self class] allocWithZone:zone] init]; - copy->_bagIdentity = [_bagIdentity copyWithZone:zone]; - copy->_keybag = [_keybag copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbBackupBag *other = (SecDbBackupBag *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_bagIdentity && !other->_bagIdentity) || [self->_bagIdentity isEqual:other->_bagIdentity]) - && - ((!self->_keybag && !other->_keybag) || [self->_keybag isEqual:other->_keybag]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_bagIdentity hash] - ^ - [self->_keybag hash] - ; -} - -- (void)mergeFrom:(SecDbBackupBag *)other -{ - if (self->_bagIdentity && other->_bagIdentity) - { - [self->_bagIdentity mergeFrom:other->_bagIdentity]; - } - else if (!self->_bagIdentity && other->_bagIdentity) - { - [self setBagIdentity:other->_bagIdentity]; - } - if (other->_keybag) - { - [self setKeybag:other->_keybag]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h deleted file mode 100644 index 939066cb..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h +++ /dev/null @@ -1,40 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBBACKUPBAGIDENTITY_FUNCTION extern "C" -#else -#define SECDBBACKUPBAGIDENTITY_FUNCTION extern -#endif - -/** Maintain identity consistency by including this in key and bag messages */ -@interface SecDbBackupBagIdentity : PBCodable -{ - NSData *_baghash; - NSData *_baguuid; -} - - -@property (nonatomic, readonly) BOOL hasBaguuid; -@property (nonatomic, retain) NSData *baguuid; - -@property (nonatomic, readonly) BOOL hasBaghash; -@property (nonatomic, retain) NSData *baghash; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbBackupBagIdentity *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbBackupBagIdentity *)other; - -SECDBBACKUPBAGIDENTITY_FUNCTION BOOL SecDbBackupBagIdentityReadFrom(__unsafe_unretained SecDbBackupBagIdentity *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m deleted file mode 100644 index 03bcbf45..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m +++ /dev/null @@ -1,159 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import "SecDbBackupBagIdentity.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbBackupBagIdentity - -- (BOOL)hasBaguuid -{ - return _baguuid != nil; -} -@synthesize baguuid = _baguuid; -- (BOOL)hasBaghash -{ - return _baghash != nil; -} -@synthesize baghash = _baghash; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_baguuid) - { - [dict setObject:self->_baguuid forKey:@"baguuid"]; - } - if (self->_baghash) - { - [dict setObject:self->_baghash forKey:@"baghash"]; - } - return dict; -} - -BOOL SecDbBackupBagIdentityReadFrom(__unsafe_unretained SecDbBackupBagIdentity *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* baguuid */: - { - NSData *new_baguuid = PBReaderReadData(reader); - self->_baguuid = new_baguuid; - } - break; - case 2 /* baghash */: - { - NSData *new_baghash = PBReaderReadData(reader); - self->_baghash = new_baghash; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbBackupBagIdentityReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* baguuid */ - { - if (self->_baguuid) - { - PBDataWriterWriteDataField(writer, self->_baguuid, 1); - } - } - /* baghash */ - { - if (self->_baghash) - { - PBDataWriterWriteDataField(writer, self->_baghash, 2); - } - } -} - -- (void)copyTo:(SecDbBackupBagIdentity *)other -{ - if (_baguuid) - { - other.baguuid = _baguuid; - } - if (_baghash) - { - other.baghash = _baghash; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbBackupBagIdentity *copy = [[[self class] allocWithZone:zone] init]; - copy->_baguuid = [_baguuid copyWithZone:zone]; - copy->_baghash = [_baghash copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbBackupBagIdentity *other = (SecDbBackupBagIdentity *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_baguuid && !other->_baguuid) || [self->_baguuid isEqual:other->_baguuid]) - && - ((!self->_baghash && !other->_baghash) || [self->_baghash isEqual:other->_baghash]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_baguuid hash] - ^ - [self->_baghash hash] - ; -} - -- (void)mergeFrom:(SecDbBackupBagIdentity *)other -{ - if (other->_baguuid) - { - [self setBaguuid:other->_baguuid]; - } - if (other->_baghash) - { - [self setBaghash:other->_baghash]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h deleted file mode 100644 index e3b5c0bc..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h +++ /dev/null @@ -1,58 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION extern "C" -#else -#define SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION extern -#endif - -/** Insert into backupkeyclasssigningkeys table, v12_keyClassSigningKey column */ -@interface SecDbBackupKeyClassSigningKey : PBCodable -{ - NSData *_aksRefKey; - NSData *_aksWrappedKey; - NSData *_backupWrappedKey; - int32_t _keyClass; - NSData *_publicKey; - struct { - int keyClass:1; - } _has; -} - - -@property (nonatomic) BOOL hasKeyClass; -@property (nonatomic) int32_t keyClass; - -@property (nonatomic, readonly) BOOL hasPublicKey; -@property (nonatomic, retain) NSData *publicKey; - -@property (nonatomic, readonly) BOOL hasAksRefKey; -/** Contains bag identity as authenticated data */ -@property (nonatomic, retain) NSData *aksRefKey; - -@property (nonatomic, readonly) BOOL hasAksWrappedKey; -/** SFECIESKeyPair wrapped by AKS ref key */ -@property (nonatomic, retain) NSData *aksWrappedKey; - -@property (nonatomic, readonly) BOOL hasBackupWrappedKey; -/** SFECIESKeyPair wrapped by KCSKSecret in RecoverySet. Also authenticates bag identity */ -@property (nonatomic, retain) NSData *backupWrappedKey; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbBackupKeyClassSigningKey *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbBackupKeyClassSigningKey *)other; - -SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION BOOL SecDbBackupKeyClassSigningKeyReadFrom(__unsafe_unretained SecDbBackupKeyClassSigningKey *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m deleted file mode 100644 index b86f63cb..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m +++ /dev/null @@ -1,279 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import "SecDbBackupKeyClassSigningKey.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbBackupKeyClassSigningKey - -@synthesize keyClass = _keyClass; -- (void)setKeyClass:(int32_t)v -{ - _has.keyClass = YES; - _keyClass = v; -} -- (void)setHasKeyClass:(BOOL)f -{ - _has.keyClass = f; -} -- (BOOL)hasKeyClass -{ - return _has.keyClass; -} -- (BOOL)hasPublicKey -{ - return _publicKey != nil; -} -@synthesize publicKey = _publicKey; -- (BOOL)hasAksRefKey -{ - return _aksRefKey != nil; -} -@synthesize aksRefKey = _aksRefKey; -- (BOOL)hasAksWrappedKey -{ - return _aksWrappedKey != nil; -} -@synthesize aksWrappedKey = _aksWrappedKey; -- (BOOL)hasBackupWrappedKey -{ - return _backupWrappedKey != nil; -} -@synthesize backupWrappedKey = _backupWrappedKey; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_has.keyClass) - { - [dict setObject:[NSNumber numberWithInt:self->_keyClass] forKey:@"keyClass"]; - } - if (self->_publicKey) - { - [dict setObject:self->_publicKey forKey:@"publicKey"]; - } - if (self->_aksRefKey) - { - [dict setObject:self->_aksRefKey forKey:@"aksRefKey"]; - } - if (self->_aksWrappedKey) - { - [dict setObject:self->_aksWrappedKey forKey:@"aksWrappedKey"]; - } - if (self->_backupWrappedKey) - { - [dict setObject:self->_backupWrappedKey forKey:@"backupWrappedKey"]; - } - return dict; -} - -BOOL SecDbBackupKeyClassSigningKeyReadFrom(__unsafe_unretained SecDbBackupKeyClassSigningKey *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* keyClass */: - { - self->_has.keyClass = YES; - self->_keyClass = PBReaderReadInt32(reader); - } - break; - case 3 /* publicKey */: - { - NSData *new_publicKey = PBReaderReadData(reader); - self->_publicKey = new_publicKey; - } - break; - case 4 /* aksRefKey */: - { - NSData *new_aksRefKey = PBReaderReadData(reader); - self->_aksRefKey = new_aksRefKey; - } - break; - case 5 /* aksWrappedKey */: - { - NSData *new_aksWrappedKey = PBReaderReadData(reader); - self->_aksWrappedKey = new_aksWrappedKey; - } - break; - case 6 /* backupWrappedKey */: - { - NSData *new_backupWrappedKey = PBReaderReadData(reader); - self->_backupWrappedKey = new_backupWrappedKey; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbBackupKeyClassSigningKeyReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* keyClass */ - { - if (self->_has.keyClass) - { - PBDataWriterWriteInt32Field(writer, self->_keyClass, 1); - } - } - /* publicKey */ - { - if (self->_publicKey) - { - PBDataWriterWriteDataField(writer, self->_publicKey, 3); - } - } - /* aksRefKey */ - { - if (self->_aksRefKey) - { - PBDataWriterWriteDataField(writer, self->_aksRefKey, 4); - } - } - /* aksWrappedKey */ - { - if (self->_aksWrappedKey) - { - PBDataWriterWriteDataField(writer, self->_aksWrappedKey, 5); - } - } - /* backupWrappedKey */ - { - if (self->_backupWrappedKey) - { - PBDataWriterWriteDataField(writer, self->_backupWrappedKey, 6); - } - } -} - -- (void)copyTo:(SecDbBackupKeyClassSigningKey *)other -{ - if (self->_has.keyClass) - { - other->_keyClass = _keyClass; - other->_has.keyClass = YES; - } - if (_publicKey) - { - other.publicKey = _publicKey; - } - if (_aksRefKey) - { - other.aksRefKey = _aksRefKey; - } - if (_aksWrappedKey) - { - other.aksWrappedKey = _aksWrappedKey; - } - if (_backupWrappedKey) - { - other.backupWrappedKey = _backupWrappedKey; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbBackupKeyClassSigningKey *copy = [[[self class] allocWithZone:zone] init]; - if (self->_has.keyClass) - { - copy->_keyClass = _keyClass; - copy->_has.keyClass = YES; - } - copy->_publicKey = [_publicKey copyWithZone:zone]; - copy->_aksRefKey = [_aksRefKey copyWithZone:zone]; - copy->_aksWrappedKey = [_aksWrappedKey copyWithZone:zone]; - copy->_backupWrappedKey = [_backupWrappedKey copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbBackupKeyClassSigningKey *other = (SecDbBackupKeyClassSigningKey *)object; - return [other isMemberOfClass:[self class]] - && - ((self->_has.keyClass && other->_has.keyClass && self->_keyClass == other->_keyClass) || (!self->_has.keyClass && !other->_has.keyClass)) - && - ((!self->_publicKey && !other->_publicKey) || [self->_publicKey isEqual:other->_publicKey]) - && - ((!self->_aksRefKey && !other->_aksRefKey) || [self->_aksRefKey isEqual:other->_aksRefKey]) - && - ((!self->_aksWrappedKey && !other->_aksWrappedKey) || [self->_aksWrappedKey isEqual:other->_aksWrappedKey]) - && - ((!self->_backupWrappedKey && !other->_backupWrappedKey) || [self->_backupWrappedKey isEqual:other->_backupWrappedKey]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - (self->_has.keyClass ? PBHashInt((NSUInteger)self->_keyClass) : 0) - ^ - [self->_publicKey hash] - ^ - [self->_aksRefKey hash] - ^ - [self->_aksWrappedKey hash] - ^ - [self->_backupWrappedKey hash] - ; -} - -- (void)mergeFrom:(SecDbBackupKeyClassSigningKey *)other -{ - if (other->_has.keyClass) - { - self->_keyClass = other->_keyClass; - self->_has.keyClass = YES; - } - if (other->_publicKey) - { - [self setPublicKey:other->_publicKey]; - } - if (other->_aksRefKey) - { - [self setAksRefKey:other->_aksRefKey]; - } - if (other->_aksWrappedKey) - { - [self setAksWrappedKey:other->_aksWrappedKey]; - } - if (other->_backupWrappedKey) - { - [self setBackupWrappedKey:other->_backupWrappedKey]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h deleted file mode 100644 index b967187f..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h +++ /dev/null @@ -1,44 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBBACKUPMETADATACLASSKEY_FUNCTION extern "C" -#else -#define SECDBBACKUPMETADATACLASSKEY_FUNCTION extern -#endif - -/** Insert into metadatakeys table, v12_metadatakeydata column */ -@interface SecDbBackupMetadataClassKey : PBCodable -{ - NSData *_backupWrappedMetadataKey; - int32_t _keyClass; - struct { - int keyClass:1; - } _has; -} - - -@property (nonatomic) BOOL hasKeyClass; -@property (nonatomic) int32_t keyClass; - -@property (nonatomic, readonly) BOOL hasBackupWrappedMetadataKey; -/** wrapped by appropriate backup keyclass for recovery */ -@property (nonatomic, retain) NSData *backupWrappedMetadataKey; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbBackupMetadataClassKey *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbBackupMetadataClassKey *)other; - -SECDBBACKUPMETADATACLASSKEY_FUNCTION BOOL SecDbBackupMetadataClassKeyReadFrom(__unsafe_unretained SecDbBackupMetadataClassKey *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m deleted file mode 100644 index eae21ba4..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m +++ /dev/null @@ -1,174 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import "SecDbBackupMetadataClassKey.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbBackupMetadataClassKey - -@synthesize keyClass = _keyClass; -- (void)setKeyClass:(int32_t)v -{ - _has.keyClass = YES; - _keyClass = v; -} -- (void)setHasKeyClass:(BOOL)f -{ - _has.keyClass = f; -} -- (BOOL)hasKeyClass -{ - return _has.keyClass; -} -- (BOOL)hasBackupWrappedMetadataKey -{ - return _backupWrappedMetadataKey != nil; -} -@synthesize backupWrappedMetadataKey = _backupWrappedMetadataKey; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_has.keyClass) - { - [dict setObject:[NSNumber numberWithInt:self->_keyClass] forKey:@"keyClass"]; - } - if (self->_backupWrappedMetadataKey) - { - [dict setObject:self->_backupWrappedMetadataKey forKey:@"backupWrappedMetadataKey"]; - } - return dict; -} - -BOOL SecDbBackupMetadataClassKeyReadFrom(__unsafe_unretained SecDbBackupMetadataClassKey *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* keyClass */: - { - self->_has.keyClass = YES; - self->_keyClass = PBReaderReadInt32(reader); - } - break; - case 2 /* backupWrappedMetadataKey */: - { - NSData *new_backupWrappedMetadataKey = PBReaderReadData(reader); - self->_backupWrappedMetadataKey = new_backupWrappedMetadataKey; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbBackupMetadataClassKeyReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* keyClass */ - { - if (self->_has.keyClass) - { - PBDataWriterWriteInt32Field(writer, self->_keyClass, 1); - } - } - /* backupWrappedMetadataKey */ - { - if (self->_backupWrappedMetadataKey) - { - PBDataWriterWriteDataField(writer, self->_backupWrappedMetadataKey, 2); - } - } -} - -- (void)copyTo:(SecDbBackupMetadataClassKey *)other -{ - if (self->_has.keyClass) - { - other->_keyClass = _keyClass; - other->_has.keyClass = YES; - } - if (_backupWrappedMetadataKey) - { - other.backupWrappedMetadataKey = _backupWrappedMetadataKey; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbBackupMetadataClassKey *copy = [[[self class] allocWithZone:zone] init]; - if (self->_has.keyClass) - { - copy->_keyClass = _keyClass; - copy->_has.keyClass = YES; - } - copy->_backupWrappedMetadataKey = [_backupWrappedMetadataKey copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbBackupMetadataClassKey *other = (SecDbBackupMetadataClassKey *)object; - return [other isMemberOfClass:[self class]] - && - ((self->_has.keyClass && other->_has.keyClass && self->_keyClass == other->_keyClass) || (!self->_has.keyClass && !other->_has.keyClass)) - && - ((!self->_backupWrappedMetadataKey && !other->_backupWrappedMetadataKey) || [self->_backupWrappedMetadataKey isEqual:other->_backupWrappedMetadataKey]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - (self->_has.keyClass ? PBHashInt((NSUInteger)self->_keyClass) : 0) - ^ - [self->_backupWrappedMetadataKey hash] - ; -} - -- (void)mergeFrom:(SecDbBackupMetadataClassKey *)other -{ - if (other->_has.keyClass) - { - self->_keyClass = other->_keyClass; - self->_has.keyClass = YES; - } - if (other->_backupWrappedMetadataKey) - { - [self setBackupWrappedMetadataKey:other->_backupWrappedMetadataKey]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h deleted file mode 100644 index 13490afc..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h +++ /dev/null @@ -1,63 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import -#import - -@class SecDbBackupBagIdentity; - -#ifdef __cplusplus -#define SECDBBACKUPRECOVERYSET_FUNCTION extern "C" -#else -#define SECDBBACKUPRECOVERYSET_FUNCTION extern -#endif - -/** - * optional bytes aksWrappedMetadataKey = 3; // wrapped by device bag for daily use. Not in use right now. - * Insert into backuprecoverysets table, v12_recoverySet column - */ -@interface SecDbBackupRecoverySet : PBCodable -{ - SecDbBackupBagIdentity *_bagIdentity; - int32_t _recoveryType; - NSData *_wrappedBagSecret; - NSData *_wrappedKCSKSecret; - NSData *_wrappedRecoveryKey; - struct { - int recoveryType:1; - } _has; -} - - -@property (nonatomic) BOOL hasRecoveryType; -@property (nonatomic) int32_t recoveryType; - -@property (nonatomic, readonly) BOOL hasBagIdentity; -@property (nonatomic, retain) SecDbBackupBagIdentity *bagIdentity; - -@property (nonatomic, readonly) BOOL hasWrappedBagSecret; -/** 'passphrase' to unlock backup bag's private keys */ -@property (nonatomic, retain) NSData *wrappedBagSecret; - -@property (nonatomic, readonly) BOOL hasWrappedKCSKSecret; -/** recovers KCSKs to verify authenticity of IKs and MCKs */ -@property (nonatomic, retain) NSData *wrappedKCSKSecret; - -@property (nonatomic, readonly) BOOL hasWrappedRecoveryKey; -/** wraps the above two secrets */ -@property (nonatomic, retain) NSData *wrappedRecoveryKey; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbBackupRecoverySet *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbBackupRecoverySet *)other; - -SECDBBACKUPRECOVERYSET_FUNCTION BOOL SecDbBackupRecoverySetReadFrom(__unsafe_unretained SecDbBackupRecoverySet *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m b/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m deleted file mode 100644 index 1621b0d2..00000000 --- a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m +++ /dev/null @@ -1,297 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbBackupRecoverySet.proto - -#import "SecDbBackupRecoverySet.h" -#import -#import -#import - -#import "SecDbBackupBagIdentity.h" - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbBackupRecoverySet - -@synthesize recoveryType = _recoveryType; -- (void)setRecoveryType:(int32_t)v -{ - _has.recoveryType = YES; - _recoveryType = v; -} -- (void)setHasRecoveryType:(BOOL)f -{ - _has.recoveryType = f; -} -- (BOOL)hasRecoveryType -{ - return _has.recoveryType; -} -- (BOOL)hasBagIdentity -{ - return _bagIdentity != nil; -} -@synthesize bagIdentity = _bagIdentity; -- (BOOL)hasWrappedBagSecret -{ - return _wrappedBagSecret != nil; -} -@synthesize wrappedBagSecret = _wrappedBagSecret; -- (BOOL)hasWrappedKCSKSecret -{ - return _wrappedKCSKSecret != nil; -} -@synthesize wrappedKCSKSecret = _wrappedKCSKSecret; -- (BOOL)hasWrappedRecoveryKey -{ - return _wrappedRecoveryKey != nil; -} -@synthesize wrappedRecoveryKey = _wrappedRecoveryKey; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_has.recoveryType) - { - [dict setObject:[NSNumber numberWithInt:self->_recoveryType] forKey:@"recoveryType"]; - } - if (self->_bagIdentity) - { - [dict setObject:[_bagIdentity dictionaryRepresentation] forKey:@"bagIdentity"]; - } - if (self->_wrappedBagSecret) - { - [dict setObject:self->_wrappedBagSecret forKey:@"wrappedBagSecret"]; - } - if (self->_wrappedKCSKSecret) - { - [dict setObject:self->_wrappedKCSKSecret forKey:@"wrappedKCSKSecret"]; - } - if (self->_wrappedRecoveryKey) - { - [dict setObject:self->_wrappedRecoveryKey forKey:@"wrappedRecoveryKey"]; - } - return dict; -} - -BOOL SecDbBackupRecoverySetReadFrom(__unsafe_unretained SecDbBackupRecoverySet *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* recoveryType */: - { - self->_has.recoveryType = YES; - self->_recoveryType = PBReaderReadInt32(reader); - } - break; - case 2 /* bagIdentity */: - { - SecDbBackupBagIdentity *new_bagIdentity = [[SecDbBackupBagIdentity alloc] init]; - self->_bagIdentity = new_bagIdentity; - PBDataReaderMark mark_bagIdentity; - BOOL markError = !PBReaderPlaceMark(reader, &mark_bagIdentity); - if (markError) - { - return NO; - } - BOOL inError = !SecDbBackupBagIdentityReadFrom(new_bagIdentity, reader); - if (inError) - { - return NO; - } - PBReaderRecallMark(reader, &mark_bagIdentity); - } - break; - case 3 /* wrappedBagSecret */: - { - NSData *new_wrappedBagSecret = PBReaderReadData(reader); - self->_wrappedBagSecret = new_wrappedBagSecret; - } - break; - case 4 /* wrappedKCSKSecret */: - { - NSData *new_wrappedKCSKSecret = PBReaderReadData(reader); - self->_wrappedKCSKSecret = new_wrappedKCSKSecret; - } - break; - case 5 /* wrappedRecoveryKey */: - { - NSData *new_wrappedRecoveryKey = PBReaderReadData(reader); - self->_wrappedRecoveryKey = new_wrappedRecoveryKey; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbBackupRecoverySetReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* recoveryType */ - { - if (self->_has.recoveryType) - { - PBDataWriterWriteInt32Field(writer, self->_recoveryType, 1); - } - } - /* bagIdentity */ - { - if (self->_bagIdentity != nil) - { - PBDataWriterWriteSubmessage(writer, self->_bagIdentity, 2); - } - } - /* wrappedBagSecret */ - { - if (self->_wrappedBagSecret) - { - PBDataWriterWriteDataField(writer, self->_wrappedBagSecret, 3); - } - } - /* wrappedKCSKSecret */ - { - if (self->_wrappedKCSKSecret) - { - PBDataWriterWriteDataField(writer, self->_wrappedKCSKSecret, 4); - } - } - /* wrappedRecoveryKey */ - { - if (self->_wrappedRecoveryKey) - { - PBDataWriterWriteDataField(writer, self->_wrappedRecoveryKey, 5); - } - } -} - -- (void)copyTo:(SecDbBackupRecoverySet *)other -{ - if (self->_has.recoveryType) - { - other->_recoveryType = _recoveryType; - other->_has.recoveryType = YES; - } - if (_bagIdentity) - { - other.bagIdentity = _bagIdentity; - } - if (_wrappedBagSecret) - { - other.wrappedBagSecret = _wrappedBagSecret; - } - if (_wrappedKCSKSecret) - { - other.wrappedKCSKSecret = _wrappedKCSKSecret; - } - if (_wrappedRecoveryKey) - { - other.wrappedRecoveryKey = _wrappedRecoveryKey; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbBackupRecoverySet *copy = [[[self class] allocWithZone:zone] init]; - if (self->_has.recoveryType) - { - copy->_recoveryType = _recoveryType; - copy->_has.recoveryType = YES; - } - copy->_bagIdentity = [_bagIdentity copyWithZone:zone]; - copy->_wrappedBagSecret = [_wrappedBagSecret copyWithZone:zone]; - copy->_wrappedKCSKSecret = [_wrappedKCSKSecret copyWithZone:zone]; - copy->_wrappedRecoveryKey = [_wrappedRecoveryKey copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbBackupRecoverySet *other = (SecDbBackupRecoverySet *)object; - return [other isMemberOfClass:[self class]] - && - ((self->_has.recoveryType && other->_has.recoveryType && self->_recoveryType == other->_recoveryType) || (!self->_has.recoveryType && !other->_has.recoveryType)) - && - ((!self->_bagIdentity && !other->_bagIdentity) || [self->_bagIdentity isEqual:other->_bagIdentity]) - && - ((!self->_wrappedBagSecret && !other->_wrappedBagSecret) || [self->_wrappedBagSecret isEqual:other->_wrappedBagSecret]) - && - ((!self->_wrappedKCSKSecret && !other->_wrappedKCSKSecret) || [self->_wrappedKCSKSecret isEqual:other->_wrappedKCSKSecret]) - && - ((!self->_wrappedRecoveryKey && !other->_wrappedRecoveryKey) || [self->_wrappedRecoveryKey isEqual:other->_wrappedRecoveryKey]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - (self->_has.recoveryType ? PBHashInt((NSUInteger)self->_recoveryType) : 0) - ^ - [self->_bagIdentity hash] - ^ - [self->_wrappedBagSecret hash] - ^ - [self->_wrappedKCSKSecret hash] - ^ - [self->_wrappedRecoveryKey hash] - ; -} - -- (void)mergeFrom:(SecDbBackupRecoverySet *)other -{ - if (other->_has.recoveryType) - { - self->_recoveryType = other->_recoveryType; - self->_has.recoveryType = YES; - } - if (self->_bagIdentity && other->_bagIdentity) - { - [self->_bagIdentity mergeFrom:other->_bagIdentity]; - } - else if (!self->_bagIdentity && other->_bagIdentity) - { - [self setBagIdentity:other->_bagIdentity]; - } - if (other->_wrappedBagSecret) - { - [self setWrappedBagSecret:other->_wrappedBagSecret]; - } - if (other->_wrappedKCSKSecret) - { - [self setWrappedKCSKSecret:other->_wrappedKCSKSecret]; - } - if (other->_wrappedRecoveryKey) - { - [self setWrappedRecoveryKey:other->_wrappedRecoveryKey]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbBackupManager.h b/OSX/sec/securityd/SecDbBackupManager.h deleted file mode 100644 index 2459ad75..00000000 --- a/OSX/sec/securityd/SecDbBackupManager.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// For now at least, we'll support backups only on iOS and macOS -#define SECDB_BACKUPS_ENABLED ((TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_IOSMAC) && !TARGET_OS_SIMULATOR && !TARGET_DARWINOS) - -#if __OBJC2__ -#import -#if !TARGET_OS_BRIDGE // Specifically needed until rdar://problem/40583882 lands -#import -#endif -#import "SecAKSObjCWrappers.h" -#import "CheckV12DevEnabled.h" - -NS_ASSUME_NONNULL_BEGIN - -typedef NS_ENUM(NSInteger, SecDbBackupRecoveryType) { - SecDbBackupRecoveryTypeInvalid = -1, - SecDbBackupRecoveryTypeAKS = 1, - SecDbBackupRecoveryTypeCylon = 2, - SecDbBackupRecoveryTypeRecoveryKey = 3, -}; - -extern NSString* const KeychainBackupsErrorDomain; - -typedef NS_ENUM(NSInteger, SecDbBackupErrorCode) { - SecDbBackupUnknownError = -1, - SecDbBackupSuccess = 0, - SecDbBackupAKSFailure, - SecDbBackupCryptoFailure, - SecDbBackupWriteFailure, - SecDbBackupDeserializationFailure, - SecDbBackupSetupFailure, - SecDbBackupNoBackupBagFound, - SecDbBackupNoKCSKFound, - SecDbBackupDuplicateBagFound, - SecDbBackupMultipleDefaultBagsFound, - SecDbBackupMalformedBagDataOnDisk, - SecDbBackupMalformedKCSKDataOnDisk, - SecDbBackupMalformedUUIDDataOnDisk, - SecDbBackupUUIDMismatch, - SecDbBackupDataMismatch, - SecDbBackupUnknownOption, - SecDbBackupKeychainLocked, - SecDbBackupInvalidArgument, - SecDbBackupNotSupported, - SecDbBackupInternalError, - - SecDbBackupTestCodeFailure = 255, // support code for testing is falling over somehow -}; - -@interface SecDbBackupWrappedItemKey : NSObject -@property (nonatomic) NSData* wrappedKey; -@property (nonatomic) NSData* baguuid; -@end - -@interface SecDbBackupManager : NSObject - -+ (instancetype)manager; -- (instancetype)init NS_UNAVAILABLE; - -#if !TARGET_OS_BRIDGE // Specifically needed until rdar://problem/40583882 lands -- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error; -#else -- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error; -#endif - -- (void)verifyBackupIntegrity:(bool)lightweight - completion:(void (^)(NSDictionary* results, NSError* _Nullable error))completion; - -@end - -NS_ASSUME_NONNULL_END -#endif // __OBJC2__ - -// Declare C functions here - -bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef _Nullable * _Nonnull error); diff --git a/OSX/sec/securityd/SecDbBackupManager.m b/OSX/sec/securityd/SecDbBackupManager.m deleted file mode 100644 index ff4dc45a..00000000 --- a/OSX/sec/securityd/SecDbBackupManager.m +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SecDbBackupManager.h" - -NSString* const KeychainBackupsErrorDomain = @"com.apple.security.keychain.backups"; - -// oink oink -@implementation SecDbBackupWrappedItemKey -+ (BOOL)supportsSecureCoding { - return YES; -} -- (void)encodeWithCoder:(nonnull NSCoder *)coder { - [coder encodeObject:self.wrappedKey forKey:@"wrappedKey"]; - [coder encodeObject:self.baguuid forKey:@"baguuid"]; -} - -- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { - if (self = [super init]) { - _wrappedKey = [coder decodeObjectOfClass:[NSData class] forKey:@"wrappedKey"]; - _baguuid = [coder decodeObjectOfClass:[NSData class] forKey:@"baguuid"]; - } - return self; -} -@end - -#if !SECDB_BACKUPS_ENABLED - -@implementation SecDbBackupManager - -+ (instancetype)manager -{ - return nil; -} - -- (void)verifyBackupIntegrity:(bool)lightweight - completion:(void (^)(NSDictionary* results, NSError* _Nullable error))completion -{ - completion(nil, [NSError errorWithDomain:KeychainBackupsErrorDomain - code:SecDbBackupNotSupported - userInfo:@{NSLocalizedDescriptionKey : @"platform doesn't do backups"}]); -} - -- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error -{ - return nil; -} - -@end - -bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error) -{ - return true; -} - -#else // SECDB_BACKUPS_ENABLED is true, roll out the code - -#import "SecDbBackupManager_Internal.h" -#include -#import -#import "SecItemServer.h" -#import "SecItemDb.h" -#import "keychain/categories/NSError+UsefulConstructors.h" -#import "sec_action.h" -#import "SecItemServer.h" -#include "utilities/der_plist.h" - -// TODO: fire off metric on outcome -bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error) -{ - NSError* localError; - bool ok = [[SecDbBackupManager manager] createOrLoadBackupInfrastructure:&localError]; - if (!ok) { - // Translate this to intelligible constant in C, but other errors can be passed along - if (localError.code == SecDbBackupKeychainLocked) { - *error = CFErrorCreate(kCFAllocatorDefault, kSecErrorDomain, errSecInteractionNotAllowed, NULL); - } else { - *error = (CFErrorRef)CFBridgingRetain(localError); - } - } - return ok; -} - -// Reading from disk is relatively expensive. Keep wrapped key in memory and just delete the unwrapped copy on lock -@interface InMemoryKCSK : NSObject -@property aks_ref_key_t refKey; -@property (nonatomic) NSData* wrappedKey; -@property (nonatomic) SFECKeyPair* key; -@end - -@implementation InMemoryKCSK -- (void)dealloc -{ - if (_refKey) { - free(_refKey); - } -} - -+ (instancetype)kcskWithRefKey:(aks_ref_key_t)refKey wrappedKey:(NSData*)wrappedKey key:(SFECKeyPair*)key -{ - InMemoryKCSK* kcsk = [InMemoryKCSK new]; - kcsk.refKey = refKey; - kcsk.wrappedKey = wrappedKey; - kcsk.key = key; - return kcsk; -} - -@end - -@interface SecDbBackupManager () { - dispatch_queue_t _queue; - keybag_handle_t _handle; - SecDbBackupBagIdentity* _bagIdentity; - NSMutableDictionary* _cachedKCSKs; -} -@end - -@implementation SecDbBackupManager - -#pragma mark - Misc Helpers - -- (NSData*)getSHA256OfData:(NSData*)data -{ - NSMutableData* digest = [[NSMutableData alloc] initWithLength:CC_SHA512_DIGEST_LENGTH]; - if (!CC_SHA512(data.bytes, (CC_LONG)data.length, digest.mutableBytes)) { - return nil; - } - return digest; -} - -- (void)setBagIdentity:(SecDbBackupBagIdentity *)bagIdentity -{ - _bagIdentity = bagIdentity; -} - -- (SecDbBackupBagIdentity*)bagIdentity -{ - return _bagIdentity; -} - -- (bool)fillError:(NSError**)error code:(enum SecDbBackupErrorCode)code underlying:(NSError*)underlying description:(NSString*)format, ... NS_FORMAT_FUNCTION(4, 5) -{ - if (error) { - va_list ap; - va_start(ap, format); - NSString* desc = [[NSString alloc] initWithFormat:format arguments:ap]; - va_end(ap); - if (underlying) { - *error = [NSError errorWithDomain:KeychainBackupsErrorDomain code:code description:desc underlying:underlying]; - } else { - *error = [NSError errorWithDomain:KeychainBackupsErrorDomain code:code description:desc]; - } - } - - // analyzer gets upset when a method taking an error** doesn't return a value - return true; -} - -static SecDbBackupManager* staticManager; -+ (instancetype)manager -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - staticManager = [SecDbBackupManager new]; - }); - return staticManager; -} - -// Testing only please -+ (void)resetManager -{ - if (staticManager) { - staticManager = [SecDbBackupManager new]; - } -} - -- (instancetype)init -{ - if (!checkV12DevEnabled()) { - return nil; - } - if (self = [super init]) { - _queue = dispatch_queue_create("com.apple.security.secdbbackupmanager", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); - _handle = bad_keybag_handle; - _cachedKCSKs = [NSMutableDictionary new]; - } - return self; -} - -- (SFECKeyPair*)getECKeyPairFromDERBytes:(void*)bytes length:(size_t)len error:(NSError**)error -{ - if (!bytes || len == 0) { - [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Need valid byte buffer to make EC keypair from"]; - return nil; - } - CFTypeRef cftype = NULL; - CFErrorRef cferr = NULL; - const uint8_t* derp = der_decode_plist(kCFAllocatorDefault, NSPropertyListImmutable, &cftype, &cferr, bytes, bytes + len); - free(bytes); - if (derp == NULL || derp != (bytes + len) || cftype == NULL) { - [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:CFBridgingRelease(cferr) description:@"Unable to parse der data"]; - return nil; - } - - return [[SFECKeyPair alloc] initWithData:(__bridge_transfer NSData*)cftype - specifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384] - error:error]; -} - -#pragma mark - Fixup And Verification - -- (void)verifyBackupIntegrity:(bool)lightweight - completion:(void (^)(NSDictionary* _Nonnull, NSError * _Nullable))completion -{ - NSError* error = nil; - completion(@{@"summary" : @"Unimplemented"}, error); -} - -#pragma mark - Backup Bag Management - -// Get the bag's UUID from AKS and the hash from provided data. This must always be the original bag's data -- (SecDbBackupBagIdentity*)bagIdentityWithHandle:(keybag_handle_t)handle data:(NSData*)data error:(NSError**)error { - assert(data); - secnotice("SecDbBackup", "Getting bag identity"); - SecDbBackupBagIdentity* identity = [SecDbBackupBagIdentity new]; - - uuid_t uuid = {0}; - kern_return_t aksResult = aks_get_bag_uuid(handle, uuid); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to get keybag UUID (%d)", aksResult]; - return nil; - } - identity.baguuid = [NSData dataWithBytes:uuid length:16]; - - NSData* digest = [self getSHA256OfData:data]; - if (!digest) { - [self fillError:error code:SecDbBackupCryptoFailure underlying:nil description:@"CC_SHA512 returned failure, can't get bag hash"]; - return nil; - } - identity.baghash = digest; - - secnotice("SecDbBackup", "Obtained bag identity: %@", identity); - - return identity; -} - -- (NSData*)createBackupBagSecret:(NSError**)error -{ - uint8_t* data = calloc(1, BACKUPBAG_PASSPHRASE_LENGTH); - if (!data) { - return nil; // Good luck allocating an error message - } - - CCRNGStatus rngResult = CCRandomGenerateBytes(data, BACKUPBAG_PASSPHRASE_LENGTH); - if (rngResult != kCCSuccess) { - [self fillError:error code:SecDbBackupCryptoFailure underlying:nil description:@"Unable to generate random bytes (%d)", rngResult]; - return nil; - } - - NSData* secret = [NSData _newZeroingDataWithBytesNoCopy:data length:BACKUPBAG_PASSPHRASE_LENGTH deallocator:NSDataDeallocatorNone]; - return secret; -} - -- (keybag_handle_t)onQueueCreateBackupBagWithSecret:(NSData*)secret error:(NSError**)error -{ - dispatch_assert_queue(_queue); - - keybag_handle_t handle = bad_keybag_handle; - kern_return_t aksresult = aks_create_bag(secret.bytes, BACKUPBAG_PASSPHRASE_LENGTH, kAppleKeyStoreAsymmetricBackupBag, &handle); - if (aksresult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to create keybag (%d)", aksresult]; - return bad_keybag_handle; - } - - // Make secret keys unavailable. Causes pubkeys to be destroyed so reload bag before use - aksresult = aks_lock_bag(handle); - if (aksresult != kAKSReturnSuccess) { // This would be rather surprising - [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to lock keybag (%d)", aksresult]; - aks_unload_bag(handle); - return bad_keybag_handle; - } - - return handle; -} - -- (BOOL)onQueueInTransaction:(SecDbConnectionRef)dbt saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error -{ - dispatch_assert_queue(_queue); - - void* buf = NULL; - int buflen = 0; - kern_return_t aksResult = aks_save_bag(handle, &buf, &buflen); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to serialize keybag (%d)", aksResult]; - return NO; - } - NSData* bagData = [NSData dataWithBytesNoCopy:buf length:buflen]; - - SecDbBackupBagIdentity* bagIdentity = [self bagIdentityWithHandle:handle data:bagData error:error]; - if (!bagIdentity) { - return NO; - } - SecDbBackupBag* bag = [SecDbBackupBag new]; - bag.bagIdentity = bagIdentity; - bag.keybag = bagData; - - __block CFErrorRef cfError = NULL; - __block bool ok = true; - if (asDefault) { - ok &= SecDbPrepare(dbt, CFSTR("UPDATE backupbags SET defaultvalue = 0 WHERE defaultvalue = 1"), &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { - // FIXME: Should this be an error? Should something else happen? - secwarning("SecDbBackup: Marking existing bag as non-default"); - }); - }); - } - if (!ok) { - return ok; - } - ok &= SecDbPrepare(dbt, CFSTR("INSERT INTO backupbags (backupUUID, backupbag, defaultvalue) VALUES (?,?,?)"), &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbBindObject(stmt, 1, (__bridge CFDataRef)bag.bagIdentity.baguuid, &cfError); - ok &= SecDbBindObject(stmt, 2, (__bridge CFDataRef)bag.data, &cfError); - ok &= SecDbBindInt(stmt, 3, asDefault ? 1 : 0, &cfError); - ok &= SecDbStep(dbt, stmt, &cfError, NULL); - }); - - if (!ok) { - secerror("SecDbBackup: unable to save keybag to disk: %@", cfError); - [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to save keybag to disk"]; - } - - return ok; -} - -- (keybag_handle_t)onQueueLoadBackupBag:(NSUUID*)uuid error:(NSError**)error { - dispatch_assert_queue(_queue); - - secnotice("SecDbBackup", "Attempting to load backup bag from disk"); - - __block CFErrorRef localErr = NULL; - __block bool ok = true; - __block NSData* readUUID; - __block NSData* readBagData; - __block unsigned found = 0; - ok &= kc_with_dbt_non_item_tables(false, &localErr, ^bool(SecDbConnectionRef dbt) { - NSString* sql = [NSString stringWithFormat:@"SELECT backupUUID, backupbag FROM backupbags WHERE %@", uuid ? @"backupUUID = ?" : @"defaultvalue = 1"]; - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &localErr, ^(sqlite3_stmt *stmt) { - if (uuid) { - unsigned char uuidbytes[UUIDBYTESLENGTH] = {0}; - [uuid getUUIDBytes:uuidbytes]; - ok &= SecDbBindBlob(stmt, 1, uuidbytes, UUIDBYTESLENGTH, SQLITE_TRANSIENT, &localErr); - } - ok &= SecDbStep(dbt, stmt, &localErr, ^(bool *stop) { - if (found > 0) { // For uuids this should have violated constraints - secerror("Encountered more than one backup bag by %@", uuid ? @"backupUUID" : @"defaultvalue"); - *stop = true; - } - readUUID = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; - readBagData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)]; - ++found; - }); - }); - return ok; - }); - - if (!ok) { - secerror("SecDbBackup: Unable to load backup bag from disk: %@", localErr); - [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(localErr) description:@"Unable to load backup bag from disk"]; - return bad_keybag_handle; - } - - if (!found) { - [self fillError:error code:SecDbBackupNoBackupBagFound underlying:nil description:@"No backup bag found to load from disk"]; - return bad_keybag_handle; - } else if (found > 1) { - [self fillError:error - code:uuid ? SecDbBackupDuplicateBagFound : SecDbBackupMultipleDefaultBagsFound - underlying:nil - description:@"More than one backup bag found"]; - return bad_keybag_handle; - } - - if (!readUUID || readUUID.length != UUIDBYTESLENGTH || !readBagData || !readBagData.length) { - [self fillError:error code:SecDbBackupMalformedBagDataOnDisk underlying:nil description:@"bags read from disk malformed"]; - return bad_keybag_handle; - } - - SecDbBackupBag* readBag = [[SecDbBackupBag alloc] initWithData:readBagData]; - if (!readBag) { - [self fillError:error code:SecDbBackupDeserializationFailure underlying:nil description:@"bag from disk does not deserialize"]; - return bad_keybag_handle; - } - - secnotice("SecDbBackup", "Successfully read backup bag from disk; loading and verifying. Read bag ID: %@", readBag.bagIdentity); - - keybag_handle_t handle = bad_keybag_handle; - kern_return_t aksResult = aks_load_bag(readBag.keybag.bytes, (int)readBag.keybag.length, &handle); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to load bag from disk (%d)", aksResult]; - return bad_keybag_handle; - } - - SecDbBackupBagIdentity* loadedID = [self bagIdentityWithHandle:handle data:readBag.keybag error:error]; - if (!loadedID) { - aks_unload_bag(handle); - return bad_keybag_handle; - } - - if (memcmp(loadedID.baguuid.bytes, readBag.bagIdentity.baguuid.bytes, UUIDBYTESLENGTH) || - memcmp(loadedID.baguuid.bytes, readUUID.bytes, UUIDBYTESLENGTH)) { - [self fillError:error code:SecDbBackupUUIDMismatch underlying:nil description:@"Loaded UUID does not match UUIDs on disk"]; - aks_unload_bag(handle); - return bad_keybag_handle; - } - - if (memcmp(loadedID.baghash.bytes, readBag.bagIdentity.baghash.bytes, CC_SHA512_DIGEST_LENGTH)) { - [self fillError:error code:SecDbBackupDeserializationFailure underlying:nil description:@"Keybag hash does not match its identity's hash"]; - return bad_keybag_handle; - } - - // TODO: verify that bag is still signed, rdar://problem/46702467 - - secnotice("SecDbBackup", "Backup bag loaded and verified."); - - // Must load readBag's identity because the hash from AKS is unstable. - // This is the hash of the original saved bag and is anchored in the KCSKes. - _bagIdentity = readBag.bagIdentity; - - return handle; -} - -- (BOOL)onQueueReloadDefaultBackupBagWithError:(NSError**)error -{ - if (_handle != bad_keybag_handle) { - aks_unload_bag(_handle); - } - - _handle = [self onQueueLoadBackupBag:nil error:error]; - return _handle != bad_keybag_handle; -} - -#pragma mark - KCSK Management - -- (SecDbBackupKeyClassSigningKey*)createKCSKForKeyClass:(keyclass_t)class withWrapper:(SFAESKey*)wrapper error:(NSError**)error -{ - if (!wrapper) { - [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Need wrapper for KCSK"]; - return nil; - } - - SecDbBackupKeyClassSigningKey* kcsk = [SecDbBackupKeyClassSigningKey new]; - kcsk.keyClass = class; - - SFECKeyPair* keypair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - kcsk.publicKey = [keypair.publicKey.keyData copy]; - - // Create a DER-encoded dictionary of bag identity - void* der_blob; - size_t der_len; - CFErrorRef cfErr = NULL; - NSDictionary* identDict = @{@"baguuid" : _bagIdentity.baguuid, @"baghash" : _bagIdentity.baghash}; - NSData* identData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)identDict, &cfErr); - aks_operation_optional_params(NULL, 0, identData.bytes, identData.length, NULL, 0, &der_blob, &der_len); - - // Create ref key with embedded bag identity DER data - aks_ref_key_t refkey = NULL; - kern_return_t aksResult = aks_ref_key_create(KEYBAG_DEVICE, class, key_type_sym, der_blob, der_len, &refkey); - free(der_blob); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil - description:@"Unable to create AKS ref key for KCSK class %d: %d", class, aksResult]; - return nil; - } - - size_t refkeyblobsize = 0; - const uint8_t* refkeyblob = aks_ref_key_get_blob(refkey, &refkeyblobsize); - kcsk.aksRefKey = [NSData dataWithBytes:refkeyblob length:refkeyblobsize]; - - size_t wrappedKeyLen = 0; - void* wrappedKey = NULL; - NSData* keypairAsData = keypair.keyData; - aksResult = aks_ref_key_encrypt(refkey, NULL, 0, keypairAsData.bytes, keypairAsData.length, &wrappedKey, &wrappedKeyLen); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error code:SecDbBackupAKSFailure underlying:nil - description:@"Unable to encrypt KCSK class %d with AKS ref key: %d", class, aksResult]; - return nil; - } - aks_ref_key_free(&refkey); - kcsk.aksWrappedKey = [NSData dataWithBytesNoCopy:wrappedKey length:wrappedKeyLen]; - - // Also add DER-encoded bag identity here - SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]]; - SFAuthenticatedCiphertext* backupwrapped = [op encrypt:keypair.keyData withKey:wrapper additionalAuthenticatedData:identData error:error]; - kcsk.backupWrappedKey = [NSKeyedArchiver archivedDataWithRootObject:backupwrapped requiringSecureCoding:YES error:error]; - if (!kcsk.backupWrappedKey) { - return nil; - } - - return kcsk; -} - -- (BOOL)inTransaction:(SecDbConnectionRef)dbt writeKCSKToKeychain:(SecDbBackupKeyClassSigningKey*)kcsk error:(NSError**)error -{ - __block bool ok = true; - __block CFErrorRef cfError = NULL; - NSString* sql = @"INSERT INTO backupkeyclasssigningkeys (keyclass, backupUUID, signingkey) VALUES (?, ?, ?)"; - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbBindInt(stmt, 1, kcsk.keyClass, &cfError); - ok &= SecDbBindObject(stmt, 2, (__bridge CFTypeRef)(self->_bagIdentity.baguuid), &cfError); - ok &= SecDbBindObject(stmt, 3, (__bridge CFTypeRef)(kcsk.data), &cfError); - ok &= SecDbStep(dbt, stmt, &cfError, NULL); - }); - - if (!ok) { - secerror("SecDbBackup: Unable to write KCSK for class %d to keychain: %@", kcsk.keyClass, cfError); - [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to write KCSK for class %d to keychain", kcsk.keyClass]; - } - - return ok; -} - -- (InMemoryKCSK*)onQueueReadKCSKFromDiskForClass:(keyclass_t)keyclass error:(NSError**)error -{ - __block bool ok = true; - __block CFErrorRef cfError = NULL; - __block NSData* readUUID; - __block NSData* readKCSK; - NSString* sql = @"SELECT backupUUID, signingkey FROM backupkeyclasssigningkeys WHERE keyclass = ?"; - ok &= kc_with_dbt_non_item_tables(NO, &cfError, ^bool(SecDbConnectionRef dbt) { - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbBindInt(stmt, 1, keyclass, &cfError); - ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { - readUUID = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; - readKCSK = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)]; - }); - }); - return ok; - }); - if (!readKCSK || !readUUID) { - [self fillError:error code:SecDbBackupNoKCSKFound underlying:nil description:@"KCSK for class %d not on disk", keyclass]; - return nil; - } - - SecDbBackupKeyClassSigningKey* kcsk = [[SecDbBackupKeyClassSigningKey alloc] initWithData:readKCSK]; - if (!kcsk) { - [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:nil description:@"Retrieved KCSK blob but it didn't become a KCSK"]; - return nil; - } - - aks_ref_key_t refkey = NULL; - kern_return_t aksResult = aks_ref_key_create_with_blob(KEYBAG_DEVICE, kcsk.aksRefKey.bytes, kcsk.aksRefKey.length, &refkey); - if (aksResult != kAKSReturnSuccess) { - [self fillError:error - code:SecDbBackupAKSFailure - underlying:nil - description:@"Failed to create refkey from KCSK blob for class %d: %d", keyclass, aksResult]; - return nil; - } - - size_t externalDataLen = 0; - const uint8_t* externalData = aks_ref_key_get_external_data(refkey, &externalDataLen); - NSData* derBagIdent = [NSData dataWithBytes:externalData length:externalDataLen]; - CFErrorRef cfErr = NULL; - NSDictionary* identData = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)derBagIdent, 0, NULL, &cfErr); - if (!identData || ![_bagIdentity.baghash isEqualToData:identData[@"baghash"]] || ![_bagIdentity.baguuid isEqualToData:identData[@"baguuid"]]) { - secerror("SecDbBackup: KCSK ref key embedded bag identity does not match loaded bag. %@ vs %@", identData, _bagIdentity); - [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:CFBridgingRelease(cfErr) description:@"KCSK ref key embedded bag identity does not match loaded bag."]; - return nil; - } - - // AKS refkey claims in its external data to belong to our backup bag. Let's see if the claim holds up: use the key. - void* keypairBytes = NULL; - size_t keypairLength = 0; - aksResult = aks_ref_key_decrypt(refkey, NULL, 0, kcsk.aksWrappedKey.bytes, kcsk.aksWrappedKey.length, &keypairBytes, &keypairLength); - if (aksResult == kSKSReturnNoPermission) { - [self fillError:error code:SecDbBackupKeychainLocked underlying:nil description:@"Unable to unwrap KCSK private key for class %d. Locked", keyclass]; - return nil; - } else if (aksResult != kAKSReturnSuccess) { - // Failure could indicate key was corrupted or tampered with - [self fillError:error - code:SecDbBackupAKSFailure - underlying:nil - description:@"AKS did not unwrap KCSK private key for class %d: %d", keyclass, aksResult]; - return nil; - } - - SFECKeyPair* keypair = [self getECKeyPairFromDERBytes:keypairBytes length:keypairLength error:error]; - return keypair ? [InMemoryKCSK kcskWithRefKey:refkey wrappedKey:kcsk.aksWrappedKey key:keypair] : nil; -} - -- (SFECKeyPair*)onQueueFetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error -{ - assert(error); - assert(_bagIdentity); - assert(_handle != bad_keybag_handle); - - InMemoryKCSK* cached = _cachedKCSKs[@(keyclass)]; - if (cached.key) { - return cached.key; - } - - if (cached) { - secnotice("SecDbBackup", "Cached but wrapped KCSK found for class %d, unwrapping", keyclass); - void* keybytes = NULL; - size_t keylen = 0; - kern_return_t aksResult = aks_ref_key_decrypt(cached.refKey, NULL, 0, cached.wrappedKey.bytes, cached.wrappedKey.length, &keybytes, &keylen); - if (aksResult == kAKSReturnSuccess) { - cached.key = [self getECKeyPairFromDERBytes:keybytes length:keylen error:error]; - return cached.key; - } else { - secerror("SecDbBackup: Cached KCSK isn't unwrapping key material. This is a bug."); - } - } - - secnotice("SecDbBackup", "No cached KCSK for class %d, reading from disk", keyclass); - cached = [self onQueueReadKCSKFromDiskForClass:keyclass error:error]; - if (!cached.key) { - secerror("SecDbBackup: Failed to obtain KCSK for class %d: %@", keyclass, *error); - if ((*error).code != SecDbBackupKeychainLocked) { - seccritical("SecDbBackup: KCSK unavailable, cannot backup-wrap class %d items. Need to perform recovery.", keyclass); - // TODO: We're borked. Need to recover from this. - } - } - _cachedKCSKs[@(keyclass)] = cached; - return cached.key; -} - -#pragma mark - Recovery Set Management - -- (BOOL)onQueueInTransaction:(SecDbConnectionRef)dbt writeRecoverySetToKeychain:(SecDbBackupRecoverySet*)set error:(NSError**)error -{ - dispatch_assert_queue(_queue); - __block bool ok = true; - __block CFErrorRef cfError = NULL; - - NSString* sql = @"INSERT INTO backuprecoverysets (backupUUID, recoverytype, recoveryset) VALUES (?, ?, ?)"; - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbBindObject(stmt, 1, (__bridge CFDataRef)set.bagIdentity.baguuid, &cfError); - ok &= SecDbBindObject(stmt, 2, (__bridge CFNumberRef)@(set.recoveryType), &cfError); - ok &= SecDbBindObject(stmt, 3, (__bridge CFDataRef)set.data, &cfError); - ok &= SecDbStep(dbt, stmt, &cfError, NULL); - }); - - if (!ok) { - secerror("SecDbBackup: Unable to write recovery set to keychain: %@", cfError); - [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to write recovery set to keychain"]; - } - - return ok; -} - -- (SecDbBackupRecoverySet*)onQueueInTransaction:(SecDbConnectionRef)dbt createRecoverySetWithBagSecret:(NSData*)secret - forType:(SecDbBackupRecoveryType)type error:(NSError**)error -{ - dispatch_assert_queue(_queue); - if (!secret) { - [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Can't create recovery set without secret"]; - return nil; - } - - SecDbBackupRecoverySet* set; - switch (type) { - case SecDbBackupRecoveryTypeAKS: - set = [self inTransaction:dbt createAKSTypeRecoverySetWithBagSecret:secret handle:_handle error:error]; - break; - case SecDbBackupRecoveryTypeCylon: - secerror("SecDbBackup: Cylon recovery type not yet implemented"); - [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type Cylon not yet implemented"]; - break; - case SecDbBackupRecoveryTypeRecoveryKey: - secerror("SecDbBackup: RecoveryKey recovery type not yet implemented"); - [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type RecoveryKey not yet implemented"]; - break; - default: - secerror("SecDbBackup: Unknown type %ld", (long)type); - [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type %li unknown", (long)type]; - break; - } - - return set; -} - -- (SecDbBackupRecoverySet*)inTransaction:(SecDbConnectionRef)dbt createAKSTypeRecoverySetWithBagSecret:(NSData*)secret handle:(keybag_handle_t)handle error:(NSError**)error -{ - SecDbBackupRecoverySet* set = [SecDbBackupRecoverySet new]; - set.recoveryType = SecDbBackupRecoveryTypeAKS; - set.bagIdentity = _bagIdentity; - - NSError* cryptoError; - SFAESKeySpecifier* specifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; - SFAESKey* KCSKSecret = [[SFAESKey alloc] initRandomKeyWithSpecifier:specifier error:&cryptoError]; - if (!KCSKSecret) { - [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to create AKS recovery set"]; - return nil; - } - - // We explicitly do NOT want akpu. For the rest, create and write all KCSKs - for (NSNumber* class in @[@(key_class_ak), @(key_class_ck), @(key_class_dk), @(key_class_aku), @(key_class_cku), @(key_class_dku)]) { - SecDbBackupKeyClassSigningKey* kcsk = [self createKCSKForKeyClass:[class intValue] withWrapper:KCSKSecret error:error]; - if (!kcsk) { - secerror("SecDbBackup: Unable to create KCSK for class %@: %@", class, *error); - return nil; - } - if (![self inTransaction:dbt writeKCSKToKeychain:kcsk error:error]) { - secerror("SecDbBackup: Unable to write KCSK for class %@ to keychain: %@", class, *error); - return nil; - } - } - - SFAESKey* recoverykey = [[SFAESKey alloc] initRandomKeyWithSpecifier:specifier error:&cryptoError]; - if (!recoverykey) { - [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to create recovery key"]; - return nil; - } - - SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] - initWithKeySpecifier:[[SFAESKeySpecifier alloc] - initWithBitSize:SFAESKeyBitSize256]]; - SFAuthenticatedCiphertext* wrappedsecret = [op encrypt:secret withKey:recoverykey error:&cryptoError]; - if (!wrappedsecret) { - secerror("SecDbBackup: Unable to wrap keybag secret: %@", cryptoError); - [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to wrap keybag secret"]; - return nil; - } - set.wrappedBagSecret = [NSKeyedArchiver archivedDataWithRootObject:wrappedsecret requiringSecureCoding:YES error:error]; - - SFAuthenticatedCiphertext* wrappedkcsksecret = [op encrypt:KCSKSecret.keyData withKey:recoverykey error:&cryptoError]; - if (!wrappedkcsksecret) { - secerror("SecDbBackup: Unable to wrap KCSK secret: %@", cryptoError); - [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to wrap KCSK secret"]; - return nil; - } - set.wrappedKCSKSecret = [NSKeyedArchiver archivedDataWithRootObject:wrappedkcsksecret requiringSecureCoding:YES error:error]; - - NSMutableData* wrappedrecoverykey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN]; - if (![SecAKSObjCWrappers aksEncryptWithKeybag:KEYBAG_DEVICE keyclass:key_class_aku plaintext:recoverykey.keyData outKeyclass:nil ciphertext:wrappedrecoverykey error:&cryptoError]) { - secerror("SecDbBackup: Unable to wrap recovery key to AKS: %@", cryptoError); - [self fillError:error code:SecDbBackupAKSFailure underlying:cryptoError description:@"Unable to wrap recovery key to AKS"]; - return nil; - } - set.wrappedRecoveryKey = [wrappedrecoverykey copy]; - - return set; -} - -#pragma mark - Backup System Initialization / Maintenance - -- (BOOL)createOrLoadBackupInfrastructure:(NSError**)error { - assert(error); - __block BOOL ok = true; - __block NSError* localError; - dispatch_sync(_queue, ^{ - ok = [self onQueueCreateOrLoadBackupInfrastructure:&localError]; - }); - - if (localError) { - *error = localError; - } - return ok; -} - -// TODO: if this creates the infrastructure, kick off a fixup routine -// TODO: if not, make sure we actually delete stuff. Nested transactions are not a thing (use checkpointing or delete explicitly) - -- (BOOL)onQueueCreateOrLoadBackupInfrastructure:(NSError**)error { - dispatch_assert_queue(_queue); - assert(error); - if (self->_handle != bad_keybag_handle) { - return true; - } - - self->_handle = [self onQueueLoadBackupBag:nil error:error]; - if (self->_handle != bad_keybag_handle) { - secnotice("SecDbBackup", "Keybag found and loaded"); - return true; - } else if (self->_handle == bad_keybag_handle && (*error).code != SecDbBackupNoBackupBagFound) { - return false; - } - *error = nil; - - __block BOOL ok = YES; - __block CFErrorRef cfError = NULL; - __block NSError* localError; - secnotice("SecDbBackup", "CreateOrLoad: No backup bag found, attempting to create new infrastructure"); - if (ok && !SecAKSDoWithUserBagLockAssertion(&cfError, ^{ - ok &= kc_with_dbt_non_item_tables(YES, &cfError, ^bool(SecDbConnectionRef dbt) { - ok &= kc_transaction(dbt, &cfError, ^bool{ - NSData* secret = [self createBackupBagSecret:&localError]; - if (!secret) { - return false; - } - - self->_handle = [self onQueueCreateBackupBagWithSecret:secret error:&localError]; - if (self->_handle == bad_keybag_handle) { - return false; - } - secnotice("SecDbBackup", "CreateOrLoad: Successfully created backup bag"); - - if (![self onQueueInTransaction:dbt saveBackupBag:self->_handle asDefault:YES error:&localError]) { - return false; - } - secnotice("SecDbBackup", "CreateOrLoad: Successfully saved backup bag"); - - if (![self onQueueReloadDefaultBackupBagWithError:&localError]) { - return false; - } - secnotice("SecDbBackup", "CreateOrLoad: Successfully reloaded backup bag"); - - SecDbBackupRecoverySet* set = [self onQueueInTransaction:dbt - createRecoverySetWithBagSecret:secret - forType:SecDbBackupRecoveryTypeAKS - error:&localError]; - if (!set) { - secnotice("SecDbBackup", "CreateOrLoad: Successfully created recovery set"); - return false; - } - - if (![self onQueueInTransaction:dbt writeRecoverySetToKeychain:set error:&localError]) { - return false; - } - secnotice("SecDbBackup", "CreateOrLoad: Successfully saved recovery set"); - - return true; - }); - return ok; - }); - })) { // could not perform action with lock assertion - static dispatch_once_t once; - static sec_action_t action; - dispatch_once(&once, ^{ - action = sec_action_create("keybag_locked_during_backup_setup_complaint", 5); - sec_action_set_handler(action, ^{ - secerror("SecDbBackup: Cannot obtain AKS lock assertion so cannot setup backup infrastructure"); - }); - }); - sec_action_perform(action); - [self fillError:&localError code:SecDbBackupKeychainLocked underlying:nil - description:@"Unable to initialize backup infrastructure, keychain locked"]; - ok = NO; - } - - if (!ok) { - self->_bagIdentity = nil; - aks_unload_bag(self->_handle); - self->_handle = bad_keybag_handle; - } - - if (ok) { - secnotice("SecDbBackup", "Hurray! Successfully created backup infrastructure"); - } else { - assert(localError || cfError); - if (localError) { - secerror("SecDbBackup: Could not initialize backup infrastructure: %@", localError); - *error = localError; - } else if (cfError) { - secerror("SecDbBackup: Could not initialize backup infrastructure: %@", cfError); - [self fillError:error code:SecDbBackupSetupFailure underlying:CFBridgingRelease(cfError) - description:@"Unable to initialize backup infrastructure"]; - } else { - secerror("SecDbBackup: Could not initialize backup infrastructure but have no error"); - [self fillError:error code:SecDbBackupSetupFailure underlying:nil - description:@"Unable to initialize backup infrastructure (not sure why)"]; - } - CFReleaseNull(cfError); - } - - return ok; -} - -#pragma mark - Item Encryption - -- (SecDbBackupWrappedItemKey*)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error -{ - assert(error); - if (keyclass == key_class_akpu) { - secwarning("SecDbBackup: Don't tempt me Frodo!"); - [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Do not call wrapItemKey with class akpu"]; - return nil; - } - - if (![self createOrLoadBackupInfrastructure:error]) { - if ((*error).domain != (__bridge NSString*)kSecErrorDomain || (*error).code != errSecInteractionNotAllowed) { - secerror("SecDbBackup: Could not create/load backup infrastructure: %@", *error); - } - return nil; - } - - __block SecDbBackupWrappedItemKey* backupWrappedKey; - - __block NSMutableData* wrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN]; - __block NSError* localError; - dispatch_sync(_queue, ^{ - if (![self onQueueCreateOrLoadBackupInfrastructure:&localError]) { - return; - } - if (![SecAKSObjCWrappers aksEncryptWithKeybag:self->_handle - keyclass:keyclass - plaintext:key.keyData - outKeyclass:nil - ciphertext:wrappedKey - error:&localError]) { - return; - } - SFSignedData* wrappedAndSigned = [self onQueueSignData:wrappedKey withKCSKForKeyclass:keyclass error:&localError]; - if (!wrappedAndSigned) { - if (localError.code != SecDbBackupKeychainLocked) { - secerror("SecDbBackup: Unable to sign item for class %d: %@", keyclass, localError); - return; - } - } - backupWrappedKey = [SecDbBackupWrappedItemKey new]; - backupWrappedKey.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedAndSigned requiringSecureCoding:YES error:&localError]; - backupWrappedKey.baguuid = self->_bagIdentity.baguuid; - }); - - if (localError) { - secerror("SecDbBackup: Unable to wrap-and-sign item of class %d: %@", keyclass, localError); - *error = localError; - return nil; - } - - return backupWrappedKey; -} - -- (SFSignedData*)onQueueSignData:(NSMutableData*)data withKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error -{ - SFECKeyPair* kcsk = [self onQueueFetchKCSKForKeyclass:keyclass error:error]; - if (!kcsk) { - return nil; - } - - SFEC_X962SigningOperation* op = [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - return [op sign:data withKey:kcsk error:error]; -} - -#pragma mark - Testing Helpers - -- (keybag_handle_t)createBackupBagWithSecret:(NSData*)secret error:(NSError**)error -{ - assert(error); - __block keybag_handle_t handle = bad_keybag_handle; - __block NSError* localError; - dispatch_sync(_queue, ^{ - handle = [self onQueueCreateBackupBagWithSecret:secret error:&localError]; - }); - if (localError) { - *error = localError; - } else if (handle == bad_keybag_handle) { - [self fillError:error code:SecDbBackupTestCodeFailure underlying:nil description:@"Unable to create backup bag, but no reason"]; - } - return handle; -} - -- (BOOL)saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error -{ - assert(error); - __block bool ok = true; - __block NSError* localErr; - __block CFErrorRef cfError = NULL; - dispatch_sync(_queue, ^{ - ok &= kc_with_dbt_non_item_tables(YES, &cfError, ^bool(SecDbConnectionRef dbt) { - ok &= kc_transaction(dbt, &cfError, ^bool{ - ok &= [self onQueueInTransaction:dbt saveBackupBag:handle asDefault:asDefault error:&localErr]; - return ok; - }); - return ok; - }); - }); - - if (!ok) { - if (cfError) { - [self fillError:error code:SecDbBackupTestCodeFailure underlying:CFBridgingRelease(cfError) description:@"Unable to save keybag to disk"]; - } else if (localErr) { - *error = localErr; - } else if (!localErr) { - [self fillError:error code:SecDbBackupTestCodeFailure underlying:nil description:@"Unable to save keybag to disk but who knows why"]; - } - } - return ok; -} - -- (keybag_handle_t)loadBackupBag:(NSUUID*)uuid error:(NSError**)error { - __block keybag_handle_t handle = bad_keybag_handle; - __block NSError* localError; - dispatch_sync(_queue, ^{ - handle = [self onQueueLoadBackupBag:uuid error:&localError]; - }); - if (error && localError) { - *error = localError; - } - return handle; -} - -- (SecDbBackupRecoverySet*)createRecoverySetWithBagSecret:(NSData*)secret forType:(SecDbBackupRecoveryType)type error:(NSError**)error -{ - __block SecDbBackupRecoverySet* set; - __block BOOL ok = YES; - __block NSError* localError; - __block CFErrorRef cfError = NULL; - dispatch_sync(_queue, ^{ - ok &= kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) { - ok &= kc_transaction(dbt, &cfError, ^bool{ - set = [self onQueueInTransaction:dbt createRecoverySetWithBagSecret:secret forType:type error:&localError]; - return set != nil; - }); - return ok; - }); - }); - if (error && cfError) { - *error = CFBridgingRelease(cfError); - } else if (error && localError) { - *error = localError; - } - CFReleaseNull(cfError); - - return set; -} - -- (SFECKeyPair*)fetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error -{ - __block SFECKeyPair* keypair; - __block NSError* localError; - dispatch_sync(_queue, ^{ - keypair = [self onQueueFetchKCSKForKeyclass:keyclass error:&localError]; - }); - if (localError && error) { - *error = localError; - } - - return keypair; -} - -@end - -#endif // SECDB_BACKUPS_ENABLED diff --git a/OSX/sec/securityd/SecDbBackupManager_Internal.h b/OSX/sec/securityd/SecDbBackupManager_Internal.h deleted file mode 100644 index 71a3b3eb..00000000 --- a/OSX/sec/securityd/SecDbBackupManager_Internal.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// DO NOT INCLUDE ME (unless you're SecDbBackupManager.m or a unit test) -// These are for internal use and testing only - -#ifndef SecDbBackupManager_Internal_h -#define SecDbBackupManager_Internal_h - -// Need these things in tests, too -#import "SecDbBackupManager.h" - -#if SECDB_BACKUPS_ENABLED - -#import "SecDbBackupBag.h" -#import "SecDbBackupBagIdentity.h" -#import "SecDbBackupKeyClassSigningKey.h" -#import "SecDbBackupMetadataClassKey.h" -#import "SecDbBackupRecoverySet.h" - -#include - -#import -#import -#import -#import - -@interface SecDbBackupManager (Internal) -@property (nonatomic) SecDbBackupBagIdentity* bagIdentity; - -#define BACKUPBAG_PASSPHRASE_LENGTH 32 -#define UUIDBYTESLENGTH 16 - -+ (void)resetManager; -- (NSData*)createBackupBagSecret:(NSError**)error; -- (keybag_handle_t)createBackupBagWithSecret:(NSData*)secret error:(NSError**)error; -- (BOOL)saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error; -- (keybag_handle_t)loadBackupBag:(NSUUID*)uuid error:(NSError**)error; -- (BOOL)createOrLoadBackupInfrastructure:(NSError**)error; -- (SecDbBackupKeyClassSigningKey*)createKCSKForKeyClass:(keyclass_t)keyclass withWrapper:(SFAESKey*)wrapper error:(NSError**)error; -- (SecDbBackupRecoverySet*)createRecoverySetWithBagSecret:(NSData*)secret forType:(SecDbBackupRecoveryType)type error:(NSError**)error; -- (SFECKeyPair*)fetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error; - -// Pure utilities -- (NSData*)getSHA256OfData:(NSData*)data; -- (SFECKeyPair*)ECKeyPairFromDerBytes:(void*)bytes length:(size_t)len error:(NSError**)error; - -@end - -#endif // SECDB_BACKUPS_ENABLED - -#endif /* SecDbBackupManager_Internal_h */ diff --git a/OSX/sec/securityd/SecDbItem.c b/OSX/sec/securityd/SecDbItem.c deleted file mode 100644 index 167e95d5..00000000 --- a/OSX/sec/securityd/SecDbItem.c +++ /dev/null @@ -1,1867 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecDbItem.c - CoreFoundation-based constants and functions representing - * database items (certificates, keys, identities, and passwords.) - */ - -#if TARGET_DARWINOS -#undef OCTAGON -#undef SECUREOBJECTSYNC -#undef SHAREDWEBCREDENTIALS -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// MARK: type converters - -CFStringRef copyString(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFStringGetTypeID()) { - return CFStringCreateCopy(0, obj); - }else if (tid == CFDataGetTypeID()) { - return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8); - } else if (tid == CFUUIDGetTypeID()) { - return CFUUIDCreateString(NULL, obj); - } else { - return NULL; - } -} - -CFDataRef copyData(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFDataGetTypeID()) { - return CFDataCreateCopy(0, obj); - } else if (tid == CFStringGetTypeID()) { - return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0); - } else if (tid == CFNumberGetTypeID()) { - SInt32 value; - CFNumberGetValue(obj, kCFNumberSInt32Type, &value); - return CFDataCreate(0, (const UInt8 *)&value, sizeof(value)); - } else { - return NULL; - } -} - -CFTypeRef copyUUID(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFDataGetTypeID()) { - CFIndex length = CFDataGetLength(obj); - if (length != 0 && length != 16) - return NULL; - return CFDataCreateCopy(NULL, obj); - } else if (tid == CFNullGetTypeID()) { - return CFDataCreate(NULL, NULL, 0); - } else if (tid == CFUUIDGetTypeID()) { - CFUUIDBytes uuidbytes = CFUUIDGetUUIDBytes(obj); - CFDataRef uuiddata = CFDataCreate(NULL, (void*) &uuidbytes, sizeof(uuidbytes)); - return uuiddata; - } else { - return NULL; - } -} - - -CFTypeRef copyBlob(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFDataGetTypeID()) { - return CFDataCreateCopy(0, obj); - } else if (tid == CFStringGetTypeID()) { - return CFStringCreateCopy(0, obj); - } else if (tid == CFNumberGetTypeID()) { - CFRetain(obj); - return obj; - } else { - return NULL; - } -} - -CFDataRef copySHA1(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFDataGetTypeID() && CFDataGetLength(obj) == CCSHA1_OUTPUT_SIZE) { - return CFDataCreateCopy(CFGetAllocator(obj), obj); - } else { - return NULL; - } -} - -CFTypeRef copyNumber(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFNumberGetTypeID()) { - CFRetain(obj); - return obj; - } else if (tid == CFBooleanGetTypeID()) { - SInt32 value = CFBooleanGetValue(obj); - return CFNumberCreate(0, kCFNumberSInt32Type, &value); - } else if (tid == CFStringGetTypeID()) { - SInt32 value = CFStringGetIntValue(obj); - CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value); - /* If a string converted to an int isn't equal to the int printed as - a string, return a CFStringRef instead. */ - if (!CFEqual(t, obj)) { - CFRelease(t); - return CFStringCreateCopy(0, obj); - } - CFRelease(t); - return CFNumberCreate(0, kCFNumberSInt32Type, &value); - } else - return NULL; -} - -CFDateRef copyDate(CFTypeRef obj) { - CFTypeID tid = CFGetTypeID(obj); - if (tid == CFDateGetTypeID()) { - CFRetain(obj); - return obj; - } else - return NULL; -} - -// MARK: SecDbColumn accessors, to retrieve values as CF types in SecDbStep. - -static CFDataRef SecDbColumnCopyData(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { - return CFDataCreate(allocator, sqlite3_column_blob(stmt, col), - sqlite3_column_bytes(stmt, col)); - //return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col), - // sqlite3_column_bytes(stmt, col), - // kCFAllocatorNull); -} - -static CFDateRef SecDbColumnCopyDate(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { - return CFDateCreate(allocator, sqlite3_column_double(stmt, col)); -} - -static CFNumberRef SecDbColumnCopyDouble(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { - double number = sqlite3_column_double(stmt, col); - return CFNumberCreate(allocator, kCFNumberDoubleType, &number); -} - -static CFNumberRef SecDbColumnCopyNumber64(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { - sqlite_int64 number = sqlite3_column_int64(stmt, col); - return CFNumberCreate(allocator, kCFNumberSInt64Type, &number); -} - -static CFNumberRef SecDbColumnCopyNumber(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { - sqlite_int64 number = sqlite3_column_int64(stmt, col); - if (INT32_MIN <= number && number <= INT32_MAX) { - int32_t num32 = (int32_t)number; - return CFNumberCreate(allocator, kCFNumberSInt32Type, &num32); - } else { - return CFNumberCreate(allocator, kCFNumberSInt64Type, &number); - } -} - -static CFTypeRef SecDbColumnCopyString(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error, - CFOptionFlags flags) { - const unsigned char *text = sqlite3_column_text(stmt, col); - if (!text || 0 == strlen((const char *)text)) { - if (flags & kSecDbDefaultEmptyFlag) { - return CFSTR(""); - } else if (flags & kSecDbDefault0Flag) { - return CFSTR("0"); - } else { - return kCFNull; - } - } - return CFStringCreateWithBytes(allocator, text, strlen((const char *)text), kCFStringEncodingUTF8, false); -} - -// MARK: SecDbClass helpers - -const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error) { - const SecDbAttr *result = NULL; - SecDbForEachAttr(class, desc) { - if (desc->kind == kind) - result = desc; - } - - if (!result) - SecError(errSecInternal, error, CFSTR("Can't find attribute of kind %d in class %@"), kind, class->name); - - return result; -} - -// MARK: SecDbAttr helpers - -static bool SecDbIsTombstoneDbSelectAttr(const SecDbAttr *attr) { - return attr->flags & kSecDbPrimaryKeyFlag || attr->kind == kSecDbTombAttr; -} - -#if 0 -static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) { - return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbModificationDateAttr; -} -#endif - -static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) { - // We add AuthenticatedData to include UUIDs, which can't be primary keys - return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr || (attr->flags & kSecDbInAuthenticatedDataFlag); -} - -CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error) { - CFTypeRef value = NULL; - switch (attr->kind) { - case kSecDbAccessAttr: - case kSecDbStringAttr: - case kSecDbAccessControlAttr: - value = CFSTR(""); - break; - case kSecDbBlobAttr: - case kSecDbDataAttr: - value = CFDataCreate(kCFAllocatorDefault, NULL, 0); - break; - case kSecDbUUIDAttr: - value = CFDataCreate(kCFAllocatorDefault, NULL, 0); - break; - case kSecDbNumberAttr: - case kSecDbSyncAttr: - case kSecDbTombAttr: - { - int32_t zero = 0; - value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &zero); - break; - } - case kSecDbDateAttr: - value = CFDateCreate(kCFAllocatorDefault, 0.0); - break; - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - break; - default: - SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name); - value = NULL; - } - - return value; -} - -static CFTypeRef SecDbAttrCopyValueForDb(const SecDbAttr *attr, CFTypeRef value, CFErrorRef *error) { - CFDataRef data = NULL; - CFTypeRef result = NULL; - - if (value == NULL) - value = kCFNull; - - if (CFEqual(value, kCFNull) && attr->flags & kSecDbPrimaryKeyFlag) { - // SQLITE3 doesn't like NULL for primary key attributes, pretend kSecDbDefaultEmptyFlag was specified - require_quiet(result = SecDbAttrCopyDefaultValue(attr, error), out); - } else { - result = CFRetain(value); - } - - if (attr->flags & kSecDbSHA1ValueInFlag && !CFEqual(result, kCFNull)) { - require_action_quiet(data = copyData(result), out, - SecError(errSecInternal, error, CFSTR("failed to get attribute %@ data"), attr->name); - CFReleaseNull(result)); - CFAssignRetained(result, CFDataCopySHA1Digest(data, error)); - } - -out: - CFReleaseSafe(data); - return result; -} - -static CFStringRef SecDbAttrGetHashName(const SecDbAttr *attr) { - if ((attr->flags & kSecDbSHA1ValueInFlag) == 0) { - return attr->name; - } - - static dispatch_once_t once; - static CFMutableDictionaryRef hash_store; - static dispatch_queue_t queue; - dispatch_once(&once, ^{ - queue = dispatch_queue_create("secd-hash-name", NULL); - hash_store = CFDictionaryCreateMutableForCFTypes(NULL); - }); - - __block CFStringRef name; - dispatch_sync(queue, ^{ - name = CFDictionaryGetValue(hash_store, attr->name); - if (name == NULL) { - name = CFStringCreateWithFormat(NULL, NULL, CFSTR("#%@"), attr->name); - CFDictionarySetValue(hash_store, attr->name, name); - CFRelease(name); - } - }); - return name; -} - -// MARK: SecDbItem - -CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name) { - return CFDictionaryGetValue(item->attributes, name); -} - -static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *desc) { - return CFDictionaryGetValue(item->attributes, desc->name); -} - -CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SecDbForEachAttrWithMask(item->class, desc, mask) { - CFTypeRef value = SecDbItemGetValue(item, desc, error); - if (value) { - if (!CFEqual(kCFNull, value)) { - CFDictionarySetValue(dict, desc->name, value); - } else if (desc->flags & kSecDbNotNullFlag) { - SecError(errSecDecode, error, CFSTR("attribute %@ has NULL value"), desc->name); - secerror("%@", error ? *error : (CFErrorRef)CFSTR("error == NULL")); - CFReleaseNull(dict); - break; - } - } else { - CFReleaseNull(dict); - break; - } - } - return dict; -} - -void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle) { - CFRetainAssign(item->credHandle, cred_handle); -} - -void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups) { - CFRetainAssign(item->callerAccessGroups, caller_access_groups); -} - -CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error) { - CFDataRef edata = NULL; - keybag_handle_t keybag = (keybag_handle_t)handle; - CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); - CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); - if (attributes || auth_attributes) { - SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error); - if (access_control) { - if (ks_encrypt_data_legacy(keybag, access_control, item->credHandle, attributes, auth_attributes, &edata, false, error)) { - item->_edataState = kSecDbItemEncrypting; - } else { - seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR("")); - } - CFRelease(access_control); - } - CFReleaseNull(attributes); - CFReleaseNull(auth_attributes); - } - - return edata; -} - -bool SecDbItemEnsureDecrypted(SecDbItemRef item, bool decryptSecretData, CFErrorRef *error) { - - // If we haven't yet decrypted the item, make sure we do so now - bool result = true; - if (item->_edataState == kSecDbItemEncrypted || (decryptSecretData && item->_edataState == kSecDbItemSecretEncrypted)) { - const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error); - if (attr) { - CFDataRef edata = SecDbItemGetCachedValue(item, attr); - if (!edata) - return SecError(errSecInternal, error, CFSTR("state= encrypted but edata is NULL")); - // Decrypt calls set value a bunch of times which clears our edata and changes our state. - item->_edataState = kSecDbItemDecrypting; - result = SecDbItemDecrypt(item, decryptSecretData, edata, error); - if (result) - item->_edataState = decryptSecretData ? kSecDbItemClean : kSecDbItemSecretEncrypted; - else - item->_edataState = kSecDbItemEncrypted; - } - } - return result; -} - -// Only called if cached value is not found. -static CFTypeRef SecDbItemCopyValue(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { - if (attr->copyValue) { - return attr->copyValue(item, attr, error); - } - - CFTypeRef value = NULL; - switch (attr->kind) { - // These have an explicit copyValue; here to shut up compiler - case kSecDbSHA1Attr: - case kSecDbEncryptedDataAttr: - case kSecDbPrimaryKeyAttr: - value = NULL; - break; - case kSecDbAccessAttr: - case kSecDbStringAttr: - case kSecDbBlobAttr: - case kSecDbAccessControlAttr: - if (attr->flags & kSecDbNotNullFlag) { - if (attr->flags & kSecDbDefault0Flag) { - value = CFSTR("0"); - break; - } else if (attr->kind != kSecDbBlobAttr && attr->flags & kSecDbDefaultEmptyFlag) { - // blob drops through to data everything else is empty string - value = CFSTR(""); - break; - } - } - //DROPTHROUGH - case kSecDbDataAttr: - if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefaultEmptyFlag) { - value = CFDataCreate(CFGetAllocator(item), NULL, 0); - } else { - value = kCFNull; - } - break; - case kSecDbUUIDAttr: - value = CFDataCreate(CFGetAllocator(item), NULL, 0); - break; - case kSecDbNumberAttr: - case kSecDbSyncAttr: - case kSecDbTombAttr: - if (attr->flags & kSecDbNotNullFlag) { - int32_t zero = 0; - value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &zero); - } else { - value = kCFNull; - } - break; - case kSecDbDateAttr: - if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefault0Flag) { - value = CFDateCreate(kCFAllocatorDefault, 0.0); - } else { - value = kCFNull; - } - break; - case kSecDbRowIdAttr: - if (attr->flags & kSecDbNotNullFlag) { - // No can do, error? - } - value = kCFNull; - break; - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - value = CFDateCreate(CFGetAllocator(item), CFAbsoluteTimeGetCurrent()); - break; - case kSecDbUTombAttr: - value = kCFNull; - break; - } - - return value; -} - -// SecDbItemGetValue will return kCFNull if there is no value for an attribute and this was not -// an error. It will return NULL and optionally set *error if there was an error computing an -// attribute, or if a required attribute was missing a value and had no known way to compute -// it's value. -CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) { - // Propagate chained errors - if (!desc) - return NULL; - - if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag || desc->flags & kSecDbReturnDataFlag) { - if (!SecDbItemEnsureDecrypted(item, desc->flags & kSecDbReturnDataFlag, error)) - return NULL; - } - - CFTypeRef value = SecDbItemGetCachedValue(item, desc); - if (!value) { - value = SecDbItemCopyValue(item, desc, error); - if (value) { - if (CFEqual(kCFNull, value)) { - CFRelease(value); // This is redundant but it shuts clang's static analyzer up. - value = kCFNull; - } else { - SecDbItemSetValue(item, desc, value, error); - CFRelease(value); - value = SecDbItemGetCachedValue(item, desc); - } - } - } - return value; -} - -CFTypeRef SecDbItemGetValueKind(SecDbItemRef item, SecDbAttrKind descKind, CFErrorRef *error) { - CFTypeRef result = NULL; - - const SecDbClass * itemClass = SecDbItemGetClass(item); - const SecDbAttr * desc = SecDbClassAttrWithKind(itemClass, descKind, error); - - if (desc) { - result = SecDbItemGetValue(item, desc, error); - } - - return result; -} - - -// Similar as SecDbItemGetValue, but if attr represents attribute stored into DB field as hash, returns -// hashed value for the attribute. -static CFTypeRef SecDbItemCopyValueForDb(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) { - CFTypeRef value = NULL; - CFStringRef hash_name = NULL; - hash_name = SecDbAttrGetHashName(desc); - if ((desc->flags & kSecDbSHA1ValueInFlag) && (desc->flags & kSecDbInFlag)) { - value = CFRetainSafe(CFDictionaryGetValue(item->attributes, hash_name)); - } - - if (value == NULL) { - require_quiet(value = SecDbItemGetValue(item, desc, error), out); - require_action_quiet(value = SecDbAttrCopyValueForDb(desc, value, error), out, CFReleaseNull(value)); - if ((desc->flags & kSecDbSHA1ValueInFlag) != 0) { - CFDictionarySetValue(item->attributes, hash_name, value); - } - } - -out: - return value; -} - -static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool *bvalue, CFErrorRef *error) { - CFTypeRef value = SecDbItemGetValue(item, desc, error); - if (!value) - return false; - char cvalue; - *bvalue = (isNumber(value) && CFNumberGetValue(value, kCFNumberCharType, &cvalue) && cvalue == 1); - return true; -} - -static CFStringRef SecDbItemCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - CFStringRef desc; - if (isDictionary(formatOptions) && CFDictionaryContainsKey(formatOptions, kSecDebugFormatOption)) { - SecDbItemRef item = (SecDbItemRef)cf; - CFMutableStringRef mdesc = CFStringCreateMutable(CFGetAllocator(cf), 0); - CFStringAppendFormat(mdesc, NULL, CFSTR("<%@"), item->class->name); - SecDbForEachAttr(item->class, attr) { - CFTypeRef value = SecDbItemGetValue(item, attr, NULL); - if (value) { - CFStringAppend(mdesc, CFSTR(",")); - CFStringAppend(mdesc, attr->name); - CFStringAppend(mdesc, CFSTR("=")); - if (CFEqual(CFSTR("data"), attr->name)) { - CFStringAppendEncryptedData(mdesc, value); - } else if (CFEqual(CFSTR("v_Data"), attr->name)) { - CFStringAppend(mdesc, CFSTR("")); - } else if (isData(value)) { - CFStringAppendHexData(mdesc, value); - } else { - CFStringAppendFormat(mdesc, 0, CFSTR("%@"), value); - } - } - } - CFStringAppend(mdesc, CFSTR(">")); - desc = mdesc; - } else { - SecDbItemRef item = (SecDbItemRef)cf; - const UInt8 zero4[4] = {}; - const UInt8 *pk = &zero4[0], *sha1 = &zero4[0]; - char sync = 0; - char tomb = 0; - SInt64 rowid = 0; - CFStringRef access = NULL; - uint8_t mdatbuf[32] = {}; - uint8_t *mdat = &mdatbuf[0]; - CFMutableStringRef attrs = CFStringCreateMutable(kCFAllocatorDefault, 0); - CFStringRef agrp = NULL; - CFBooleanRef utomb = NULL; - - SecDbForEachAttr(item->class, attr) { - CFTypeRef value; - switch (attr->kind) { - case kSecDbBlobAttr: - case kSecDbDataAttr: - case kSecDbStringAttr: - case kSecDbNumberAttr: - case kSecDbDateAttr: - case kSecDbEncryptedDataAttr: - if (attr->flags & (kSecDbReturnAttrFlag | kSecDbReturnDataFlag) && (value = SecDbItemGetValue(item, attr, NULL)) && !CFEqual(value, kCFNull)) { - if (isString(value) && CFEqual(attr->name, kSecAttrAccessGroup)) { - agrp = value; - } else { - // We don't log these, just record that we saw the attribute. - CFStringAppend(attrs, CFSTR(",")); - CFStringAppend(attrs, attr->name); - } - } - break; - case kSecDbUUIDAttr: - if ((value = SecDbItemGetValue(item, attr, NULL))) { - if (CFEqual(attr->name, kSecAttrMultiUser)) { - if (isData(value)) { - CFStringAppend(attrs, CFSTR(",")); - if (CFDataGetLength(value)) { - CFStringAppendHexData(attrs, value); - } else { - CFStringAppend(attrs, attr->name); - } - } - } - } - break; - case kSecDbCreationDateAttr: - // We don't care about this and every object has one. - break; - case kSecDbModificationDateAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isDate(value)) - mdat = der_encode_generalizedtime_body(CFDateGetAbsoluteTime(value), NULL, mdat, &mdatbuf[31]); - break; - case kSecDbSHA1Attr: - value = SecDbItemGetValue(item, attr, NULL); - if (isData(value) && CFDataGetLength(value) >= (CFIndex)sizeof(zero4)) - sha1 = CFDataGetBytePtr(value); - break; - case kSecDbRowIdAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isNumber(value)) - CFNumberGetValue(value, kCFNumberSInt64Type, &rowid); - break; - case kSecDbPrimaryKeyAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isData(value)) - pk = CFDataGetBytePtr(value); - break; - case kSecDbSyncAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isNumber(value)) - CFNumberGetValue(value, kCFNumberCharType, &sync); - break; - case kSecDbTombAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isNumber(value)) - CFNumberGetValue(value, kCFNumberCharType, &tomb); - break; - case kSecDbAccessAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isString(value)) - access = value; - break; - case kSecDbUTombAttr: - value = SecDbItemGetValue(item, attr, NULL); - if (isBoolean(value)) - utomb = value; - case kSecDbAccessControlAttr: - /* TODO: Add formatting of ACLs. */ - break; - } - } - - desc = CFStringCreateWithFormat(CFGetAllocator(cf), NULL, - CFSTR( - "%s," - "%@," - "%02X%02X%02X%02X," - "%s," - "%@," - "%@," - "%"PRId64 - "%@," - "%s," - "%s" - "%02X%02X%02X%02X"), - tomb ? "T" : "O", - item->class->name, - pk[0], pk[1], pk[2], pk[3], - sync ? "S" : "L", - access, - agrp, - rowid, - attrs, - mdat, - utomb ? (CFEqual(utomb, kCFBooleanFalse) ? "F," : "T,") : "", - sha1[0], sha1[1], sha1[2], sha1[3]); - CFReleaseSafe(attrs); - } - - return desc; -} - -static void SecDbItemDestroy(CFTypeRef cf) { - SecDbItemRef item = (SecDbItemRef)cf; - CFReleaseSafe(item->attributes); - CFReleaseSafe(item->credHandle); - CFReleaseSafe(item->callerAccessGroups); - CFReleaseSafe(item->cryptoOp); -} - -static CFHashCode SecDbItemHash(CFTypeRef cf) { - SecDbItemRef item = (SecDbItemRef)cf; - CFDataRef digest = SecDbItemGetSHA1(item, NULL); - CFHashCode code; - const UInt8 *p = CFDataGetBytePtr(digest); - // Read first 8 bytes of digest in order - code = p[0] + ((p[1] + ((p[2] + ((p[3] + ((p[4] + ((p[5] + ((p[6] + (p[7] << 8)) << 8)) << 8)) << 8)) << 8)) << 8)) << 8); - return code; -} - -static Boolean SecDbItemCompare(CFTypeRef cf1, CFTypeRef cf2) { - SecDbItemRef item1 = (SecDbItemRef)cf1; - SecDbItemRef item2 = (SecDbItemRef)cf2; - CFDataRef digest1 = NULL; - CFDataRef digest2 = NULL; - if (item1) - digest1 = SecDbItemGetSHA1(item1, NULL); - if (item2) - digest2 = SecDbItemGetSHA1(item2, NULL); - Boolean equal = CFEqual(digest1, digest2); - return equal; -} - -CFGiblisWithHashFor(SecDbItem) - -static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass *class, keybag_handle_t keybag) { - SecDbItemRef item = CFTypeAllocate(SecDbItem, struct SecDbItem, allocator); - item->class = class; - item->attributes = CFDictionaryCreateMutableForCFTypes(allocator); - item->keybag = keybag; - item->_edataState = kSecDbItemDirty; - item->cryptoOp = kAKSKeyOpDecrypt; - - return item; -} - -const SecDbClass *SecDbItemGetClass(SecDbItemRef item) { - return item->class; -} - -keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item) { - return item->keybag; -} - -bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error) { - if (!SecDbItemEnsureDecrypted(item, true, error)) - return false; - if (item->keybag != keybag) { - item->keybag = keybag; - if (item->_edataState == kSecDbItemClean) { - SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL); - } - } - - return true; -} - -bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error) { - // Propagate chained errors. - if (!desc) - return false; - - if (!value) - value = kCFNull; - - if (desc->setValue) - return desc->setValue(item, desc, value, error); - - if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) { - if (!SecDbItemEnsureDecrypted(item, true, error)) { - return false; - } - } - - bool changed = false; - CFTypeRef attr = NULL; - switch (desc->kind) { - case kSecDbPrimaryKeyAttr: - case kSecDbDataAttr: - attr = copyData(value); - break; - case kSecDbEncryptedDataAttr: - attr = copyData(value); - if (attr) { - if (item->_edataState == kSecDbItemEncrypting) - item->_edataState = kSecDbItemClean; - else - item->_edataState = kSecDbItemEncrypted; - } else if (!value || CFEqual(kCFNull, value)) { - item->_edataState = kSecDbItemDirty; - } - break; - case kSecDbBlobAttr: - case kSecDbAccessControlAttr: - attr = copyBlob(value); - break; - case kSecDbDateAttr: - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - attr = copyDate(value); - break; - case kSecDbNumberAttr: - case kSecDbSyncAttr: - case kSecDbTombAttr: - case kSecDbRowIdAttr: - attr = copyNumber(value); - break; - case kSecDbAccessAttr: - case kSecDbStringAttr: - attr = copyString(value); - break; - case kSecDbSHA1Attr: - attr = copySHA1(value); - break; - case kSecDbUTombAttr: - attr = CFRetainSafe(asBoolean(value, NULL)); - break; - case kSecDbUUIDAttr: - attr = copyUUID(value); - break; - } - - if (attr) { - CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name); - changed = (!ovalue || !CFEqual(ovalue, attr)); - CFDictionarySetValue(item->attributes, desc->name, attr); - CFRelease(attr); - } else { - if (value && !CFEqual(kCFNull, value)) { - SecError(errSecItemInvalidValue, error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value); - return false; - } - CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name); - changed = (ovalue && !CFEqual(ovalue, kCFNull)); - CFDictionaryRemoveValue(item->attributes, desc->name); - } - - if (changed) { - if (desc->flags & kSecDbInHashFlag) - SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL), kCFNull, NULL); - if (desc->flags & kSecDbPrimaryKeyFlag) - SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, NULL), kCFNull, NULL); - if ((desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) && (item->_edataState == kSecDbItemClean || (item->_edataState == kSecDbItemSecretEncrypted && (desc->flags & kSecDbReturnDataFlag) == 0))) - SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL); - if (desc->flags & kSecDbSHA1ValueInFlag) - CFDictionaryRemoveValue(item->attributes, SecDbAttrGetHashName(desc)); - } - - return true; -} - -bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error) { - SecDbForEachAttr(item->class, attr) { - CFTypeRef value = CFDictionaryGetValue(values, attr->name); - if (value && !SecDbItemSetValue(item, attr, value, error)) - return false; - } - return true; -} - -bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error) { - SecDbForEachAttr(item->class, attr) { - if (CFEqual(attr->name, name)) { - return SecDbItemSetValue(item, attr, value, error); - } - } - return false; -} - -bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error) { - bool ok = true; - if (item->_edataState == kSecDbItemClean) - ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error), kCFNull, error); - if (ok && access_control) { //added check for access_control because ks_decrypt_data can leave NULL in access_control in case of error - item->_edataState = kSecDbItemDirty; - CFDataRef data = SecAccessControlCopyData(access_control); - ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), data, error); - CFRelease(data); - } - return ok; -} - -SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error) { - SecDbItemRef item = SecDbItemCreate(kCFAllocatorDefault, class, keybag); - if (item && !SecDbItemSetValues(item, attributes, error)) - CFReleaseNull(item); - return item; -} - -static CFTypeRef -SecDbColumnCopyValueWithAttr(CFAllocatorRef allocator, sqlite3_stmt *stmt, const SecDbAttr *attr, int col, CFErrorRef *error) { - CFTypeRef value = NULL; - switch (attr->kind) { - case kSecDbDateAttr: - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - value = SecDbColumnCopyDate(allocator, stmt, col, error); - break; - case kSecDbBlobAttr: - case kSecDbNumberAttr: - switch (sqlite3_column_type(stmt, col)) { - case SQLITE_INTEGER: - value = SecDbColumnCopyNumber(allocator, stmt, col, error); - break; - case SQLITE_FLOAT: - value = SecDbColumnCopyDouble(allocator, stmt, col, error); - break; - case SQLITE_TEXT: - value = SecDbColumnCopyString(allocator, stmt, col, error, - attr->flags); - break; - case SQLITE_BLOB: - value = SecDbColumnCopyData(allocator, stmt, col, error); - break; - case SQLITE_NULL: - value = kCFNull; - break; - } - break; - case kSecDbAccessAttr: - case kSecDbStringAttr: - value = SecDbColumnCopyString(allocator, stmt, col, error, - attr->flags); - break; - case kSecDbDataAttr: - case kSecDbUUIDAttr: - case kSecDbSHA1Attr: - case kSecDbPrimaryKeyAttr: - case kSecDbEncryptedDataAttr: - value = SecDbColumnCopyData(allocator, stmt, col, error); - break; - case kSecDbSyncAttr: - case kSecDbTombAttr: - value = SecDbColumnCopyNumber(allocator, stmt, col, error); - break; - case kSecDbRowIdAttr: - value = SecDbColumnCopyNumber64(allocator, stmt, col, error); - break; - case kSecDbAccessControlAttr: - case kSecDbUTombAttr: - /* This attributes does not have any database column associated, exists only inside encrypted blob as metadata. */ - break; - } - return value; -} - -SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)) { - SecDbItemRef item = SecDbItemCreate(allocator, class, keybag); - int col = 0; - SecDbForEachAttr(class, attr) { - if (return_attr(attr)) { - CFTypeRef value = SecDbColumnCopyValueWithAttr(allocator, stmt, attr, col++, error); - require_action_quiet(value, errOut, CFReleaseNull(item)); - - CFDictionarySetValue(item->attributes, SecDbAttrGetHashName(attr), value); - CFRelease(value); - } - - const SecDbAttr *data_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, NULL); - if (data_attr != NULL && CFDictionaryGetValue(item->attributes, data_attr->name) != NULL) { - item->_edataState = kSecDbItemEncrypted; - } - } - -errOut: - return item; -} - -SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class, - CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error) { - SecDbItemRef item = SecDbItemCreate(allocator, class, keybag); - const SecDbAttr *edata_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, error); - if (edata_attr) { - if (!SecDbItemSetValue(item, edata_attr, edata, error)) - CFReleaseNull(item); - } - return item; -} - -// TODO: Hack -- Replace with real filtering - -// Return true iff an item for which SecDbItemIsSyncable() already returns true should be part of the v2 view. -bool SecDbItemInV2(SecDbItemRef item) { - const SecDbClass *iclass = SecDbItemGetClass(item); - return (SecDbItemGetCachedValueWithName(item, kSecAttrSyncViewHint) == NULL && - (iclass == genp_class() || iclass == inet_class() || iclass == keys_class() || iclass == cert_class())); -} - -// Return true iff an item for which SecDbItemIsSyncable() and SecDbItemInV2() already return true should be part of the v0 view. -bool SecDbItemInV2AlsoInV0(SecDbItemRef item) { - return (SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL && SecDbItemGetClass(item) != cert_class()); -} - -SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) { - SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag); - SecDbItemSetCredHandle(new_item, item->credHandle); - SecDbForEachAttr(item->class, attr) { - // Copy each attribute, except the mod date attribute (it will be reset to now when needed), - // from the updates dict unless it's not there in which case we copy the attribute from the passed in item. - if (attr->kind != kSecDbModificationDateAttr && attr->kind != kSecDbEncryptedDataAttr && attr->kind != kSecDbSHA1Attr && attr->kind != kSecDbPrimaryKeyAttr) { - CFTypeRef value = NULL; - if (CFDictionaryGetValueIfPresent(updates, attr->name, &value)) { - if (!value) - SecError(errSecParam, error, CFSTR("NULL value in dictionary")); - } else { - value = SecDbItemGetValue(item, attr, error); - } - if (!value || !SecDbItemSetValue(new_item, attr, value, error)) { - CFReleaseNull(new_item); - break; - } - } - } - return new_item; -} - -// Ensure that the date value of attr of new_item is greater than that of old_item. -static bool SecDbItemMakeAttrYounger(SecDbItemRef new_item, SecDbItemRef old_item, const SecDbAttr *attr, CFErrorRef *error) { - CFDateRef old_date = SecDbItemGetValue(old_item, attr, error); - if (!old_date) - return false; - CFDateRef new_date = SecDbItemGetValue(new_item, attr, error); - if (!new_date) - return false; - bool ok = true; - if (CFDateCompare(new_date, old_date, NULL) != kCFCompareGreaterThan) { - CFDateRef adjusted_date = CFDateCreate(kCFAllocatorDefault, CFDateGetAbsoluteTime(old_date) + 0.001); - if (adjusted_date) { - ok = SecDbItemSetValue(new_item, attr, adjusted_date, error); - CFRelease(adjusted_date); - } - } - return ok; -} - -// Ensure that the mod date of new_item is greater than that of old_item. -static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, CFErrorRef *error) { - const SecDbAttr *attr = SecDbClassAttrWithKind(new_item->class, kSecDbModificationDateAttr, error); - return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error); -} - -static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeTombStone, CFErrorRef *error) { - SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag); - SecDbForEachAttr(item->class, attr) { - if (attr->kind == kSecDbTombAttr) { - // Set the tomb attr to true to indicate a tombstone. - if (!SecDbItemSetValue(new_item, attr, kCFBooleanTrue, error)) { - CFReleaseNull(new_item); - break; - } - } else if (SecDbIsTombstoneDbUpdateAttr(attr)) { - // Copy all primary key attributes and creation timestamps from the original item. - CFTypeRef value = SecDbItemGetValue(item, attr, error); - if (!value || (!CFEqual(kCFNull, value) && !SecDbItemSetValue(new_item, attr, value, error))) { - CFReleaseNull(new_item); - break; - } - } else if (attr->kind == kSecDbModificationDateAttr) { - if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) { - CFReleaseNull(new_item); - break; - } - } else if (makeTombStone && attr->kind == kSecDbUTombAttr) { - if (makeTombStone) - SecDbItemSetValue(new_item, attr, makeTombStone, error); - } - } - - return new_item; -} - -bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject) { - // Only used for controlling logging - // Use agrp=com.apple.security.sos, since it is not encrypted - if (!itemObject) { - return false; - } - const SecDbAttr *agrp = SecDbAttrWithKey(SecDbItemGetClass(itemObject), kSecAttrAccessGroup, NULL); - CFTypeRef cfval = SecDbItemGetValue(itemObject, agrp, NULL); - return cfval && CFStringCompareSafe(cfval, kSOSInternalAccessGroup, NULL) == kCFCompareEqualTo; -} - - -// MARK: - -// MARK: SQL Construction helpers -- These should become private in the future - -void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma) { - assert(needComma); - if (*needComma) { - CFStringAppend(sql, CFSTR(",")); - } else { - *needComma = true; - } - CFStringAppend(sql, value); -} - -static void SecDbAppendElementEquals(CFMutableStringRef sql, CFStringRef value, bool *needComma) { - SecDbAppendElement(sql, value, needComma); - CFStringAppend(sql, CFSTR("=?")); -} - -/* Append AND is needWhere is NULL or *needWhere is false. Append WHERE - otherwise. Upon return *needWhere will be false. */ -void -SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) { - if (!needWhere || !*needWhere) { - CFStringAppend(sql, CFSTR(" AND ")); - } else { - CFStringAppend(sql, CFSTR(" WHERE ")); - *needWhere = false; - } -} - -void -SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) { - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppend(sql, col); - CFStringAppend(sql, CFSTR("=?")); -} - -void -SecDbAppendWhereOrAndNotEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) { - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppend(sql, col); - CFStringAppend(sql, CFSTR("!=?")); -} - -static void SecDbAppendCountArgsAndCloseParen(CFMutableStringRef sql, CFIndex count) { - bool needComma = false; - while (count-- > 0) - SecDbAppendElement(sql, CFSTR("?"), &needComma); - CFStringAppend(sql, CFSTR(")")); -} - -void -SecDbAppendWhereOrAndIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) { - if (count == 1) - return SecDbAppendWhereOrAndEquals(sql, col, needWhere); - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppend(sql, col); - CFStringAppend(sql, CFSTR(" IN (")); - SecDbAppendCountArgsAndCloseParen(sql, count); -} - -void -SecDbAppendWhereOrAndNotIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) { - if (count == 1) - return SecDbAppendWhereOrAndNotEquals(sql, col, needWhere); - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppend(sql, col); - CFStringAppend(sql, CFSTR(" NOT IN (")); - SecDbAppendCountArgsAndCloseParen(sql, count); -} - -static CFStringRef SecDbItemCopyInsertSQL(SecDbItemRef item, bool(^use_attr)(const SecDbAttr *attr)) { - CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0); - CFStringAppend(sql, CFSTR("INSERT INTO ")); - CFStringAppend(sql, item->class->name); - CFStringAppend(sql, CFSTR("(")); - bool needComma = false; - CFIndex used_attr = 0; - SecDbForEachAttr(item->class, attr) { - if (use_attr(attr)) { - ++used_attr; - SecDbAppendElement(sql, attr->name, &needComma); - } - } - CFStringAppend(sql, CFSTR(")VALUES(?")); - while (used_attr-- > 1) { - CFStringAppend(sql, CFSTR(",?")); - } - CFStringAppend(sql, CFSTR(")")); - return sql; - -} - -static bool SecDbItemInsertBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr)(const SecDbAttr *attr)) { - bool ok = true; - int param = 0; - SecDbForEachAttr(item->class, attr) { - if (use_attr(attr)) { - CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error); - ok = value && SecDbBindObject(stmt, ++param, value, error); - CFReleaseSafe(value); - if (!ok) - break; - } - } - return ok; -} - -sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error) { - sqlite3_int64 row_id = 0; - const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); - if (attr) { - CFNumberRef number = SecDbItemGetValue(item, attr, error); - if (!isNumber(number)|| !CFNumberGetValue(number, kCFNumberSInt64Type, &row_id)) - SecDbError(SQLITE_ERROR, error, CFSTR("rowid %@ is not a 64 bit number"), number); - } - - return row_id; -} - -static CFNumberRef SecDbItemCreateRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) { - return CFNumberCreate(CFGetAllocator(item), kCFNumberSInt64Type, &rowid); -} - -bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) { - bool ok = true; - const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); - if (attr) { - CFNumberRef value = SecDbItemCreateRowId(item, rowid, error); - if (!value) - return false; - - ok = SecDbItemSetValue(item, attr, value, error); - CFRelease(value); - } - return ok; -} - -bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error) { - bool ok = true; - const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); - if (attr) { - CFDictionaryRemoveValue(item->attributes, attr->name); - //ok = SecDbItemSetValue(item, attr, kCFNull, error); - } - return ok; -} - -static bool SecDbItemSetLastInsertRowId(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { - sqlite3_int64 rowid = sqlite3_last_insert_rowid(SecDbHandle(dbconn)); - return SecDbItemSetRowId(item, rowid, error); -} - -bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item) { - bool is_syncable_or_corrupted = false; - CFErrorRef localError = NULL; - if (!SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, &localError), - &is_syncable_or_corrupted, &localError)) { - is_syncable_or_corrupted = SecErrorGetOSStatus(localError) == errSecDecode; - } - CFReleaseSafe(localError); - return is_syncable_or_corrupted; -} - -bool SecDbItemIsSyncable(SecDbItemRef item) { - bool is_syncable; - if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, NULL), &is_syncable, NULL)) - return is_syncable; - return false; -} - -bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error) -{ - return SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, error), sync ? kCFBooleanTrue : kCFBooleanFalse, error); -} - -bool SecDbItemIsTombstone(SecDbItemRef item) { - bool is_tomb; - if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbTombAttr, NULL), &is_tomb, NULL)) - return is_tomb; - return false; -} - -CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error) { - return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, error), error); -} - -CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error) { - return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), error); -} - -static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErrorRef *error) { - CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, error); - if (!dict) - return NULL; - - SecDbQueryRef query = query_create(item->class, NULL, NULL, error); - if (query) { - CFReleaseSafe(query->q_item); - query->q_item = dict; - } - else - CFRelease(dict); - - return query; -} - -static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *error) { - CFErrorRef localError = NULL; - // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. - const struct SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, &localError); - CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, &localError)); - bool akpu = false; - - if (localError || !SecDbItemEnsureDecrypted(item, true, &localError)) { - if (SecErrorGetOSStatus(localError) == errSecDecode) { - // We failed to decrypt the item - const SecDbAttr *desc = SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, &localError); - SecAccessControlRef accc = NULL; - CFDataRef acccData = NULL; - - acccData = (CFDataRef)SecDbItemGetValue(item, desc, &localError); - if (isData(acccData)) { - accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, &localError); - } - - if (accc && CFEqualSafe(SecAccessControlGetProtection(accc), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { - akpu = true; - secwarning("cannot decrypt item %@, item is irrecoverably lost with older passcode (error %@)", item, localError); - } else { - secerror("error %@ reading item %@ (corrupted)", localError, item); - __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem); - } - CFReleaseNull(localError); - *is_corrupt = true; - } - } - - // Recompute sha1 hash attribute and compare with the cached one. - CFDataRef computedSHA1 = SecDbItemCopyValue(item, sha1attr, &localError); - if (storedSHA1 && computedSHA1 && !CFEqual(storedSHA1, computedSHA1)) { - CFStringRef storedHex = CFDataCopyHexString(storedSHA1), computedHex = CFDataCopyHexString(computedSHA1); - secerror("error %@ %@ != %@ item %@ (corrupted)", sha1attr->name, storedHex, computedHex, item); - __security_simulatecrash(CFSTR("Corrupted item (sha1 mismatch) found in keychain"), __sec_exception_code_CorruptItem); - CFReleaseSafe(storedHex); - CFReleaseSafe(computedHex); - *is_corrupt = true; - } - - // Sanity check that all attributes that must not be NULL actually aren't - if (!localError) SecDbForEachAttr(item->class, attr) { - if (attr->flags & (kSecDbInCryptoDataFlag | kSecDbInAuthenticatedDataFlag)) { - CFTypeRef value = SecDbItemGetValue(item, attr, &localError); - if (value) { - if (CFEqual(kCFNull, value) && attr->flags & kSecDbNotNullFlag) { - secerror("error attribute %@ has NULL value in item %@ (corrupted)", attr->name, item); - __security_simulatecrash(CFSTR("Corrupted item (attr NULL) found in keychain"), __sec_exception_code_CorruptItem); - *is_corrupt = true; - break; - } - } else { - if (SecErrorGetOSStatus(localError) == errSecDecode) { - // We failed to decrypt the item - if (akpu) { - secwarning("attribute %@: %@ item %@ (item lost with older passcode)", attr->name, localError, item); - } else { - secerror("error attribute %@: %@ item %@ (corrupted)", attr->name, localError, item); - __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem); - } - *is_corrupt = true; - CFReleaseNull(localError); - } - break; - } - } - } - - CFReleaseSafe(computedSHA1); - CFReleaseSafe(storedSHA1); - return SecErrorPropagate(localError, error); -} - -static void SecDbItemRecordUpdate(SecDbConnectionRef dbconn, SecDbItemRef deleted, SecDbItemRef inserted) { - SecDbRecordChange(dbconn, deleted, inserted); -} - -static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { - bool (^use_attr)(const SecDbAttr *attr) = ^bool(const SecDbAttr *attr) { - return (attr->flags & kSecDbInFlag); - }; - - if (!SecDbItemEnsureDecrypted(item, true, error)) { - return false; - } - - CFStringRef sql = SecDbItemCopyInsertSQL(item, use_attr); - __block bool ok = sql; - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - ok = (SecDbItemInsertBind(item, stmt, error, use_attr) && - SecDbStep(dbconn, stmt, error, NULL) && - SecDbItemSetLastInsertRowId(item, dbconn, error)); - }); - CFRelease(sql); - } - if (ok) { - secnotice("item", "inserted %@", item); - SecDbItemRecordUpdate(dbconn, NULL, item); - } else { - if (SecDbItemIsEngineInternalState(item)) { - secdebug ("item", "insert failed for item %@ with %@", item, error ? *error : NULL); - } else { - secnotice("item", "insert failed for item %@ with %@", item, error ? *error : NULL); - } - } - - return ok; -} - -bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error) { - return error && CFErrorGetCode(error) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(error)); -} - -bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) { - __block CFErrorRef localError = NULL; - __block bool ok = SecDbItemDoInsert(item, dbconn, &localError); - if (!ok && localError && CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { - SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(item, error); - if (query) { - CFRetainAssign(query->q_use_cred_handle, item->credHandle); - SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { - return attr->flags & kSecDbPrimaryKeyFlag; - }, NULL, NULL, ^(SecDbItemRef old_item, bool *stop) { - bool is_corrupt = false; - ok = SecDbItemIsCorrupt(old_item, &is_corrupt, error); - SecDbItemRef replace = NULL; - if (is_corrupt) { - // If old_item is corrupted pretend it's not there and just replace it. - replace = item; - CFRetain(replace); - if(error) - CFReleaseNull(*error); //item is corrupted and will be replaced, so drop the error - } else if (ok && duplicate) { - duplicate(old_item, &replace); - } - if (replace) { - const SecDbAttr *rowid_attr = SecDbClassAttrWithKind(old_item->class, kSecDbRowIdAttr, error); - CFNumberRef oldrowid = SecDbItemGetCachedValue(old_item, rowid_attr); - if (oldrowid) { - ok = SecDbItemSetValue(replace, rowid_attr, oldrowid, &localError); - if (ok && !is_corrupt) { - ok = SecDbItemMakeYounger(replace, old_item, error); - } - ok = ok && SecDbItemDoUpdate(old_item, replace, dbconn, &localError, ^bool (const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - } else { - ok = SecError(errSecInternal, &localError, CFSTR("no rowid for %@"), old_item); - } - CFRelease(replace); - if (ok) - CFReleaseNull(localError); // Clear the error, since we replaced the item. - } - }); - SecDbItemSetCredHandle(item, query->q_use_cred_handle); - ok &= query_destroy(query, error); - } - } - - return ok & SecErrorPropagate(localError, error); // Don't use && here! -} - -bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { - return SecDbItemInsertOrReplace(item, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) { - if (SecDbItemIsTombstone(old_item)) { - CFRetain(item); - *replace = item; - } - }); -} - -static CFStringRef SecDbItemCopyUpdateSQL(SecDbItemRef old_item, SecDbItemRef new_item, bool(^use_attr_in_where)(const SecDbAttr *attr)) { - CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(new_item), 0); - CFStringAppend(sql, CFSTR("UPDATE ")); - CFStringAppend(sql, new_item->class->name); - CFStringAppend(sql, CFSTR(" SET ")); - bool needComma = false; - CFIndex used_attr = 0; - SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) { - ++used_attr; - SecDbAppendElementEquals(sql, attr->name, &needComma); - } - - bool needWhere = true; - SecDbForEachAttr(old_item->class, attr) { - if (use_attr_in_where(attr)) { - SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); - } - } - - return sql; -} - -static bool SecDbItemUpdateBind(SecDbItemRef old_item, SecDbItemRef new_item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) { - bool ok = true; - int param = 0; - SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) { - CFTypeRef value = SecDbItemCopyValueForDb(new_item, attr, error); - ok &= value && SecDbBindObject(stmt, ++param, value, error); - CFReleaseSafe(value); - if (!ok) - break; - } - SecDbForEachAttr(old_item->class, attr) { - if (use_attr_in_where(attr)) { - CFTypeRef value = SecDbItemCopyValueForDb(old_item, attr, error); - ok &= value && SecDbBindObject(stmt, ++param, value, error); - CFReleaseSafe(value); - if (!ok) - break; - } - } - return ok; -} - -// Primary keys are the same -- do an update -bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { - CFStringRef sql = SecDbItemCopyUpdateSQL(old_item, new_item, use_attr_in_where); - __block bool ok = sql; - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - ok = SecDbItemUpdateBind(old_item, new_item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL); - }); - CFRelease(sql); - } - if (ok) { - if (SecDbItemIsEngineInternalState(old_item)) { - secdebug ("item", "replaced %@ in %@", old_item, dbconn); - secdebug ("item", " with %@ in %@", new_item, dbconn); - } else { - secnotice("item", "replaced %@ in %@", old_item, dbconn); - secnotice("item", " with %@ in %@", new_item, dbconn); - } - SecDbItemRecordUpdate(dbconn, old_item, new_item); - } - return ok; -} - -static CFStringRef SecDbItemCopyDeleteSQL(SecDbItemRef item, bool(^use_attr_in_where)(const SecDbAttr *attr)) { - CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0); - CFStringAppend(sql, CFSTR("DELETE FROM ")); - CFStringAppend(sql, item->class->name); - bool needWhere = true; - SecDbForEachAttr(item->class, attr) { - if (use_attr_in_where(attr)) { - SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); - } - } - - return sql; -} - -static bool SecDbItemDeleteBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) { - bool ok = true; - int param = 0; - SecDbForEachAttr(item->class, attr) { - if (use_attr_in_where(attr)) { - CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error); - ok &= value && SecDbBindObject(stmt, ++param, value, error); - CFReleaseSafe(value); - if (!ok) - break; - } - } - return ok; -} - -static bool SecDbItemDoDeleteOnly(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { - CFStringRef sql = SecDbItemCopyDeleteSQL(item, use_attr_in_where); - __block bool ok = sql; - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - ok = SecDbItemDeleteBind(item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL); - }); - CFRelease(sql); - } - return ok; -} - -bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { - return SecDbItemDoDeleteOnly(item, dbconn, error, ^bool(const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); -} - -static bool SecDbItemDoDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { - bool ok = SecDbItemDoDeleteOnly(item, dbconn, error, use_attr_in_where); - if (ok) { - secnotice("item", "deleted %@ from %@", item, dbconn); - SecDbItemRecordUpdate(dbconn, item, NULL); - } - return ok; -} - -#if 0 -static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { - bool ok = true; - // TODO: Treat non decryptable items like tombstones here too and delete them - SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error); - ok = tombstone; - if (tombstone) { - ok = SecDbItemClearRowId(tombstone, error); - if (ok) { - ok = SecDbItemDoDelete(tombstone, dbconn, error, ^bool (const SecDbAttr *attr) { - return SecDbIsTombstoneDbSelectAttr(attr); - }); - } - CFRelease(tombstone); - } - return ok; -} -#endif - -static bool -isCKKSEnabled(void) -{ -#if OCTAGON - return SecCKKSIsEnabled(); -#else - return false; -#endif -} - -// Replace old_item with new_item. If primary keys are the same this does an update otherwise it does a delete + add -bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error) { - __block bool ok = true; - __block CFErrorRef localError = NULL; - - CFDataRef old_pk = SecDbItemGetPrimaryKey(old_item, error); - CFDataRef new_pk = SecDbItemGetPrimaryKey(new_item, error); - - ok = old_pk && new_pk; - - bool pk_equal = ok && CFEqual(old_pk, new_pk); - if (pk_equal) { - ok = SecDbItemMakeYounger(new_item, old_item, error); - } else if(!CFEqualSafe(makeTombstone, kCFBooleanFalse) && isCKKSEnabled()) { - // The primary keys aren't equal, and we're going to make a tombstone. - // Help CKKS out: the tombstone should have the existing item's UUID, and the newly updated item should have a new UUID. - - s3dl_item_make_new_uuid(new_item, uuid_from_primary_key, error); - } - ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - - if (localError) { - if(CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { - /* Update failed because we changed the PrimaryKey and there was a dup. - Find the dup and see if it is a tombstone or corrupted item. */ - SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(new_item, error); - ok = query; - if (query) { - ok &= SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { - return attr->flags & kSecDbPrimaryKeyFlag; - }, NULL, NULL, ^(SecDbItemRef duplicate_item, bool *stop) { - bool is_corrupt = false; - bool is_tomb = false; - ok = SecDbItemIsCorrupt(duplicate_item, &is_corrupt, error); - if (ok && !is_corrupt) { - if ((is_tomb = SecDbItemIsTombstone(duplicate_item))) - ok = SecDbItemMakeYounger(new_item, duplicate_item, error); - } - if (ok && (is_corrupt || is_tomb)) { - ok = SecDbItemDoDelete(old_item, dbconn, error, ^bool (const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - ok = ok && SecDbItemDoUpdate(duplicate_item, new_item, dbconn, error, ^bool (const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - CFReleaseNull(localError); - } - }); - ok &= query_destroy(query, error); - } - } - - if (localError) { - ok = false; - if (error && *error == NULL) { - *error = localError; - localError = NULL; - } - CFReleaseSafe(localError); - } - } - - if (ok && !pk_equal && !CFEqualSafe(makeTombstone, kCFBooleanFalse)) { - /* The primary key of new_item is different than that of old_item, we - have been asked to make a tombstone so leave one for the old_item. */ - SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, makeTombstone, error); - ok = tombstone; - if (tombstone) { - ok = (SecDbItemClearRowId(tombstone, error) && - SecDbItemDoInsert(tombstone, dbconn, error)); - CFRelease(tombstone); - } - } - - return ok; -} - -// Replace the object with a tombstone -bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error) { - bool ok = false; - if (!CFEqualSafe(makeTombstone, kCFBooleanFalse)) { - SecDbItemRef tombstone = SecDbItemCopyTombstone(item, makeTombstone, error); - if (tombstone) { - ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - CFRelease(tombstone); - } - } else { - ok = SecDbItemDoDelete(item, dbconn, error, ^bool(const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - }); - } - return ok; -} - -CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query, - bool (^return_attr)(const SecDbAttr *attr), - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)) { - CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); - CFStringAppend(sql, CFSTR("SELECT ")); - // What are we selecting? - bool needComma = false; - SecDbForEachAttr(query->q_class, attr) { - if (return_attr(attr)) - SecDbAppendElement(sql, attr->name, &needComma); - } - - // From which table? - CFStringAppend(sql, CFSTR(" FROM ")); - CFStringAppend(sql, query->q_class->name); - - // And which elements do we want to select - bool needWhere = true; - SecDbForEachAttr(query->q_class, attr) { - if (use_attr_in_where(attr)) { - CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name); - if (isArray(value)) { - CFArrayRef array = (CFArrayRef)value; - CFIndex length = CFArrayGetCount(array); - if (length > 0) { - CFTypeRef head = CFArrayGetValueAtIndex(array, 0); - if (CFEqualSafe(head, kCFNull)) { - SecDbAppendWhereOrAndNotIn(sql, attr->name, &needWhere, length - 1); - } else { - SecDbAppendWhereOrAndIn(sql, attr->name, &needWhere, length); - } - } - } else { - SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); - } - } - } - // Append SQL for access groups and limits. - if (add_where_sql) - add_where_sql(sql, &needWhere); - - return sql; -} - -static bool SecDbItemSelectBindValue(SecDbQueryRef query, sqlite3_stmt *stmt, int param, const SecDbAttr *attr, CFTypeRef inValue, CFErrorRef *error) { - bool ok = true; - CFTypeRef value = NULL; - if (attr->kind == kSecDbRowIdAttr) { - // TODO: Ignores inValue and uses rowid directly instead HACK should go - value = CFNumberCreate(NULL, kCFNumberSInt64Type, &query->q_row_id); - } else { - value = SecDbAttrCopyValueForDb(attr, inValue, error); - } - ok = ok && value != NULL && SecDbBindObject(stmt, ++param, value, error); - CFReleaseSafe(value); - return ok; -} - -bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error, - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col)) { - __block bool ok = true; - __block int param = 0; - SecDbForEachAttr(query->q_class, attr) { - if (use_attr_in_where(attr)) { - CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name); - if (isArray(value)) { - CFArrayRef array = (CFArrayRef)value; - CFRange range = {.location = 0, .length = CFArrayGetCount(array) }; - if (range.length > 0) { - CFTypeRef head = CFArrayGetValueAtIndex(array, 0); - if (CFEqualSafe(head, kCFNull)) { - range.length--; - range.location++; - } - } - CFArrayApplyFunction(array, range, apply_block_1, (void (^)(const void *value)) ^(const void *arrayValue) { - ok = SecDbItemSelectBindValue(query, stmt, param++, attr, arrayValue, error); - }); - } else { - ok = SecDbItemSelectBindValue(query, stmt, param++, attr, value, error); - } - - if (!ok) - break; - } - } - // TODO: Bind arguments for access groups and limits. - if (bind_added_where) - bind_added_where(stmt, ++param); - - return ok; -} - -bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, - bool (^return_attr)(const SecDbAttr *attr), - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col), - void (^handle_row)(SecDbItemRef item, bool *stop)) { - __block bool ok = true; - if (return_attr == NULL) { - return_attr = ^bool (const SecDbAttr * attr) { - return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr || attr->kind == kSecDbSHA1Attr; - }; - } - if (use_attr_in_where == NULL) { - use_attr_in_where = ^bool (const SecDbAttr* attr) { return false; }; - } - - CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql); - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) && - SecDbStep(dbconn, stmt, error, ^(bool *stop) { - SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr); - if (item) { - CFRetainAssign(item->credHandle, query->q_use_cred_handle); - handle_row(item, stop); - CFRelease(item); - } else { - //*stop = true; - //ok = false; - } - })); - }); - CFRelease(sql); - } else { - ok = false; - } - return ok; -} - diff --git a/OSX/sec/securityd/SecDbItem.h b/OSX/sec/securityd/SecDbItem.h deleted file mode 100644 index 8b38586b..00000000 --- a/OSX/sec/securityd/SecDbItem.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecDbItem - The functions provided in SecDbItem provide an interface to - database items (certificates, keys, identities, and passwords). - */ - -#ifndef _SECURITYD_SECDBITEM_H_ -#define _SECURITYD_SECDBITEM_H_ - -#include -#include -#include // For CCSHA1_OUTPUT_SIZE -#include -#include "utilities/SecCFError.h" -#include "utilities/SecCFWrappers.h" -#include "utilities/SecDb.h" -#include "securityd/SecKeybagSupport.h" -#include -#include - -// MARK SecDbAttrKind, SecDbFlag - -typedef enum { - kSecDbBlobAttr, // CFString or CFData, preserves caller provided type. - kSecDbDataAttr, - kSecDbStringAttr, - kSecDbNumberAttr, - kSecDbDateAttr, - kSecDbCreationDateAttr, - kSecDbModificationDateAttr, - kSecDbSHA1Attr, - kSecDbRowIdAttr, - kSecDbEncryptedDataAttr, - kSecDbPrimaryKeyAttr, - kSecDbSyncAttr, - kSecDbTombAttr, - kSecDbUTombAttr, - kSecDbAccessAttr, - kSecDbAccessControlAttr, - kSecDbUUIDAttr, -} SecDbAttrKind; - -enum { - kSecDbPrimaryKeyFlag = (1 << 0), // attr is part of primary key - kSecDbInFlag = (1 << 1), // attr exists in db - kSecDbIndexFlag = (1 << 2), // attr should have a db index - kSecDbSHA1ValueInFlag = (1 << 3), // col in db is sha1 of attr value - kSecDbReturnAttrFlag = (1 << 4), - kSecDbReturnDataFlag = (1 << 5), - kSecDbReturnRefFlag = (1 << 6), - kSecDbInCryptoDataFlag = (1 << 7), - kSecDbInHashFlag = (1 << 8), - kSecDbInBackupFlag = (1 << 9), - kSecDbDefault0Flag = (1 << 10), // default attr value is 0 - kSecDbDefaultEmptyFlag = (1 << 11), // default attr value is "" - kSecDbNotNullFlag = (1 << 12), // attr value can't be null - kSecDbInAuthenticatedDataFlag = (1 << 13), // attr is in authenticated data - kSecDbSyncPrimaryKeyV0 = (1 << 14), - kSecDbSyncPrimaryKeyV2 = (1 << 15), - kSecDbSyncFlag = (1 << 16), -}; - -#define SecVersionDbFlag(v) ((v & 0xFF) << 8) - -#define SecDbFlagGetVersion(flags) ((flags >> 8) & 0xFF) - -#define SECDB_ATTR(var, name, kind, flags, copyValue, setValue) const SecDbAttr var = { CFSTR(name), kSecDb ## kind ## Attr, flags, copyValue, setValue } - -typedef struct SecDbItem *SecDbItemRef; -typedef struct SecDbAttr SecDbAttr; - -typedef CFTypeRef (*SecDbItemCopyAttrValue)(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); -typedef bool (*SecDbItemSetAttrValue)(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error); - -struct SecDbAttr { - CFStringRef name; - SecDbAttrKind kind; - CFOptionFlags flags; - SecDbItemCopyAttrValue copyValue; - SecDbItemSetAttrValue setValue; -}; - -typedef struct SecDbClass { - CFStringRef name; - bool itemclass; // true if keychain items are stored in this class, false otherwise - const SecDbAttr *attrs[]; -} SecDbClass; - -typedef struct SecDbSchema { - int majorVersion; - int minorVersion; - const SecDbClass *classes[]; -} SecDbSchema; - - -#define SecDbForEachAttr(class, attr) for (const SecDbAttr * const* _pattr = (class)->attrs, *attr = *_pattr; attr; attr = *(++_pattr)) - -#define SecDbForEachAttrWithMask(class, attr, flag_mask) SecDbForEachAttr(class, attr) if ((attr->flags & (flag_mask)) == (flag_mask)) - -CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error); - - -// MARK: SecDbItem - -enum SecDbItemState { - kSecDbItemDirty, // We have no edata (or if we do it's invalid), attributes are the truth - kSecDbItemEncrypted, // Attributes haven't been decrypted yet from edata - kSecDbItemClean, // Attributes and _edata are in sync. - kSecDbItemDecrypting, // Temporary state while we are decrypting so set knows not to blow away the edata. - kSecDbItemEncrypting, // Temporary state while we are encrypting so set knows to move to clean. - kSecDbItemAlwaysEncrypted, // As kSecDbItemEncrypted, but decryption is never attempted - kSecDbItemSecretEncrypted, // Metadata is clean, but the secret data remains encrypted -}; - -struct SecDbItem { - CFRuntimeBase _base; - const SecDbClass *class; - keyclass_t keyclass; - keybag_handle_t keybag; - enum SecDbItemState _edataState; - CFMutableDictionaryRef attributes; - CFDataRef credHandle; - CFTypeRef cryptoOp; - CFArrayRef callerAccessGroups; -}; - -// TODO: Make this a callback to client -bool SecDbItemDecrypt(SecDbItemRef item, bool decryptSecretData, CFDataRef edata, CFErrorRef *error); - -CFTypeID SecDbItemGetTypeID(void); - -static inline size_t SecDbClassAttrCount(const SecDbClass *dbClass) { - size_t n_attrs = 0; - SecDbForEachAttr(dbClass, attr) { n_attrs++; } - return n_attrs; -} - -const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error); - -SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error); - -const SecDbClass *SecDbItemGetClass(SecDbItemRef item); -keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item); -bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error); -void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle); -void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups); - -CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name); -CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error); -CFTypeRef SecDbItemGetValueKind(SecDbItemRef item, SecDbAttrKind desc, CFErrorRef *error); - -bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error); -bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error); -bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error); - -sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error); -bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error); -bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error); - -bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item); -bool SecDbItemIsSyncable(SecDbItemRef item); - -bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error); - -bool SecDbItemIsTombstone(SecDbItemRef item); - -CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error); - -CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error); -CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error); - -CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error); - -SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)); - -SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class, - CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error); - -SecDbItemRef SecDbItemCreateWithPrimaryKey(CFAllocatorRef allocator, const SecDbClass *class, CFDataRef primary_key); - -#if 0 -SecDbItemRef SecDbItemCreateWithRowId(CFAllocatorRef allocator, const SecDbClass *class, sqlite_int64 row_id, keybag_handle_t keybag, CFErrorRef *error); -#endif - -bool SecDbItemEnsureDecrypted(SecDbItemRef item, bool decryptSecretData, CFErrorRef *error); - -SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error); - -bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)); - -// SecDbItemInsertOrReplace returns an error even when it succeeds; use this to determine if it's spurious -bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error); - -bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error); - -bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error); - -bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error); - -// Low level update, just do the update -bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)); - -// High level update, will replace tombstones and create them if needed. -bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error); - - -// MARK: - -// MARK: SQL Construction helpers -- These should become private in the future - -void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma); -void SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere); -void SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere); -void SecDbAppendWhereOrAndNotEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere); -void SecDbAppendWhereOrAndIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count); -void SecDbAppendWhereOrAndNotIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count); - -// MARK: type converters. -// TODO: these should be static and private to SecDbItem, or part of the schema - -CFStringRef copyString(CFTypeRef obj); -CFDataRef copyData(CFTypeRef obj); -CFTypeRef copyBlob(CFTypeRef obj); -CFDataRef copySHA1(CFTypeRef obj); -CFTypeRef copyNumber(CFTypeRef obj); -CFDateRef copyDate(CFTypeRef obj); -CFTypeRef copyUUID(CFTypeRef obj); - -// MARK: cFErrorPropagate which handles errSecAuthNeeded -static inline -bool SecErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) { - if (possibleError && error && *error && CFErrorGetCode(*error) == errSecAuthNeeded) - CFReleaseNull(*error); - return CFErrorPropagate(possibleError, error); -} - -// TODO: Hack -bool SecDbItemInV2(SecDbItemRef item); -bool SecDbItemInV2AlsoInV0(SecDbItemRef item); - -// For debug output filtering -bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject); - -__END_DECLS - -#endif /* _SECURITYD_SECDBITEM_H_ */ diff --git a/OSX/sec/securityd/SecDbKeychainItem.h b/OSX/sec/securityd/SecDbKeychainItem.h deleted file mode 100644 index 1cb4bfca..00000000 --- a/OSX/sec/securityd/SecDbKeychainItem.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecDbKeychainItem.h - The thing that does the stuff with the gibli. - */ - -#ifndef _SECURITYD_SECKEYCHAINITEM_H_ -#define _SECURITYD_SECKEYCHAINITEM_H_ - -#include -#include -#include - -__BEGIN_DECLS - -bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error); -bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error); -bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error); // used for backup -bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context, - CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups, - CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error); -bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, - CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error); -SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error); -bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error); -bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error); - -CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); -CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error); -CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); -CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); -CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); - -SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error); -bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error); - -void SecDbResetMetadataKeys(void); - -__END_DECLS - -#endif /* _SECURITYD_SECKEYCHAINITEM_H_ */ diff --git a/OSX/sec/securityd/SecDbKeychainItem.m b/OSX/sec/securityd/SecDbKeychainItem.m deleted file mode 100644 index 54c5cf04..00000000 --- a/OSX/sec/securityd/SecDbKeychainItem.m +++ /dev/null @@ -1,1542 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecDbKeychainItem.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include - -#import "SecInternalReleasePriv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#import "SecDbKeychainItemV7.h" -#import "SecDbKeychainMetadataKeyStore.h" -#import "sec_action.h" - -#if USE_KEYSTORE -#include -#include -#include -#include -#include - -#endif /* USE_KEYSTORE */ - -#include "OSX/utilities/SecAKSWrappers.h" - -pthread_key_t CURRENT_CONNECTION_KEY; - -// From SecItemServer, should be a acl-check block -bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); - -static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error); -static CFTypeRef kc_encode_keyclass(keyclass_t keyclass); -static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control); -static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end); -static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error); -static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error); -#if USE_KEYSTORE -static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version, - CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error); -static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes); -static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error); -#endif - -static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFOptionFlags mutability, CFPropertyListRef* cf, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end)); -static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end)); -static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end)); -static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end)); -static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFSetRef* set, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end)); - -const uint32_t kUseDefaultIVMask = 1<<31; -const int16_t kIVSizeAESGCM = 12; - -// echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i -static const uint8_t gcmIV[kIVSizeAESGCM] = { - 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24 -}; - -/* Given plainText create and return a CFDataRef containing: - BULK_KEY = RandomKey() - version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) || - AES(BULK_KEY, NULL_IV, plainText || padding) - */ -bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) { - CFMutableDataRef blob = NULL; - CFDataRef ac_data = NULL; - bool ok = true; - //check(keybag >= 0); - - /* Precalculate output blob length. */ - const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */ - const uint32_t maxKeyWrapOverHead = 8 + 32; - uint8_t bulkKey[bulkKeySize]; - CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0); - CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead); - uint32_t key_wrapped_size; - size_t ivLen = 0; - const uint8_t *iv = NULL; - const uint8_t *aad = NULL; // Additional Authenticated Data - ptrdiff_t aadLen = 0; - -#if USE_KEYSTORE - CFDataRef auth_data = NULL; -#endif - - /* If access_control specifies only protection and no ACL, use legacy blob format version 3, - which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */ - bool hasACLConstraints = SecAccessControlGetConstraints(access_control); - const uint32_t version = (hasACLConstraints ? 6 : 3); - CFDataRef plainText = NULL; - if (version < 4) { - CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); - if (authenticated_attributes) { - CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { - CFDictionaryAddValue(attributes_dict, key, value); - }); - } - - if (attributes_dict) { - // Drop the accc attribute for non v6 items during encode. - CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl); - plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error); - CFRelease(attributes_dict); - } - } else { -#if USE_KEYSTORE - if (attributes) { - plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes, error); - } -#else - CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); - if (authenticated_attributes) { - CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { - CFDictionaryAddValue(attributes_dict, key, value); - }); - } - - if (attributes_dict) { - plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error); - CFRelease(attributes_dict); - } -#endif - } - - if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID() - || access_control == 0) { - ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text")); - goto out; - } - - size_t ptLen = CFDataGetLength(plainText); - size_t ctLen = ptLen; - size_t tagLen = 16; - keyclass_t actual_class = 0; - - if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) { - ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed")); - goto out; - } - - /* Extract keyclass from access control. */ - keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); - if (!keyclass) - goto out; - -#if USE_KEYSTORE - if (version >= 4) { - auth_data = kc_create_auth_data(access_control, authenticated_attributes); - require_quiet(ok = ks_encrypt_acl(keybag, keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, auth_data, acm_context, access_control, error), out); - } else -#endif - { - /* Encrypt bulkKey. */ - require_quiet(ok = ks_crypt(kAKSKeyOpEncrypt, keybag, - keyclass, bulkKeySize, bulkKey, - &actual_class, bulkKeyWrapped, - error), out); - } - - key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped); - UInt8 *cursor; - size_t blobLen = sizeof(version); - uint32_t prot_length = 0; - - if (!hasACLConstraints) { - blobLen += sizeof(actual_class); - } else { - require_quiet(ac_data = kc_copy_protection_data(access_control), out); - prot_length = (uint32_t)CFDataGetLength(ac_data); - blobLen += sizeof(prot_length) + prot_length; - } - - blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen; - require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out); - CFDataSetLength(blob, blobLen); - cursor = CFDataGetMutableBytePtr(blob); - - *((uint32_t *)cursor) = useDefaultIV ? (version | kUseDefaultIVMask) : version; - cursor += sizeof(version); - - //secerror("class: %d actual class: %d", keyclass, actual_class); - if (!hasACLConstraints) { - *((keyclass_t *)cursor) = actual_class; - cursor += sizeof(keyclass); - } else { - *((uint32_t *)cursor) = prot_length; - cursor += sizeof(prot_length); - - CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor); - cursor += prot_length; - } - - *((uint32_t *)cursor) = key_wrapped_size; - cursor += sizeof(key_wrapped_size); - - if (useDefaultIV) { - iv = gcmIV; - ivLen = kIVSizeAESGCM; - // AAD is (version || ac_data || key_wrapped_size) - aad = CFDataGetMutableBytePtr(blob); - aadLen = cursor - aad; - } - - memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size); - cursor += key_wrapped_size; - - /* Encrypt the plainText with the bulkKey. */ - CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128, - bulkKey, bulkKeySize, - iv, ivLen, /* iv */ - aad, aadLen, /* auth data */ - CFDataGetBytePtr(plainText), ptLen, - cursor, - cursor + ctLen, &tagLen); - if (ccerr) { - ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr); - goto out; - } - if (tagLen != 16) { - ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); - goto out; - } - - out: - memset(bulkKey, 0, sizeof(bulkKey)); - CFReleaseSafe(ac_data); - CFReleaseSafe(bulkKeyWrapped); - CFReleaseSafe(plainText); - if (!ok) { - CFReleaseSafe(blob); - } else { - *pBlob = blob; - } - -#if USE_KEYSTORE - CFReleaseSafe(auth_data); -#endif - return ok; -} - -static void -ks_warn_non_device_keybag(void) -{ - static dispatch_once_t once; - static sec_action_t action; - - dispatch_once(&once, ^{ - action = sec_action_create("non-device keybag", 2); - sec_action_set_handler(action, ^{ - secwarning("ks_encrypt_data: called with non-device keybag - call should be rerouted to ks_encrypt_data_legacy"); - }); - }); - sec_action_perform(action); -} - -bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) { - return ks_encrypt_data_with_backupuuid(keybag, access_control, acm_context, secretData, attributes, authenticated_attributes, pBlob, NULL, useDefaultIV, error); -} - -bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, - CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error) { - if (keybag != KEYBAG_DEVICE) { - ks_warn_non_device_keybag(); - - CFMutableDictionaryRef allAttributes = CFDictionaryCreateMutableCopy(NULL, CFDictionaryGetCount(secretData) + CFDictionaryGetCount(attributes), attributes); - CFDictionaryForEach(secretData, ^(const void *key, const void *value) { - CFDictionaryAddValue(allAttributes, key, value); - }); - bool result = ks_encrypt_data_legacy(keybag, access_control, acm_context, allAttributes, authenticated_attributes, pBlob, useDefaultIV, error); - CFReleaseNull(allAttributes); - return result; - } - - keyclass_t key_class = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); - if (!key_class) { - return false; - } - - if (SecAccessControlGetConstraints(access_control)) { - NSMutableDictionary* allAttributes = [(__bridge NSDictionary*)attributes mutableCopy]; - [allAttributes addEntriesFromDictionary:(__bridge NSDictionary*)secretData]; - return ks_encrypt_data_legacy(keybag, access_control, acm_context, (__bridge CFDictionaryRef)allAttributes, authenticated_attributes, pBlob, useDefaultIV, error); - } - - bool success = false; - @autoreleasepool { - NSMutableDictionary* metadataAttributes = attributes ? [(__bridge NSDictionary*)attributes mutableCopy] : [NSMutableDictionary dictionary]; - [metadataAttributes addEntriesFromDictionary:(__bridge NSDictionary*)authenticated_attributes]; - metadataAttributes[@"SecAccessControl"] = (__bridge_transfer NSData*)SecAccessControlCopyData(access_control); - - NSString* tamperCheck = [[NSUUID UUID] UUIDString]; // can use the item persistent reference when that starts getting filled in - SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:(__bridge NSDictionary*)secretData metadataAttributes:metadataAttributes tamperCheck:tamperCheck keyclass:key_class]; - - NSError* localError = nil; - NSData* encryptedBlob = [item encryptedBlobWithKeybag:keybag accessControl:access_control acmContext:(__bridge NSData*)acm_context error:&localError]; - if (encryptedBlob) { - NSMutableData* encryptedBlobWithVersion = [NSMutableData dataWithLength:encryptedBlob.length + sizeof(uint32_t)]; - *((uint32_t*)encryptedBlobWithVersion.mutableBytes) = (uint32_t)7; - memcpy((uint32_t*)encryptedBlobWithVersion.mutableBytes + 1, encryptedBlob.bytes, encryptedBlob.length); - *pBlob = (__bridge_retained CFDataRef)encryptedBlobWithVersion; - if (bkUUID && item.backupUUID) { // TODO: Failing this should turn into at least a stern warning at some point - *bkUUID = (__bridge_retained CFDataRef)[item.backupUUID copy]; - } - success = true; - } - else { - if (error) { - *error = (__bridge_retained CFErrorRef)localError; - } - } - } - - return success; -} - -/* Given cipherText containing: - version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) || - AES(BULK_KEY, NULL_IV, plainText || padding) - return the plainText. */ -bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context, - CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups, - CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error) { - const uint32_t v0KeyWrapOverHead = 8; - CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */ - CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */ - bool ok = true; - SecAccessControlRef access_control = NULL; - - if (attributes_p) - *attributes_p = NULL; - if (version_p) - *version_p = 0; - - CFMutableDataRef plainText = NULL; - CFMutableDictionaryRef attributes = NULL; - uint32_t version = 0; - size_t ivLen = 0; - const uint8_t *iv = NULL; - const uint8_t *aad = NULL; // Additional Authenticated Data - ptrdiff_t aadLen = 0; - -#if USE_KEYSTORE - CFMutableDictionaryRef authenticated_attributes = NULL; - CFDataRef caller_access_groups_data = NULL; - CFDataRef ed_data = NULL; - aks_ref_key_t ref_key = NULL; -#if TARGET_OS_IPHONE - check(keybag >= 0); -#else - check((keybag >= 0) || (keybag == session_keybag_handle)); -#endif -#endif - - if (!blob) { - ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob")); - goto out; - } - - size_t blobLen = CFDataGetLength(blob); - const uint8_t *cursor = CFDataGetBytePtr(blob); - keyclass_t keyclass; - - if (blobLen < sizeof(version)) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (length)")); - goto out; - } - - version = *((uint32_t *)cursor); - if (version & kUseDefaultIVMask) { - version &= ~kUseDefaultIVMask; - iv = gcmIV; - ivLen = kIVSizeAESGCM; - } - - cursor += sizeof(version); - blobLen -= sizeof(version); - - bool hasProtectionData = (version >= 4 && version < 7); - - if (version >= 7) { - @autoreleasepool { - NSError* localError = nil; - NSData* encryptedBlob = [NSData dataWithBytes:cursor length:blobLen]; - SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithData:encryptedBlob decryptionKeybag:keybag error:&localError]; - if (outKeyclass) { - *outKeyclass = item.keyclass; - } - - NSMutableDictionary* itemAttributes = [[item metadataAttributesWithError:&localError] mutableCopy]; - if (itemAttributes && !localError) { - NSData* accessControlData = itemAttributes[@"SecAccessControl"]; - access_control = SecAccessControlCreateFromData(NULL, (__bridge CFDataRef)accessControlData, error); - [itemAttributes removeObjectForKey:@"SecAccessControl"]; - - if (decryptSecretData) { - NSDictionary* secretAttributes = [item secretAttributesWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError]; - if (secretAttributes) { - [itemAttributes addEntriesFromDictionary:secretAttributes]; - } - else { - ok = false; - } - } - - if (ok) { - if (CFEqual(kAKSKeyOpDelete, cryptoOp)) { - ok = [item deleteWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError]; - } - - attributes = (__bridge_retained CFMutableDictionaryRef)itemAttributes; - } - } - else { - ok = false; - } - - if (!ok && error) { - *error = (__bridge_retained CFErrorRef)localError; - } - } - goto out; - } - - if (hasProtectionData) { - /* Deserialize SecAccessControl object from the blob. */ - uint32_t prot_length; - - /* - * Parse proto length - */ - - if (blobLen < sizeof(prot_length)) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot_length)")); - goto out; - } - - prot_length = *((uint32_t *)cursor); - cursor += sizeof(prot_length); - blobLen -= sizeof(prot_length); - - /* - * Parse proto itself - */ - - if (blobLen < prot_length) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot)")); - goto out; - } - - CFTypeRef protection = kc_copy_protection_from(cursor, cursor + prot_length); - if (!protection) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); - goto out; - } else { - access_control = SecAccessControlCreate(NULL, NULL); - require_quiet(access_control, out); - ok = SecAccessControlSetProtection(access_control, protection, NULL); - CFRelease(protection); - if (!ok) { - SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); - goto out; - } - } - - cursor += prot_length; - blobLen -= prot_length; - - /* - * Get numeric value of keyclass from the access_control. - */ - keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); - if (!keyclass) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); - goto out; - } - } else { - if (blobLen < sizeof(keyclass)) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (keyclass)")); - goto out; - } - - keyclass = *((keyclass_t *)cursor); - -#if USE_KEYSTORE - CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation -#else - CFTypeRef protection = kc_encode_keyclass(keyclass); -#endif - require_action_quiet(protection, out, ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected"))); - require_action_quiet(access_control = SecAccessControlCreate(kCFAllocatorDefault, error), out, - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlCreate failed"))); - require_action_quiet(SecAccessControlSetProtection(access_control, protection, error), out, - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed"))); - - cursor += sizeof(keyclass); - blobLen -= sizeof(keyclass); - } - - size_t tagLen = 0; - uint32_t wrapped_key_size = 0; - - switch (version) { - case 0: - wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead; - break; - case 2: - case 3: - /* DROPTHROUGH */ - /* v2 and v3 have the same crypto, just different dictionary encodings. */ - /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */ - case 4: - case 5: - case 6: - tagLen = 16; - /* DROPTHROUGH */ - case 1: - if (blobLen < sizeof(wrapped_key_size)) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key_size)")); - goto out; - } - wrapped_key_size = *((uint32_t *)cursor); - - cursor += sizeof(wrapped_key_size); - blobLen -= sizeof(wrapped_key_size); - - break; - default: - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version); - goto out; - } - - if (blobLen < tagLen + wrapped_key_size) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key/taglen)")); - goto out; - } - - size_t ctLen = blobLen - tagLen - wrapped_key_size; - - /* - * Pre-version 2 have some additial constraints since it use AES in CBC mode - */ - if (version < 2) { - if (ctLen < kCCBlockSizeAES128) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (CBC check)")); - goto out; - } - if ((ctLen & 0xF) != 0) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid length on CBC data")); - goto out; - } - } - -#if USE_KEYSTORE - if (hasProtectionData) { - if (caller_access_groups) { - caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error); - require_quiet(ok = (caller_access_groups_data != NULL), out); - } - - require_quiet(ok = kc_attribs_key_encrypted_data_from_blob(keybag, db_class, cursor, wrapped_key_size, access_control, version, - &authenticated_attributes, &ref_key, &ed_data, error), out); - if (CFEqual(cryptoOp, kAKSKeyOpDecrypt)) { - require_quiet(ok = ks_decrypt_acl(ref_key, ed_data, bulkKey, acm_context, caller_access_groups_data, access_control, error), out); - } else if (CFEqual(cryptoOp, kAKSKeyOpDelete)) { - require_quiet(ok = ks_delete_acl(ref_key, ed_data, acm_context, caller_access_groups_data, access_control, error), out); - attributes = CFRetainSafe(authenticated_attributes); - goto out; - } else { - ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: invalid operation")); - goto out; - } - } else -#endif - { - /* Now unwrap the bulk key using a key in the keybag. */ - require_quiet(ok = ks_crypt(cryptoOp, keybag, - keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out); - } - - if (iv) { - // AAD is (version || ... [|| key_wrapped_size ]) - aad = CFDataGetBytePtr(blob); - aadLen = cursor - aad; - } - - cursor += wrapped_key_size; - - plainText = CFDataCreateMutable(NULL, ctLen); - if (!plainText) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text")); - goto out; - } - CFDataSetLength(plainText, ctLen); - - /* Decrypt the cipherText with the bulkKey. */ - CCCryptorStatus ccerr; - if (tagLen) { - uint8_t tag[tagLen]; - ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128, - CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), - iv, ivLen, /* iv */ - aad, aadLen, /* auth data */ - cursor, ctLen, - CFDataGetMutableBytePtr(plainText), - tag, &tagLen); - if (ccerr) { - /* TODO: Should this be errSecDecode once AppleKeyStore correctly - identifies uuid unwrap failures? */ - /* errSecInteractionNotAllowed; */ - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr); - goto out; - } - if (tagLen != 16) { - ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); - goto out; - } - cursor += ctLen; - if (timingsafe_bcmp(tag, cursor, tagLen)) { - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob")); - goto out; - } - } else { - size_t ptLen; - ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, - CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen, - CFDataGetMutableBytePtr(plainText), ctLen, &ptLen); - if (ccerr) { - /* TODO: Should this be errSecDecode once AppleKeyStore correctly - identifies uuid unwrap failures? */ - /* errSecInteractionNotAllowed; */ - ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr); - goto out; - } - CFDataSetLength(plainText, ptLen); - } - - if (version < 2) { - attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText); - } else if (version < 3) { - attributes = s3dl_item_v2_decode(plainText, error); - } else { - attributes = s3dl_item_v3_decode(plainText, error); - } - - require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@", version, error ? *error : NULL); }); - -#if USE_KEYSTORE - if (version >= 4 && authenticated_attributes != NULL) { - CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { - CFDictionaryAddValue(attributes, key, value); - }); - } -#endif - -out: - memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey)); - CFReleaseNull(bulkKey); - CFReleaseNull(plainText); - - // Always copy access control data (if present), because if we fail it may indicate why. - if (paccess_control) - *paccess_control = access_control; - else - CFReleaseNull(access_control); - - if (ok) { - if (attributes_p) - CFRetainAssign(*attributes_p, attributes); - if (version_p) - *version_p = version; - } - CFReleaseNull(attributes); -#if USE_KEYSTORE - CFReleaseNull(authenticated_attributes); - CFReleaseNull(caller_access_groups_data); - CFReleaseNull(ed_data); - if (ref_key) aks_ref_key_free(&ref_key); -#endif - return ok; -} - -static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) { - if (!isString(value)) { - SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value); - } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) { - return key_class_ak; - } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) { - return key_class_ck; - } else if (CFEqual(value, kSecAttrAccessibleAlwaysPrivate)) { - return key_class_dk; - } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) { - return key_class_aku; - } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) { - return key_class_cku; - } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) { - return key_class_dku; - } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { - return key_class_akpu; - } else { - SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value); - } - return 0; -} - -static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) { - switch (keyclass) { - case key_class_ak: - return kSecAttrAccessibleWhenUnlocked; - case key_class_ck: - return kSecAttrAccessibleAfterFirstUnlock; - case key_class_dk: - return kSecAttrAccessibleAlwaysPrivate; - case key_class_aku: - return kSecAttrAccessibleWhenUnlockedThisDeviceOnly; - case key_class_cku: - return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; - case key_class_dku: - return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate; - case key_class_akpu: - return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; - default: - return 0; - } -} - -#if USE_KEYSTORE -static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version, - CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error) -{ - CFMutableDictionaryRef acl = NULL; - CFDictionaryRef blob_dict = NULL; - aks_ref_key_t tmp_ref_key = NULL; - CFDataRef key_data = NULL; - CFDataRef ed = NULL; - bool ok = false; - - der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len); - require_action_quiet(blob_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'"))); - - if (!ks_separate_data_and_key(blob_dict, &ed, &key_data)) { - ed = CFDataCreate(kCFAllocatorDefault, blob_data, blob_data_len); - key_data = CFRetain(ed); - } - require_action_quiet(ed, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'"))); - require_action_quiet(key_data, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'"))); - - const void *external_data = NULL; - size_t external_data_len = 0; - require_quiet(external_data = ks_ref_key_get_external_data(keybag, key_data, &tmp_ref_key, &external_data_len, error), out); - - CFPropertyListRef external_data_dict = NULL; - der_decode_plist(NULL, kCFPropertyListImmutable, &external_data_dict, NULL, external_data, external_data + external_data_len); - require_action_quiet(external_data_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'"))); - acl = CFDictionaryCreateMutableCopy(NULL, 0, external_data_dict); - SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) { - CFDictionaryRemoveValue(acl, attr_desc->name); - CFTypeRef value = CFDictionaryGetValue(external_data_dict, attr_desc->name); - if (value) { - if (!*authenticated_attributes) - *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value); - } - } - CFReleaseSafe(external_data_dict); - - if (acl) { - /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */ - if (version == 4) { - SecAccessControlSetConstraints(access_control, acl); - } else { - CFDictionaryRef constraints = CFDictionaryGetValue(acl, kAKSKeyAcl); - require_action_quiet(isDictionary(constraints), out, - SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: acl missing"))); - SecAccessControlSetConstraints(access_control, constraints); - } - - /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */ - if (version < 6) { - SecAccessConstraintRef encryptConstraint = SecAccessControlGetConstraint(access_control, kAKSKeyOpEncrypt); - if (!encryptConstraint) - SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL); - } - - } - - if (encrypted_data) - *encrypted_data = CFRetain(ed); - - if (ref_key) { - *ref_key = tmp_ref_key; - tmp_ref_key = NULL; - } - - ok = true; - -out: - if (tmp_ref_key) - aks_ref_key_free(&tmp_ref_key); - CFReleaseSafe(blob_dict); - CFReleaseSafe(key_data); - CFReleaseSafe(ed); - CFReleaseSafe(acl); - - - return ok; -} - -static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) { - CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control); - CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, auth_attributes); - CFDictionarySetValue(auth_data, kAKSKeyAcl, constraints); - CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL); - CFReleaseSafe(auth_data); - return encoded; -} - -static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error) -{ - size_t ag_size = der_sizeof_plist(access_groups, error); - CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0); - CFDataSetLength(result, ag_size); - if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) { - CFRelease(result); - return NULL; - } - else - return result; -} - -#endif /* USE_KEYSTORE */ - -static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control) -{ - CFTypeRef protection = SecAccessControlGetProtection(access_control); - size_t protection_size = der_sizeof_plist(protection, NULL); - CFMutableDataRef result = CFDataCreateMutable(NULL, 0); - CFDataSetLength(result, protection_size); - if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) { - CFRelease(result); - return NULL; - } - else - return result; -} - -static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end) -{ - CFTypeRef result = NULL; - der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, der, der_end); - return result; -} - -/* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */ -static CF_RETURNS_RETAINED -CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) { - if (plist && !isDictionary(plist)) { - CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist)); - SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName); - CFReleaseSafe(typeName); - CFReleaseNull(plist); - } - return (CFMutableDictionaryRef)plist; -} - -static CF_RETURNS_RETAINED -CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) { - CFPropertyListRef item; - item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error); - return dictionaryFromPlist(item, error); -} - -static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) = - ^const uint8_t*(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { - if (error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) { - CFAbsoluteTime date = 0; - CFCalendarRef calendar = CFCalendarCreateWithIdentifier(allocator, kCFGregorianCalendar); - CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, 0); - CFCalendarSetTimeZone(calendar, tz); - CFCalendarComposeAbsoluteTime(calendar, &date, "yMd", 2001, 3, 24); // random date for 15A143: can't recover keychain - CFReleaseSafe(tz); - CFReleaseSafe(calendar); - - *pl = CFDateCreate(allocator, date); - if (NULL != *pl) { - CFReleaseNull(*error); - return der_end; - } - } - return NULL; -}; - -static CF_RETURNS_RETAINED -CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) { - CFPropertyListRef item = NULL; - const uint8_t *der_beg = CFDataGetBytePtr(plain); - const uint8_t *der_end = der_beg + CFDataGetLength(plain); - const uint8_t *der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end); - if (!der && error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) { - CFReleaseNull(*error); - der = der_decode_plist_with_repair(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date); - } - if (der && der != der_end) { - SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error); - CFReleaseNull(item); - } - return dictionaryFromPlist(item, error); -} - -bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, - CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error) { - SecAccessControlRef ac = NULL; - CFDataRef ac_data = NULL; - bool ok = false; - - /* Decrypt and decode the item and check the decoded attributes against the query. */ - uint32_t version = 0; - - bool decryptSecretData = false; - if ((q->q_return_type & kSecReturnDataMask) || (q->q_return_type & kSecReturnRefMask)) { - decryptSecretData = true; - } - else if (q->q_match_policy || q->q_match_valid_on_date || q->q_match_trusted_only) { - decryptSecretData = true; - } - - require_quiet((ok = ks_decrypt_data(q->q_keybag, kAKSKeyOpDecrypt, &ac, q->q_use_cred_handle, edata, q->q_class, - q->q_caller_access_groups, item, &version, decryptSecretData, keyclass, error)), out); - if (version < 2) { - SecError(errSecDecode, error, CFSTR("version is unexpected: %d"), (int)version); - ok = false; - goto out; - } - - ac_data = SecAccessControlCopyData(ac); - if (!itemInAccessGroup(*item, accessGroups)) { - secerror("items accessGroup '%@' not in %@", - CFDictionaryGetValue(*item, kSecAttrAccessGroup), - accessGroups); - // We likely don't want to surface it to clients like this, but this is most accurate - SecError(errSecMissingEntitlement, error, CFSTR("item's access group '%@' not in %@"), - CFDictionaryGetValue(*item, kSecAttrAccessGroup), accessGroups); - CFReleaseNull(*item); - ok = false; - goto out; - } - - /* AccessControl attribute does not exist in the db, so synthesize it. */ - if (version > 3) - CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data); - - /* TODO: Validate access_control attribute. */ - -out: - if (access_control) - *access_control = CFRetainSafe(ac); - CFReleaseSafe(ac); - CFReleaseSafe(ac_data); - return ok; -} - -/* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items - being imported from a backup. */ -static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) { - bool ok = true; - CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); - CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); - - if (!isString(agrp) || !isString(accessible)) - return ok; - if (SecDbItemGetClass(item) == genp_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { - CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService); - if (!isString(svce)) return ok; - if (CFEqual(agrp, CFSTR("apple"))) { - if (CFEqual(svce, CFSTR("AirPort"))) { - ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); - } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) { - ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); - } else if (CFEqual(svce, CFSTR("YouTube"))) { - ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) && - SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error)); - } else { - CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription); - if (!isString(desc)) return ok; - if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) { - ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); - } - } - } - } else if (SecDbItemGetClass(item) == inet_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { - if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) { - ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); - } else if (CFEqual(agrp, CFSTR("apple"))) { - CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); - bool is_proxy = false; - if (isNumber(ptcl)) { - SInt32 iptcl; - CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl); - is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') || - iptcl == FOUR_CHAR_CODE('htsx') || - iptcl == FOUR_CHAR_CODE('ftpx') || - iptcl == FOUR_CHAR_CODE('rtsx') || - iptcl == FOUR_CHAR_CODE('xpth') || - iptcl == FOUR_CHAR_CODE('xsth') || - iptcl == FOUR_CHAR_CODE('xptf') || - iptcl == FOUR_CHAR_CODE('xstr')); - } else if (isString(ptcl)) { - is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) || - CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) || - CFEqual(ptcl, kSecAttrProtocolRTSPProxy) || - CFEqual(ptcl, kSecAttrProtocolFTPProxy)); - } - if (is_proxy) - ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); - } - } - return ok; -} - -bool SecDbItemDecrypt(SecDbItemRef item, bool decryptSecretData, CFDataRef edata, CFErrorRef *error) { - bool ok = true; - CFMutableDictionaryRef dict = NULL; - SecAccessControlRef access_control = NULL; - uint32_t version = 0; - - require_quiet(ok = ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, item->credHandle, edata, - item->class, item->callerAccessGroups, &dict, &version, decryptSecretData, NULL, error), out); - - if (version < 2) { - /* Old V4 style keychain backup being imported. */ - ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) && - SecDbItemImportMigrate(item, error); - } else { - ok = dict && SecDbItemSetValues(item, dict, error); - } - - SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error); - if (!my_access_control) { - ok = false; - goto out; - } - - /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got - back from decoding the data blob. */ - if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) { - ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"), - SecAccessControlGetProtection(my_access_control), - SecAccessControlGetProtection(access_control)); - } - CFRelease(my_access_control); - -out: - // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else - // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually - // decrypt the data. - ok = SecDbItemSetAccessControl(item, access_control, NULL) && ok; - - CFReleaseSafe(dict); - CFReleaseSafe(access_control); - return ok; -} - -/* Automagically make a item syncable, based on various attributes. */ -bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error) -{ - CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); - - if (!isString(agrp)) - return true; - - if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == inet_class()) { - CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer); - CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); - CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType); - - if (isString(srvr) && isString(ptcl) && isString(atyp)) { - /* This looks like a Mobile Safari Password, make syncable */ - secnotice("item", "Make this item syncable: %@", item); - return SecDbItemSetSyncable(item, true, error); - } - } - - return true; -} - -/* This create a SecDbItem from the item dictionnary that are exported for backups. - Item are stored in the backup as a dictionary containing two keys: - - v_Data: the encrypted data blob - - v_PersistentRef: a persistent Ref. - src_keybag is normally the backup keybag. - dst_keybag is normally the device keybag. - */ -SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error) -{ - CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data")); - SecDbItemRef item = NULL; - - if (edata) { - item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error); - if (item) - if (!SecDbItemSetKeybag(item, dst_keybag, error)) - CFReleaseNull(item); - } else { - SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict); - } - - return item; -} - -bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) { - CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef")); - if (!ref) - return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict); - - CFStringRef className; - sqlite3_int64 rowid; - if (!_SecItemParsePersistentRef(ref, &className, &rowid, NULL)) - return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref); - - if (!CFEqual(SecDbItemGetClass(item)->name, className)) - return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className); - - return SecDbItemSetRowId(item, rowid, error); -} - -static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { - CFDataRef der = NULL; - CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error); - if (dict) { - der = CFPropertyListCreateDERData(kCFAllocatorDefault, dict, error); - CFRelease(dict); - } - return der; -} - -static CFTypeRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { - CFDataRef digest = NULL; - CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error); - if (der) { - digest = CFDataCopySHA1Digest(der, error); - CFRelease(der); - } - return digest; -} - -static CFTypeRef SecDbItemCopySHA256DigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { - CFDataRef digest = NULL; - CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error); - if (der) { - digest = CFDataCopySHA256Digest(der, error); - CFRelease(der); - } - return digest; -} - -CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { - return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error); -} - -CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error) { - return SecDbItemCopySHA256DigestWithMask(item, kSecDbPrimaryKeyFlag, error); -} - -CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { - return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error); -} - -CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { - CFDataRef edata = NULL; - CFDataRef bkuuid = NULL; - CFMutableDictionaryRef secretStuff = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error); - CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); - CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); - if (secretStuff || attributes || auth_attributes) { - SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error); - CFDataRef sha1 = SecDbKeychainItemCopySHA1(item, attr, error); - if (access_control && sha1) { - if (!auth_attributes) { - auth_attributes = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } - CFDictionarySetValue(auth_attributes, kSecAttrSHA1, sha1); - - CFDictionaryForEach(secretStuff, ^(const void *key, const void *value) { - CFDictionaryRemoveValue(attributes, key); - CFDictionaryRemoveValue(auth_attributes, key); - }); - - if (ks_encrypt_data_with_backupuuid(item->keybag, access_control, item->credHandle, secretStuff, attributes, auth_attributes, &edata, &bkuuid, true, error)) { - item->_edataState = kSecDbItemEncrypting; - } else if (!error || !*error || CFErrorGetCode(*error) != errSecAuthNeeded || !CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain) ) { - seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR("")); - } - CFRelease(access_control); - } - CFReleaseNull(secretStuff); - CFReleaseNull(attributes); - CFReleaseNull(auth_attributes); - CFReleaseNull(sha1); - if (bkuuid) { - // "data" is defined first in the schema so called first. The UUID will therefore be in the cache when ForEach gets to it - CFErrorRef localError = NULL; - SecDbItemSetValueWithName(item, CFSTR("backupUUID"), bkuuid, &localError); - if (localError) { - // Don't want to propagate this. It's bad but should be handled in the manager and not interrupt production - secerror("Unable to wrap keychain item to backup: %@", localError); - CFReleaseNull(localError); - CFReleaseNull(bkuuid); - } - } - } - return edata; -} - -CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { - CFTypeRef value = NULL; - switch (attr->kind) { - case kSecDbDateAttr: - value = CFDateCreate(kCFAllocatorDefault, 0.0); - break; - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - break; - default: - SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name); - value = NULL; - } - - return value; -} - -SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error) { - SecAccessControlRef accc = NULL, pdmn = NULL, result = NULL; - CFTypeRef acccData = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), error); - CFTypeRef pdmnValue = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error); - - if (!acccData || !pdmnValue) - return NULL; - if (!CFEqual(acccData, kCFNull)) - require_quiet(accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, error), out); - - if (!CFEqual(pdmnValue, kCFNull)) { - require_quiet(pdmn = SecAccessControlCreate(CFGetAllocator(item), error), out); - require_quiet(SecAccessControlSetProtection(pdmn, pdmnValue, error), out); - } - - if (accc && pdmn) { - CFTypeRef acccProt = SecAccessControlGetProtection(accc); - CFTypeRef pdmnProt = SecAccessControlGetProtection(pdmn); - if (!acccProt || !pdmnProt || !CFEqual(acccProt, pdmnProt)) { - secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt, pdmnProt); - __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem); - // Setting pdmn to accc prot value. - require_quiet(SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), acccProt, error), out); - } - } - - if (accc) - CFRetainAssign(result, accc); - else if(pdmn) - CFRetainAssign(result, pdmn); - -out: - CFReleaseSafe(accc); - CFReleaseSafe(pdmn); - - return result; -} - -static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, - CFPropertyListRef* pl, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, - const uint8_t*, const uint8_t*)) -{ - if (NULL == der) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); - return NULL; - } - - ccder_tag tag; - if (NULL == ccder_decode_tag(&tag, der, der_end)) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error); - return NULL; - } - - switch (tag) { - case CCDER_NULL: - return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end); - case CCDER_BOOLEAN: - return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end); - case CCDER_OCTET_STRING: - return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end); - case CCDER_GENERALIZED_TIME: { - const uint8_t* der_result = der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end); - if (!der_result) { - der_result = repairBlock(allocator, mutability, pl, error, der, der_end); - } - return der_result; - } - case CCDER_CONSTRUCTED_SEQUENCE: - return der_decode_array_with_repair(allocator, mutability, (CFArrayRef*)pl, error, der, der_end, repairBlock); - case CCDER_UTF8_STRING: - return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end); - case CCDER_INTEGER: - return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end); - case CCDER_CONSTRUCTED_SET: - return der_decode_dictionary_with_repair(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end, repairBlock); - case CCDER_CONSTRUCTED_CFSET: - return der_decode_set_with_repair(allocator, mutability, (CFSetRef*)pl, error, der, der_end, repairBlock); - default: - SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error); - return NULL; - } -} - -static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, - CFDictionaryRef* dictionary, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, - const uint8_t*, const uint8_t*)) -{ - if (NULL == der) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); - return NULL; - } - - const uint8_t *payload_end = 0; - const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end); - - if (NULL == payload) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error); - return NULL; - } - - - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - if (NULL == dict) { - SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error); - payload = NULL; - goto exit; - } - - while (payload != NULL && payload < payload_end) { - CFTypeRef key = NULL; - CFTypeRef value = NULL; - - payload = der_decode_key_value_with_repair(allocator, mutability, &key, &value, error, payload, payload_end, repairBlock); - - if (payload) { - CFDictionaryAddValue(dict, key, value); - } - - CFReleaseNull(key); - CFReleaseNull(value); - } - - -exit: - if (payload == payload_end) { - *dictionary = dict; - dict = NULL; - } - - CFReleaseNull(dict); - - return payload; -} - -static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, - CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, - const uint8_t*, const uint8_t*)) -{ - const uint8_t *payload_end = 0; - const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end); - - if (NULL == payload) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error); - return NULL; - } - - CFTypeRef keyObject = NULL; - CFTypeRef valueObject = NULL; - - - payload = der_decode_plist_with_repair(allocator, mutability, &keyObject, error, payload, payload_end, repairBlock); - payload = der_decode_plist_with_repair(allocator, mutability, &valueObject, error, payload, payload_end, repairBlock); - - if (payload != NULL) { - *key = keyObject; - *value = valueObject; - } else { - CFReleaseNull(keyObject); - CFReleaseNull(valueObject); - } - return payload; -} - -static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, - CFArrayRef* array, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, - const uint8_t*, const uint8_t*)) -{ - if (NULL == der) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); - return NULL; - } - - CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); - - const uint8_t *elements_end; - const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end); - - while (current_element != NULL && current_element < elements_end) { - CFPropertyListRef element = NULL; - current_element = der_decode_plist_with_repair(allocator, mutability, &element, error, current_element, elements_end, repairBlock); - if (current_element) { - CFArrayAppendValue(result, element); - CFReleaseNull(element); - } - } - - if (current_element) { - *array = result; - result = NULL; - } - - CFReleaseNull(result); - return current_element; -} - -static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, - CFSetRef* set, CFErrorRef *error, - const uint8_t* der, const uint8_t *der_end, - const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, - const uint8_t*, const uint8_t*)) -{ - if (NULL == der) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); - return NULL; - } - - const uint8_t *payload_end = 0; - const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end); - - if (NULL == payload) { - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL, error); - return NULL; - } - - CFMutableSetRef theSet = (set && *set) ? CFSetCreateMutableCopy(allocator, 0, *set) - : CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); - - if (NULL == theSet) { - SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create set"), NULL, error); - payload = NULL; - goto exit; - } - - while (payload != NULL && payload < payload_end) { - CFTypeRef value = NULL; - - payload = der_decode_plist_with_repair(allocator, mutability, &value, error, payload, payload_end, repairBlock); - - if (payload) { - CFSetAddValue(theSet, value); - } - CFReleaseNull(value); - } - - -exit: - if (set && payload == payload_end) { - CFTransferRetained(*set, theSet); - } - - CFReleaseNull(theSet); - - return payload; -} - -void SecDbResetMetadataKeys(void) { - [SecDbKeychainMetadataKeyStore resetSharedStore]; -} diff --git a/OSX/sec/securityd/SecDbKeychainItemV7.h b/OSX/sec/securityd/SecDbKeychainItemV7.h deleted file mode 100644 index 7c96a0a3..00000000 --- a/OSX/sec/securityd/SecDbKeychainItemV7.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SecKeybagSupport.h" -#import -#import -#import "CheckV12DevEnabled.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface SecDbKeychainItemV7 : NSObject - -@property (nonatomic, readonly) keyclass_t keyclass; -@property (nonatomic, readonly) NSData* backupUUID; - -- (nullable instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error; -- (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass; - -- (nullable NSDictionary*)metadataAttributesWithError:(NSError**)error; -- (nullable NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error; -- (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error; - -- (nullable NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(nullable NSData*)acmContext error:(NSError**)error; - -@end - -extern NSString* const SecDbKeychainErrorDomain; -extern const NSInteger SecDbKeychainErrorDeserializationFailed; - - -@class SecDbKeychainSerializedMetadata; -@class SecDbKeychainSerializedSecretData; - -@interface SecDbKeychainItemV7 (UnitTesting) - -+ (bool)isKeychainUnlocked; - -@property (readonly) NSData* encryptedMetadataBlob; -@property (readonly) NSData* encryptedSecretDataBlob; - -- (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error; -- (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(nullable NSData*)acmContext error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/OSX/sec/securityd/SecDbKeychainItemV7.m b/OSX/sec/securityd/SecDbKeychainItemV7.m deleted file mode 100644 index 1fd3957d..00000000 --- a/OSX/sec/securityd/SecDbKeychainItemV7.m +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SecDbKeychainItemV7.h" -#import "SecKeybagSupport.h" -#import "SecItemServer.h" -#import "SecAccessControl.h" -#import "SecDbKeychainSerializedItemV7.h" -#import "SecDbKeychainSerializedAKSWrappedKey.h" -#import "SecDbKeychainSerializedMetadata.h" -#import "SecDbKeychainSerializedSecretData.h" -#import -#import -#import "SecAKSObjCWrappers.h" -#import -#import -#import -#import - -#import - -#if USE_KEYSTORE && __has_include() -#import -#endif - -#import "SecDbKeychainMetadataKeyStore.h" -#import "SecDbBackupManager.h" - -#define KEYCHAIN_ITEM_PADDING_MODULUS 20 - -// See corresponding "reasonable size" client-side limit(s) in SecItem. - -// Generally the secret data dictionary contains a single key -// with the client's password/key NSData therein, so 4k feels extremely luxurious -#define REASONABLE_SECRET_DATA_SIZE 4096 - -// This feels similarly generous, but let's find out -#define REASONABLE_METADATA_SIZE 2048 - -NSString* const SecDbKeychainErrorDomain = @"SecDbKeychainErrorDomain"; -const NSInteger SecDbKeychainErrorDeserializationFailed = 1; - -static NSString* const SecDBTamperCheck = @"TamperCheck"; - -static NSDictionary* dictionaryFromDERData(NSData* data) -{ - NSDictionary* dict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)data, 0, NULL, NULL); - return [dict isKindOfClass:[NSDictionary class]] ? dict : nil; -} - -typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) { - SecDbKeychainAKSWrappedKeyTypeRegular, - SecDbKeychainAKSWrappedKeyTypeRefKey -}; - -@interface SecDbKeychainAKSWrappedKey : NSObject - -@property (readonly) NSData* wrappedKey; -@property (readonly) NSData* refKeyBlob; -@property (readonly) SecDbKeychainAKSWrappedKeyType type; - -@property (readonly) NSData* serializedRepresentation; - -- (instancetype)initWithData:(NSData*)data; -- (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey; -- (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob; - -@end - -@interface SecDbKeychainMetadata : NSObject - -@property (readonly) SFAuthenticatedCiphertext* ciphertext; -@property (readonly) SFAuthenticatedCiphertext* wrappedKey; -@property (readonly) NSString* tamperCheck; - -@property (readonly) NSData* serializedRepresentation; - -- (instancetype)initWithData:(NSData*)data; -- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error; - -@end - -@interface SecDbKeychainSecretData : NSObject - -@property (readonly) SFAuthenticatedCiphertext* ciphertext; -@property (readonly) SecDbKeychainAKSWrappedKey* wrappedKey; -@property (readonly) NSString* tamperCheck; - -@property (readonly) NSData* serializedRepresentation; - -- (instancetype)initWithData:(NSData*)data; -- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey error:(NSError**)error; - -@end - -@implementation SecDbKeychainAKSWrappedKey { - SecDbKeychainSerializedAKSWrappedKey* _serializedHolder; -} - -- (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; - _serializedHolder.wrappedKey = wrappedKey; - _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRegular; - } - - return self; -} - -- (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; - _serializedHolder.wrappedKey = wrappedKey; - _serializedHolder.refKeyBlob = refKeyBlob; - _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRefKey; - } - - return self; -} - -- (instancetype)initWithData:(NSData*)data -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] initWithData:data]; - if (!_serializedHolder.wrappedKey || (_serializedHolder.type == SecDbKeychainAKSWrappedKeyTypeRefKey && !_serializedHolder.refKeyBlob)) { - self = nil; - } - } - - return self; -} - -- (NSData*)serializedRepresentation -{ - return _serializedHolder.data; -} - -- (NSData*)wrappedKey -{ - return _serializedHolder.wrappedKey; -} - -- (NSData*)refKeyBlob -{ - return _serializedHolder.refKeyBlob; -} - -- (SecDbKeychainAKSWrappedKeyType)type -{ - return _serializedHolder.type; -} - -@end - -@implementation SecDbKeychainMetadata { - SecDbKeychainSerializedMetadata* _serializedHolder; -} - -- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext - wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey - tamperCheck:(NSString*)tamperCheck - error:(NSError**)error -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] init]; - _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; - _serializedHolder.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedKey requiringSecureCoding:YES error:error]; - _serializedHolder.tamperCheck = tamperCheck; - if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { - self = nil; - } - } - - return self; -} - -- (instancetype)initWithData:(NSData*)data -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] initWithData:data]; - if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { - self = nil; - } - } - - return self; -} - -- (NSData*)serializedRepresentation -{ - return _serializedHolder.data; -} - -- (SFAuthenticatedCiphertext*)ciphertext -{ - NSError* error = nil; - SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; - if (!ciphertext) { - secerror("SecDbKeychainItemV7: error deserializing ciphertext from metadata: %@", error); - } - - return ciphertext; -} - -- (SFAuthenticatedCiphertext*)wrappedKey -{ - NSError* error = nil; - SFAuthenticatedCiphertext* wrappedKey = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.wrappedKey error:&error]; - if (!wrappedKey) { - secerror("SecDbKeychainItemV7: error deserializing wrappedKey from metadata: %@", error); - } - - return wrappedKey; -} - -- (NSString*)tamperCheck -{ - return _serializedHolder.tamperCheck; -} - -@end - -@implementation SecDbKeychainSecretData { - SecDbKeychainSerializedSecretData* _serializedHolder; -} - -- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext - wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey - tamperCheck:(NSString*)tamperCheck - backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey - error:(NSError**)error -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] init]; - _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; - _serializedHolder.wrappedKey = wrappedKey.serializedRepresentation; - _serializedHolder.tamperCheck = tamperCheck; - _serializedHolder.secDbBackupWrappedItemKey = backupWrappedKey ? [NSKeyedArchiver archivedDataWithRootObject:backupWrappedKey requiringSecureCoding:YES error:error] : nil; - if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { - self = nil; - } - } - - return self; -} - -- (instancetype)initWithData:(NSData*)data -{ - if (self = [super init]) { - _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] initWithData:data]; - if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { - self = nil; - } - } - - return self; -} - -- (NSData*)serializedRepresentation -{ - return _serializedHolder.data; -} - -- (SFAuthenticatedCiphertext*)ciphertext -{ - NSError* error = nil; - SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; - if (!ciphertext) { - secerror("SecDbKeychainItemV7: error deserializing ciphertext from secret data: %@", error); - } - - return ciphertext; -} - -- (SecDbKeychainAKSWrappedKey*)wrappedKey -{ - return [[SecDbKeychainAKSWrappedKey alloc] initWithData:_serializedHolder.wrappedKey]; -} - -- (NSString*)tamperCheck -{ - return _serializedHolder.tamperCheck; -} - -@end - -@interface SecDbKeychainItemV7 () -@property (nonatomic) NSData* backupUUID; -@end; - -@implementation SecDbKeychainItemV7 { - SecDbKeychainSecretData* _encryptedSecretData; - SecDbKeychainMetadata* _encryptedMetadata; - NSDictionary* _secretAttributes; - NSDictionary* _metadataAttributes; - NSString* _tamperCheck; - keyclass_t _keyclass; - keybag_handle_t _keybag; -} - -@synthesize keyclass = _keyclass; - -// bring back with -#if 0 -+ (bool)isKeychainUnlocked -{ - return kc_is_unlocked(); -} -#endif - -- (instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error -{ - if (self = [super init]) { - SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] initWithData:data]; - if (serializedItem) { - - // Add 10% for serializing overhead. We're trying to catch blatant overstuffing, not enforce hard limits - if (data.length > ((REASONABLE_SECRET_DATA_SIZE + REASONABLE_METADATA_SIZE) * 1.1)) { - secwarning("SecDbKeychainItemV7: serialized item exceeds reasonable size (%lu bytes)", (unsigned long)data.length); - } - - _keybag = decryptionKeybag; - _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithData:serializedItem.encryptedSecretData]; - _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithData:serializedItem.encryptedMetadata]; - _keyclass = serializedItem.keyclass; - if (![_encryptedSecretData.tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { - self = nil; - } - } - else { - self = nil; - } - } - - if (!self && error) { - *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecItemNotFound userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}]; - } - - return self; -} - -- (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass -{ - NSParameterAssert(tamperCheck); - - if (self = [super init]) { - _secretAttributes = secretAttributes ? secretAttributes.copy : [NSDictionary dictionary]; - _metadataAttributes = metadataAttributes ? metadataAttributes.copy : [NSDictionary dictionary]; - _tamperCheck = tamperCheck.copy; - _keyclass = keyclass; - } - - return self; -} - -+ (SFAESKeySpecifier*)keySpecifier -{ - static SFAESKeySpecifier* keySpecifier = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; - }); - - return keySpecifier; -} - -+ (SFAuthenticatedEncryptionOperation*)encryptionOperation -{ - static SFAuthenticatedEncryptionOperation* encryptionOperation = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; - }); - - return encryptionOperation; -} - -+ (SFAuthenticatedEncryptionOperation*)decryptionOperation -{ - static SFAuthenticatedEncryptionOperation* decryptionOperation = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - decryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; - }); - - return decryptionOperation; -} - -- (NSDictionary*)metadataAttributesWithError:(NSError**)error -{ - if (!_metadataAttributes) { - SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:_keybag - createKeyIfMissing:false - overwriteCorruptKey:false - error:error]; - if (metadataClassKey) { - NSError* localError = nil; - NSData* keyData = [[self.class decryptionOperation] decrypt:_encryptedMetadata.wrappedKey withKey:metadataClassKey error:&localError]; - if (!keyData) { - secerror("SecDbKeychainItemV7: error unwrapping item metadata key (class %d, bag %d): %@", (int)self.keyclass, _keybag, localError); - // TODO: track this in LocalKeychainAnalytics - if (error) { - CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error - SecError(errSecDecode, &secError, CFSTR("failed to unwrap item metadata key")); - *error = CFBridgingRelease(secError); - } - return nil; - } - SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:[self.class keySpecifier] error:error]; - if (!key) { - return nil; - } - - NSData* metadata = [[self.class decryptionOperation] decrypt:_encryptedMetadata.ciphertext withKey:key error:&localError]; - if (!metadata) { - secerror("SecDbKeychainItemV7: error decrypting metadata content: %@", localError); - if (error) { - CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error - SecError(errSecDecode, &secError, CFSTR("failed to decrypt item metadata contents")); - *error = CFBridgingRelease(secError); - } - return nil; - } - NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(metadata).mutableCopy; - NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; - if ([tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { - [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; - _metadataAttributes = decryptedAttributes; - } - else { - secerror("SecDbKeychainItemV7: tamper check failed for metadata decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); - if (error) { - CFErrorRef secError = NULL; - SecError(errSecDecode, &secError, CFSTR("tamper check failed for metadata decryption")); - *error = CFBridgingRelease(secError); - } - } - } - } - - return _metadataAttributes; -} - -- (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error -{ - if (!_secretAttributes) { - SFAESKey* key = [self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:NO error:error]; - if (key) { - NSError* localError = nil; - NSData* secretDataWithPadding = [[self.class decryptionOperation] decrypt:_encryptedSecretData.ciphertext withKey:key error:&localError]; - if (!secretDataWithPadding) { - secerror("SecDbKeychainItemV7: error decrypting item secret data contents: %@", localError); - if (error) { - CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error - SecError(errSecDecode, &secError, CFSTR("error decrypting item secret data contents")); - *error = CFBridgingRelease(secError); - } - return nil; - } - int8_t paddingLength = *((int8_t*)secretDataWithPadding.bytes + secretDataWithPadding.length - 1); - NSData* secretDataWithoutPadding = [secretDataWithPadding subdataWithRange:NSMakeRange(0, secretDataWithPadding.length - paddingLength)]; - - NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(secretDataWithoutPadding).mutableCopy; - NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; - if ([tamperCheck isEqualToString:_encryptedSecretData.tamperCheck]) { - [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; - _secretAttributes = decryptedAttributes; - } - else { - secerror("SecDbKeychainItemV7: tamper check failed for secret data decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); - } - } - } - - return _secretAttributes; -} - -- (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error -{ - NSError* localError = nil; - (void)[self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:YES error:&localError]; - if (localError) { - secerror("SecDbKeychainItemV7: failed to delete item secret key from aks"); - if (error) { - *error = localError; - } - - return NO; - } - - return YES; -} - -- (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error -{ - NSError* localError = nil; - BOOL success = [self encryptMetadataWithKeybag:keybag error:&localError]; - if (!success || !_encryptedMetadata || localError) { - if (error) { - *error = localError; - } - return nil; - } - - success = [self encryptSecretDataWithKeybag:keybag accessControl:accessControl acmContext:acmContext error:&localError]; - if (!success || !_encryptedSecretData || localError) { - if (error) { - *error = localError; - } - return nil; - } - - SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init]; - serializedItem.encryptedMetadata = self.encryptedMetadataBlob; - serializedItem.encryptedSecretData = self.encryptedSecretDataBlob; - serializedItem.keyclass = _keyclass; - return serializedItem.data; -} - -- (NSData*)encryptedMetadataBlob -{ - return _encryptedMetadata.serializedRepresentation; -} - -- (NSData*)encryptedSecretDataBlob -{ - return _encryptedSecretData.serializedRepresentation; -} - -- (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error -{ - SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; - if (!key) { - return NO; - } - SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; - - NSMutableDictionary* attributesToEncrypt = _metadataAttributes.mutableCopy; - attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; - NSData* metadata = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL); - - if (metadata.length > REASONABLE_METADATA_SIZE) { - NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; - secwarning("SecDbKeychainItemV7: item's metadata exceeds reasonable size (%lu bytes) (%@)", (unsigned long)metadata.length, agrp); - } - - SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error]; - - SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag - createKeyIfMissing:true - overwriteCorruptKey:true - error:error]; - if (metadataClassKey) { - SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error]; - _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error]; - } - - return _encryptedMetadata != nil; -} - -- (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error -{ - SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; - if (!key) { - return NO; - } - SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; - - NSMutableDictionary* attributesToEncrypt = _secretAttributes.mutableCopy; - attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; - NSMutableData* secretData = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL) mutableCopy]; - - if (secretData.length > REASONABLE_SECRET_DATA_SIZE) { - NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; - secwarning("SecDbKeychainItemV7: item's secret data exceeds reasonable size (%lu bytes) (%@)", (unsigned long)secretData.length, agrp); - } - - int8_t paddingLength = KEYCHAIN_ITEM_PADDING_MODULUS - (secretData.length % KEYCHAIN_ITEM_PADDING_MODULUS); - int8_t paddingBytes[KEYCHAIN_ITEM_PADDING_MODULUS]; - for (int i = 0; i < KEYCHAIN_ITEM_PADDING_MODULUS; i++) { - paddingBytes[i] = paddingLength; - } - [secretData appendBytes:paddingBytes length:paddingLength]; - - SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error]; - SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error]; - - SecDbBackupWrappedItemKey* backupWrappedKey; - if (checkV12DevEnabled()) { - backupWrappedKey = [[SecDbBackupManager manager] wrapItemKey:key forKeyclass:_keyclass error:error]; - if (backupWrappedKey) { - _backupUUID = backupWrappedKey.baguuid; - } else { - secwarning("SecDbKeychainItemV7: backup manager didn't return wrapped key: %@", error ? *error : nil); - if (error) { - *error = nil; - } - } - } - - _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithCiphertext:ciphertext - wrappedKey:wrappedKey - tamperCheck:_tamperCheck - backupWrappedKey:backupWrappedKey - error:error]; - return _encryptedSecretData != nil; -} - -- (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag - createKeyIfMissing:(bool)createIfMissing - overwriteCorruptKey:(bool)force - error:(NSError**)error -{ - return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass - keybag:keybag - keySpecifier:[self.class keySpecifier] - createKeyIfMissing:(bool)createIfMissing - overwriteCorruptKey:force - error:error]; -} - -- (SecDbKeychainAKSWrappedKey*)wrapToAKS:(SFAESKey*)key withKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error -{ - NSData* keyData = key.keyData; - -#if USE_KEYSTORE - NSDictionary* constraints = (__bridge NSDictionary*)SecAccessControlGetConstraints(accessControl); - if (constraints) { - aks_ref_key_t refKey = NULL; - CFErrorRef cfError = NULL; - NSData* authData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)@{(id)kAKSKeyAcl : constraints}, &cfError); - - if (!acmContext || !SecAccessControlIsBound(accessControl)) { - secerror("SecDbKeychainItemV7: access control error"); - if (error) { - CFDataRef accessControlData = SecAccessControlCopyData(accessControl); - ks_access_control_needed_error(&cfError, accessControlData, SecAccessControlIsBound(accessControl) ? kAKSKeyOpEncrypt : CFSTR("")); - CFReleaseNull(accessControlData); - } - - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - - void* aksParams = NULL; - size_t aksParamsLength = 0; - aks_operation_optional_params(0, 0, authData.bytes, authData.length, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); - - int aksResult = aks_ref_key_create(keybag, _keyclass, key_type_sym, aksParams, aksParamsLength, &refKey); - if (aksResult != 0) { - CFDataRef accessControlData = SecAccessControlCopyData(accessControl); - create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); - CFReleaseNull(accessControlData); - free(aksParams); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - - size_t wrappedKeySize = 0; - void* wrappedKeyBytes = NULL; - aksResult = aks_ref_key_encrypt(refKey, aksParams, aksParamsLength, keyData.bytes, keyData.length, &wrappedKeyBytes, &wrappedKeySize); - if (aksResult != 0) { - CFDataRef accessControlData = SecAccessControlCopyData(accessControl); - create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); - CFReleaseNull(accessControlData); - free(aksParams); - aks_ref_key_free(&refKey); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - free(aksParams); - - BridgeCFErrorToNSErrorOut(error, cfError); - - NSData* wrappedKey = [[NSData alloc] initWithBytesNoCopy:wrappedKeyBytes length:wrappedKeySize]; - - size_t refKeyBlobLength = 0; - const void* refKeyBlobBytes = aks_ref_key_get_blob(refKey, &refKeyBlobLength); - NSData* refKeyBlob = [[NSData alloc] initWithBytesNoCopy:(void*)refKeyBlobBytes length:refKeyBlobLength]; - aks_ref_key_free(&refKey); - return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob]; - } - else { - NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40]; - bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; - return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; - } -#else - NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40]; - bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; - return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; -#endif -} - -- (SFAESKey*)unwrapFromAKS:(SecDbKeychainAKSWrappedKey*)wrappedKey accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext callerAccessGroups:(NSArray*)callerAccessGroups delete:(BOOL)delete error:(NSError**)error -{ - NSData* wrappedKeyData = wrappedKey.wrappedKey; - - if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) { - NSMutableData* unwrappedKey = [NSMutableData dataWithCapacity:wrappedKeyData.length + 40]; - unwrappedKey.length = wrappedKeyData.length + 40; - bool result = [SecAKSObjCWrappers aksDecryptWithKeybag:_keybag keyclass:_keyclass ciphertext:wrappedKeyData outKeyclass:&_keyclass plaintext:unwrappedKey error:error]; - if (result) { - return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error]; - } - else { - return nil; - } - } -#if USE_KEYSTORE - else if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRefKey) { - aks_ref_key_t refKey = NULL; - aks_ref_key_create_with_blob(_keybag, wrappedKey.refKeyBlob.bytes, wrappedKey.refKeyBlob.length, &refKey); - - CFErrorRef cfError = NULL; - size_t refKeyExternalDataLength = 0; - const uint8_t* refKeyExternalDataBytes = aks_ref_key_get_external_data(refKey, &refKeyExternalDataLength); - if (!refKeyExternalDataBytes) { - aks_ref_key_free(&refKey); - return nil; - } - NSDictionary* aclDict = nil; - der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength); - if (!aclDict) { - SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict")); - } - SecAccessControlSetConstraints(accessControl, (__bridge CFDictionaryRef)aclDict); - if (!SecAccessControlGetConstraint(accessControl, kAKSKeyOpEncrypt)) { - SecAccessControlAddConstraintForOperation(accessControl, kAKSKeyOpEncrypt, kCFBooleanTrue, &cfError); - } - - size_t derPlistLength = der_sizeof_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError); - NSMutableData* accessGroupDERData = [[NSMutableData alloc] initWithLength:derPlistLength]; - der_encode_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError, accessGroupDERData.mutableBytes, accessGroupDERData.mutableBytes + derPlistLength); - void* aksParams = NULL; - size_t aksParamsLength = 0; - aks_operation_optional_params(accessGroupDERData.bytes, derPlistLength, NULL, 0, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); - - void* unwrappedKeyDERData = NULL; - size_t unwrappedKeyDERLength = 0; - int aksResult = aks_ref_key_decrypt(refKey, aksParams, aksParamsLength, wrappedKeyData.bytes, wrappedKeyData.length, &unwrappedKeyDERData, &unwrappedKeyDERLength); - if (aksResult != 0) { - CFDataRef accessControlData = SecAccessControlCopyData(accessControl); - create_cferror_from_aks(aksResult, kAKSKeyOpDecrypt, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); - CFReleaseNull(accessControlData); - aks_ref_key_free(&refKey); - free(aksParams); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - if (!unwrappedKeyDERData) { - SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); - aks_ref_key_free(&refKey); - free(aksParams); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - - CFPropertyListRef unwrappedKeyData = NULL; - der_decode_plist(NULL, kCFPropertyListImmutable, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength); - SFAESKey* result = nil; - if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) { - result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error]; - CFReleaseNull(unwrappedKeyDERData); - } - else { - SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); - aks_ref_key_free(&refKey); - free(aksParams); - free(unwrappedKeyDERData); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - - if (delete) { - aksResult = aks_ref_key_delete(refKey, aksParams, aksParamsLength); - if (aksResult != 0) { - CFDataRef accessControlData = SecAccessControlCopyData(accessControl); - create_cferror_from_aks(aksResult, kAKSKeyOpDelete, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); - CFReleaseNull(accessControlData); - aks_ref_key_free(&refKey); - free(aksParams); - free(unwrappedKeyDERData); - BridgeCFErrorToNSErrorOut(error, cfError); - return nil; - } - } - - BridgeCFErrorToNSErrorOut(error, cfError); - aks_ref_key_free(&refKey); - free(aksParams); - free(unwrappedKeyDERData); - return result; - } -#endif - else { - return nil; - } -} - -@end diff --git a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.h b/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.h deleted file mode 100644 index 5c35094a..00000000 --- a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import -#import -#import "SecKeybagSupport.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -// This class is intended for SecDbKeychainItemV7, db resets and SecDbKeychainManager _only_ - -@interface SecDbKeychainMetadataKeyStore : NSObject - -+ (bool)cachingEnabled; - -+ (void)resetSharedStore; -+ (instancetype)sharedStore; - -- (instancetype)init NS_UNAVAILABLE; - -- (void)dropClassAKeys; - -- (SFAESKey*)keyForKeyclass:(keyclass_t)keyClass - keybag:(keybag_handle_t)keybag - keySpecifier:(SFAESKeySpecifier*)keySpecifier - createKeyIfMissing:(bool)createIfMissing - overwriteCorruptKey:(bool)overwriteCorruptKey - error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m b/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m deleted file mode 100644 index d406a1b1..00000000 --- a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "SecDbKeychainMetadataKeyStore.h" -#import -#import -#import -#import "SecItemServer.h" -#import "SecAKSObjCWrappers.h" -#import "sec_action.h" - -static SecDbKeychainMetadataKeyStore* sharedStore = nil; -static dispatch_queue_t sharedMetadataStoreQueue; -static void initializeSharedMetadataStoreQueue(void) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedMetadataStoreQueue = dispatch_queue_create("metadata_store", DISPATCH_QUEUE_SERIAL); - }); -} - -@implementation SecDbKeychainMetadataKeyStore { - NSMutableDictionary* _keysDict; - dispatch_queue_t _queue; -} - -+ (void)resetSharedStore -{ - initializeSharedMetadataStoreQueue(); - dispatch_sync(sharedMetadataStoreQueue, ^{ - if(sharedStore) { - dispatch_sync(sharedStore->_queue, ^{ - [sharedStore _onQueueDropAllKeys]; - }); - } - sharedStore = nil; - }); -} - -+ (instancetype)sharedStore -{ - __block SecDbKeychainMetadataKeyStore* ret; - initializeSharedMetadataStoreQueue(); - dispatch_sync(sharedMetadataStoreQueue, ^{ - if(!sharedStore) { - sharedStore = [[self alloc] _init]; - } - - ret = sharedStore; - }); - - return ret; -} - -+ (bool)cachingEnabled -{ - return true; -} - -- (instancetype)_init -{ - if (self = [super init]) { - _keysDict = [[NSMutableDictionary alloc] init]; - _queue = dispatch_queue_create("SecDbKeychainMetadataKeyStore", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); - int token = 0; - __weak __typeof(self) weakSelf = self; - notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int inToken) { - bool locked = true; - CFErrorRef error = NULL; - if (!SecAKSGetIsLocked(&locked, &error)) { - secerror("SecDbKeychainMetadataKeyStore: error getting lock state: %@", error); - CFReleaseNull(error); - } - - if (locked) { - [weakSelf _onQueueDropClassAKeys]; - } - }); - } - - return self; -} - -- (void)dropClassAKeys -{ - dispatch_sync(_queue, ^{ - [self _onQueueDropClassAKeys]; - }); -} - -- (void)_onQueueDropClassAKeys -{ - dispatch_assert_queue(_queue); - - secnotice("SecDbKeychainMetadataKeyStore", "dropping class A metadata keys"); - _keysDict[@(key_class_ak)] = nil; - _keysDict[@(key_class_aku)] = nil; - _keysDict[@(key_class_akpu)] = nil; -} - -- (void)_onQueueDropAllKeys -{ - dispatch_assert_queue(_queue); - - secnotice("SecDbKeychainMetadataKeyStore", "dropping all metadata keys"); - [_keysDict removeAllObjects]; -} - -- (void)_updateActualKeyclassIfNeeded:(keyclass_t)actualKeyclassToWriteBackToDB keyclass:(keyclass_t)keyclass -{ - __block CFErrorRef cfError = NULL; - - secnotice("SecDbKeychainItemV7", "saving actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass); - - kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) { - __block bool actualKeyWriteBackOk = true; - - // we did not find an actualKeyclass entry in the db, so let's add one in now. - NSString *sql = @"UPDATE metadatakeys SET actualKeyclass = ? WHERE keyclass = ? AND actualKeyclass IS NULL"; - __block CFErrorRef actualKeyWriteBackError = NULL; - actualKeyWriteBackOk &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &actualKeyWriteBackError, ^(sqlite3_stmt* stmt) { - actualKeyWriteBackOk &= SecDbBindInt(stmt, 1, actualKeyclassToWriteBackToDB, &actualKeyWriteBackError); - actualKeyWriteBackOk &= SecDbBindInt(stmt, 2, keyclass, &actualKeyWriteBackError); - actualKeyWriteBackOk &= SecDbStep(dbt, stmt, &actualKeyWriteBackError, ^(bool* stop) { - // woohoo - }); - }); - - if (actualKeyWriteBackOk) { - secnotice("SecDbKeychainItemV7", "successfully saved actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass); - - } - else { - // we can always try this again in the future if it failed - secerror("SecDbKeychainItemV7: failed to save actualKeyclass %d for metadata keyclass %d; error: %@", actualKeyclassToWriteBackToDB, keyclass, actualKeyWriteBackError); - } - return actualKeyWriteBackOk; - }); -} - -- (SFAESKey*)keyForKeyclass:(keyclass_t)keyclass - keybag:(keybag_handle_t)keybag - keySpecifier:(SFAESKeySpecifier*)keySpecifier - createKeyIfMissing:(bool)createIfMissing - overwriteCorruptKey:(bool)overwriteCorruptKey - error:(NSError**)error -{ - __block SFAESKey* key = nil; - __block NSError* nsErrorLocal = nil; - __block CFErrorRef cfError = NULL; - static __thread BOOL reentrant = NO; - - NSAssert(!reentrant, @"re-entering -[%@ %@] - that shouldn't happen!", NSStringFromClass(self.class), NSStringFromSelector(_cmd)); - reentrant = YES; - - keyclass = SecAKSSanitizedKeyclass(keyclass); - - dispatch_sync(_queue, ^{ - // if we think we're locked, it's possible AKS will still give us access to keys, such as during backup, - // but we should force AKS to be the truth and not used cached class A keys while locked - bool allowKeyCaching = [SecDbKeychainMetadataKeyStore cachingEnabled]; - - // However, we must not cache a newly-created key, just in case someone above us in the stack rolls back our database transaction and the stored key is lost. - __block bool keyIsNewlyCreated = false; -#if 0 - // Fix keychain lock state check to be both secure and fast for EDU mode - if (![SecDbKeychainItemV7 isKeychainUnlocked]) { - [self _onQueueDropClassAKeys]; - allowKeyCaching = !(keyclass == key_class_ak || keyclass == key_class_aku || keyclass == key_class_akpu); - } -#endif - - key = allowKeyCaching ? self->_keysDict[@(keyclass)] : nil; - if (!key) { - __block bool ok = true; - __block bool metadataKeyDoesntAuthenticate = false; - ok &= kc_with_dbt_non_item_tables(createIfMissing, &cfError, ^bool(SecDbConnectionRef dbt) { - __block NSString* sql = [NSString stringWithFormat:@"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = %d", keyclass]; - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { - ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { - NSData* wrappedKeyData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; - NSMutableData* unwrappedKeyData = [NSMutableData dataWithLength:wrappedKeyData.length]; - - keyclass_t actualKeyclass = sqlite3_column_int(stmt, 1); - - keyclass_t actualKeyclassToWriteBackToDB = 0; - keyclass_t keyclassForUnwrapping = actualKeyclass == 0 ? keyclass : actualKeyclass; - ok &= [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyclassForUnwrapping ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&nsErrorLocal]; - if (ok) { - key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&nsErrorLocal]; - - if(!key) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted, but didn't become a key: %@", keyclass, nsErrorLocal); - } - - if (actualKeyclass == 0) { - actualKeyclassToWriteBackToDB = keyclassForUnwrapping; - } - } -#if USE_KEYSTORE - else if (actualKeyclass == 0 && keyclass <= key_class_last) { - // in this case we might have luck decrypting with a key-rolled keyclass - keyclass_t keyrolledKeyclass = keyclass | (key_class_last + 1); - secerror("SecDbKeychainItemV7: failed to decrypt metadata key for class %d, but trying keyrolled keyclass (%d); error: %@", keyclass, keyrolledKeyclass, nsErrorLocal); - - // we don't want to pollute subsequent error-handling logic with what happens on our retry - // we'll give it a shot, and if it works, great - if it doesn't work, we'll just report that error in the log and move on - NSError* retryError = nil; - ok = [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyrolledKeyclass ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&retryError]; - - if (ok) { - secerror("SecDbKeychainItemV7: successfully decrypted metadata key using keyrolled keyclass %d", keyrolledKeyclass); - key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&retryError]; - - if(!key) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted using keyrolled keyclass %d, but didn't become a key: %@", keyclass, keyrolledKeyclass, retryError); - nsErrorLocal = retryError; - } - } - else { - secerror("SecDbKeychainItemV7: failed to decrypt metadata key with keyrolled keyclass %d; error: %@", keyrolledKeyclass, retryError); - } - } -#endif - - if (ok && key) { - if (actualKeyclassToWriteBackToDB > 0) { - // check if we have updated this keyclass or not already - static NSMutableDictionary* updated = NULL; - if (!updated) { - updated = [NSMutableDictionary dictionary]; - } - if (!updated[@(keyclass)]) { - updated[@(keyclass)] = @YES; - dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ - [self _updateActualKeyclassIfNeeded:actualKeyclassToWriteBackToDB keyclass:keyclass]; - }); - } - } - } - else { - if (nsErrorLocal && [nsErrorLocal.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && nsErrorLocal.code == errSecInteractionNotAllowed) { - static dispatch_once_t kclockedtoken; - static sec_action_t kclockedaction; - dispatch_once(&kclockedtoken, ^{ - kclockedaction = sec_action_create("keychainlockedlogmessage", 1); - sec_action_set_handler(kclockedaction, ^{ - secerror("SecDbKeychainItemV7: failed to decrypt metadata key because the keychain is locked (%d)", (int)errSecInteractionNotAllowed); - }); - }); - sec_action_perform(kclockedaction); - } else { - secerror("SecDbKeychainItemV7: failed to decrypt and create metadata key for class %d; error: %@", keyclass, nsErrorLocal); - - // If this error is errSecDecode, then it's failed authentication and likely will forever. Other errors are scary. - metadataKeyDoesntAuthenticate = [nsErrorLocal.domain isEqualToString:NSOSStatusErrorDomain] && nsErrorLocal.code == errSecDecode; - if(metadataKeyDoesntAuthenticate) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal); - } - } - } - }); - }); - - bool keyNotYetCreated = ok && !key; - bool forceOverwriteBadKey = !key && metadataKeyDoesntAuthenticate && overwriteCorruptKey; - - if (createIfMissing && (keyNotYetCreated || forceOverwriteBadKey)) { - // we completed the database query, but no key exists or it's broken - we should create one - if(forceOverwriteBadKey) { - secerror("SecDbKeychainItemV7: metadata key is irreparably corrupt; throwing away forever"); - // TODO: track this in LocalKeychainAnalytics - } - - ok = true; // Reset 'ok': we have a second chance - - key = [[SFAESKey alloc] initRandomKeyWithSpecifier:keySpecifier error:&nsErrorLocal]; - keyIsNewlyCreated = true; - - if (key) { - NSMutableData* wrappedKey = [NSMutableData dataWithLength:key.keyData.length + 40]; - keyclass_t outKeyclass = keyclass; - ok &= [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:keyclass plaintext:key.keyData outKeyclass:&outKeyclass ciphertext:wrappedKey error:&nsErrorLocal]; - if (ok) { - secinfo("SecDbKeychainItemV7", "attempting to save new metadata key for keyclass %d with actualKeyclass %d", keyclass, outKeyclass); - NSString* insertString = forceOverwriteBadKey ? @"INSERT OR REPLACE" : @"INSERT"; - sql = [NSString stringWithFormat:@"%@ into metadatakeys (keyclass, actualKeyclass, data) VALUES (?, ?, ?)", insertString]; - ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt* stmt) { - ok &= SecDbBindInt(stmt, 1, keyclass, &cfError); - ok &= SecDbBindInt(stmt, 2, outKeyclass, &cfError); - ok &= SecDbBindBlob(stmt, 3, wrappedKey.bytes, wrappedKey.length, SQLITE_TRANSIENT, NULL); - ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { - // woohoo - }); - }); - - if (ok) { - secnotice("SecDbKeychainItemV7", "successfully saved new metadata key for keyclass %d", keyclass); - } - else { - secerror("SecDbKeychainItemV7: failed to save new metadata key for keyclass %d - probably there is already one in the database: %@", keyclass, cfError); - } - } else { - secerror("SecDbKeychainItemV7: unable to encrypt new metadata key(%d) with keybag(%d): %@", keyclass, keybag, nsErrorLocal); - } - } - else { - ok = false; - } - } else if(!key) { - // No key, but we're not supposed to make one. Make an error if one doesn't yet exist. - ok = false; - if(!nsErrorLocal) { - nsErrorLocal = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Unable to find or create a suitable metadata key"}]; - } - } - - return ok; - }); - - if (ok && key) { - // We can't cache a newly-created key, just in case this db transaction is rolled back and we lose the persisted key. - // Don't worry, we'll cache it as soon as it's used again. - if (allowKeyCaching && !keyIsNewlyCreated) { - self->_keysDict[@(keyclass)] = key; - __weak __typeof(self) weakSelf = self; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * 5 * NSEC_PER_SEC)), self->_queue, ^{ - [weakSelf _onQueueDropClassAKeys]; - }); - } - } - else { - key = nil; - } - } - }); - - reentrant = NO; - - if (error && nsErrorLocal) { - *error = nsErrorLocal; - CFReleaseNull(cfError); - } - else { - BridgeCFErrorToNSErrorOut(error, cfError); - } - - return key; -} - -@end diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto b/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto deleted file mode 100644 index 4c6db5da..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto2"; - -message SecDbKeychainSerializedAKSWrappedKey { - required bytes wrappedKey = 1; - optional bytes refKeyBlob = 2; - required uint32 type = 3; -} diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto b/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto deleted file mode 100644 index 4138447d..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto2"; - -message SecDbKeychainSerializedItemV7 { - required bytes encryptedSecretData = 1; - required bytes encryptedMetadata = 2; - - enum Keyclass { - KEYCLASS_AK = 6; - KEYCLASS_CK = 7; - KEYCLASS_DK = 8; - KEYCLASS_AKU = 9; - KEYCLASS_CKU = 10; - KEYCLASS_DKU = 11; - KEYCLASS_AKPU = 12; - } - required Keyclass keyclass = 3 [default = KEYCLASS_AKPU]; -} diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto b/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto deleted file mode 100644 index f21796c2..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto2"; - -message SecDbKeychainSerializedMetadata { - required bytes ciphertext = 1; - required bytes wrappedKey = 2; - required string tamperCheck = 3; -} diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto b/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto deleted file mode 100644 index 55353e16..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto +++ /dev/null @@ -1,8 +0,0 @@ -syntax = "proto2"; - -message SecDbKeychainSerializedSecretData { - required bytes ciphertext = 1; - required bytes wrappedKey = 2; - required string tamperCheck = 3; - optional bytes SecDbBackupWrappedItemKey = 4; -} diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h deleted file mode 100644 index 154cc192..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h +++ /dev/null @@ -1,41 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedAKSWrappedKey.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION extern "C" -#else -#define SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION extern -#endif - -@interface SecDbKeychainSerializedAKSWrappedKey : PBCodable -{ - NSData *_refKeyBlob; - uint32_t _type; - NSData *_wrappedKey; -} - - -@property (nonatomic, retain) NSData *wrappedKey; - -@property (nonatomic, readonly) BOOL hasRefKeyBlob; -@property (nonatomic, retain) NSData *refKeyBlob; - -@property (nonatomic) uint32_t type; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbKeychainSerializedAKSWrappedKey *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbKeychainSerializedAKSWrappedKey *)other; - -SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION BOOL SecDbKeychainSerializedAKSWrappedKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedAKSWrappedKey *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m deleted file mode 100644 index 5a4b4465..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m +++ /dev/null @@ -1,168 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedAKSWrappedKey.proto - -#import "SecDbKeychainSerializedAKSWrappedKey.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbKeychainSerializedAKSWrappedKey - -@synthesize wrappedKey = _wrappedKey; -- (BOOL)hasRefKeyBlob -{ - return _refKeyBlob != nil; -} -@synthesize refKeyBlob = _refKeyBlob; -@synthesize type = _type; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_wrappedKey) - { - [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; - } - if (self->_refKeyBlob) - { - [dict setObject:self->_refKeyBlob forKey:@"refKeyBlob"]; - } - [dict setObject:[NSNumber numberWithUnsignedInt:self->_type] forKey:@"type"]; - return dict; -} - -BOOL SecDbKeychainSerializedAKSWrappedKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedAKSWrappedKey *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* wrappedKey */: - { - NSData *new_wrappedKey = PBReaderReadData(reader); - self->_wrappedKey = new_wrappedKey; - } - break; - case 2 /* refKeyBlob */: - { - NSData *new_refKeyBlob = PBReaderReadData(reader); - self->_refKeyBlob = new_refKeyBlob; - } - break; - case 3 /* type */: - { - self->_type = PBReaderReadUint32(reader); - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbKeychainSerializedAKSWrappedKeyReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* wrappedKey */ - { - assert(nil != self->_wrappedKey); - PBDataWriterWriteDataField(writer, self->_wrappedKey, 1); - } - /* refKeyBlob */ - { - if (self->_refKeyBlob) - { - PBDataWriterWriteDataField(writer, self->_refKeyBlob, 2); - } - } - /* type */ - { - PBDataWriterWriteUint32Field(writer, self->_type, 3); - } -} - -- (void)copyTo:(SecDbKeychainSerializedAKSWrappedKey *)other -{ - other.wrappedKey = _wrappedKey; - if (_refKeyBlob) - { - other.refKeyBlob = _refKeyBlob; - } - other->_type = _type; -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbKeychainSerializedAKSWrappedKey *copy = [[[self class] allocWithZone:zone] init]; - copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; - copy->_refKeyBlob = [_refKeyBlob copyWithZone:zone]; - copy->_type = _type; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbKeychainSerializedAKSWrappedKey *other = (SecDbKeychainSerializedAKSWrappedKey *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) - && - ((!self->_refKeyBlob && !other->_refKeyBlob) || [self->_refKeyBlob isEqual:other->_refKeyBlob]) - && - self->_type == other->_type - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_wrappedKey hash] - ^ - [self->_refKeyBlob hash] - ^ - PBHashInt((NSUInteger)_type) - ; -} - -- (void)mergeFrom:(SecDbKeychainSerializedAKSWrappedKey *)other -{ - if (other->_wrappedKey) - { - [self setWrappedKey:other->_wrappedKey]; - } - if (other->_refKeyBlob) - { - [self setRefKeyBlob:other->_refKeyBlob]; - } - self->_type = other->_type; -} - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h deleted file mode 100644 index 630bd070..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h +++ /dev/null @@ -1,81 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedItemV7.proto - -#import -#import - -typedef NS_ENUM(int32_t, SecDbKeychainSerializedItemV7_Keyclass) { - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK = 6, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK = 7, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK = 8, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU = 9, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU = 10, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU = 11, - SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU = 12, -}; -#ifdef __OBJC__ -NS_INLINE NSString *SecDbKeychainSerializedItemV7_KeyclassAsString(SecDbKeychainSerializedItemV7_Keyclass value) -{ - switch (value) - { - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK: return @"KEYCLASS_AK"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK: return @"KEYCLASS_CK"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK: return @"KEYCLASS_DK"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU: return @"KEYCLASS_AKU"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU: return @"KEYCLASS_CKU"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU: return @"KEYCLASS_DKU"; - case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU: return @"KEYCLASS_AKPU"; - default: return [NSString stringWithFormat:@"(unknown: %i)", value]; - } -} -#endif /* __OBJC__ */ -#ifdef __OBJC__ -NS_INLINE SecDbKeychainSerializedItemV7_Keyclass StringAsSecDbKeychainSerializedItemV7_Keyclass(NSString *value) -{ - if ([value isEqualToString:@"KEYCLASS_AK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK; - if ([value isEqualToString:@"KEYCLASS_CK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK; - if ([value isEqualToString:@"KEYCLASS_DK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK; - if ([value isEqualToString:@"KEYCLASS_AKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU; - if ([value isEqualToString:@"KEYCLASS_CKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU; - if ([value isEqualToString:@"KEYCLASS_DKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU; - if ([value isEqualToString:@"KEYCLASS_AKPU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU; - return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK; -} -#endif /* __OBJC__ */ - -#ifdef __cplusplus -#define SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION extern "C" -#else -#define SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION extern -#endif - -@interface SecDbKeychainSerializedItemV7 : PBCodable -{ - NSData *_encryptedMetadata; - NSData *_encryptedSecretData; - SecDbKeychainSerializedItemV7_Keyclass _keyclass; -} - - -@property (nonatomic, retain) NSData *encryptedSecretData; - -@property (nonatomic, retain) NSData *encryptedMetadata; - -@property (nonatomic) SecDbKeychainSerializedItemV7_Keyclass keyclass; -- (NSString *)keyclassAsString:(SecDbKeychainSerializedItemV7_Keyclass)value; -- (SecDbKeychainSerializedItemV7_Keyclass)StringAsKeyclass:(NSString *)str; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbKeychainSerializedItemV7 *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbKeychainSerializedItemV7 *)other; - -SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION BOOL SecDbKeychainSerializedItemV7ReadFrom(__unsafe_unretained SecDbKeychainSerializedItemV7 *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m deleted file mode 100644 index 3ccff9ec..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m +++ /dev/null @@ -1,167 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedItemV7.proto - -#import "SecDbKeychainSerializedItemV7.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbKeychainSerializedItemV7 - -@synthesize encryptedSecretData = _encryptedSecretData; -@synthesize encryptedMetadata = _encryptedMetadata; -@synthesize keyclass = _keyclass; -- (NSString *)keyclassAsString:(SecDbKeychainSerializedItemV7_Keyclass)value -{ - return SecDbKeychainSerializedItemV7_KeyclassAsString(value); -} -- (SecDbKeychainSerializedItemV7_Keyclass)StringAsKeyclass:(NSString *)str -{ - return StringAsSecDbKeychainSerializedItemV7_Keyclass(str); -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_encryptedSecretData) - { - [dict setObject:self->_encryptedSecretData forKey:@"encryptedSecretData"]; - } - if (self->_encryptedMetadata) - { - [dict setObject:self->_encryptedMetadata forKey:@"encryptedMetadata"]; - } - [dict setObject:SecDbKeychainSerializedItemV7_KeyclassAsString(self->_keyclass) forKey:@"keyclass"]; - return dict; -} - -BOOL SecDbKeychainSerializedItemV7ReadFrom(__unsafe_unretained SecDbKeychainSerializedItemV7 *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* encryptedSecretData */: - { - NSData *new_encryptedSecretData = PBReaderReadData(reader); - self->_encryptedSecretData = new_encryptedSecretData; - } - break; - case 2 /* encryptedMetadata */: - { - NSData *new_encryptedMetadata = PBReaderReadData(reader); - self->_encryptedMetadata = new_encryptedMetadata; - } - break; - case 3 /* keyclass */: - { - self->_keyclass = PBReaderReadInt32(reader); - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbKeychainSerializedItemV7ReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* encryptedSecretData */ - { - assert(nil != self->_encryptedSecretData); - PBDataWriterWriteDataField(writer, self->_encryptedSecretData, 1); - } - /* encryptedMetadata */ - { - assert(nil != self->_encryptedMetadata); - PBDataWriterWriteDataField(writer, self->_encryptedMetadata, 2); - } - /* keyclass */ - { - PBDataWriterWriteInt32Field(writer, self->_keyclass, 3); - } -} - -- (void)copyTo:(SecDbKeychainSerializedItemV7 *)other -{ - other.encryptedSecretData = _encryptedSecretData; - other.encryptedMetadata = _encryptedMetadata; - other->_keyclass = _keyclass; -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbKeychainSerializedItemV7 *copy = [[[self class] allocWithZone:zone] init]; - copy->_encryptedSecretData = [_encryptedSecretData copyWithZone:zone]; - copy->_encryptedMetadata = [_encryptedMetadata copyWithZone:zone]; - copy->_keyclass = _keyclass; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbKeychainSerializedItemV7 *other = (SecDbKeychainSerializedItemV7 *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_encryptedSecretData && !other->_encryptedSecretData) || [self->_encryptedSecretData isEqual:other->_encryptedSecretData]) - && - ((!self->_encryptedMetadata && !other->_encryptedMetadata) || [self->_encryptedMetadata isEqual:other->_encryptedMetadata]) - && - self->_keyclass == other->_keyclass - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_encryptedSecretData hash] - ^ - [self->_encryptedMetadata hash] - ^ - PBHashInt((NSUInteger)_keyclass) - ; -} - -- (void)mergeFrom:(SecDbKeychainSerializedItemV7 *)other -{ - if (other->_encryptedSecretData) - { - [self setEncryptedSecretData:other->_encryptedSecretData]; - } - if (other->_encryptedMetadata) - { - [self setEncryptedMetadata:other->_encryptedMetadata]; - } - self->_keyclass = other->_keyclass; -} - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h deleted file mode 100644 index a2855be0..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h +++ /dev/null @@ -1,40 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedMetadata.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION extern "C" -#else -#define SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION extern -#endif - -@interface SecDbKeychainSerializedMetadata : PBCodable -{ - NSData *_ciphertext; - NSString *_tamperCheck; - NSData *_wrappedKey; -} - - -@property (nonatomic, retain) NSData *ciphertext; - -@property (nonatomic, retain) NSData *wrappedKey; - -@property (nonatomic, retain) NSString *tamperCheck; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbKeychainSerializedMetadata *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbKeychainSerializedMetadata *)other; - -SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION BOOL SecDbKeychainSerializedMetadataReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadata *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m deleted file mode 100644 index b32c5b2d..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m +++ /dev/null @@ -1,167 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedMetadata.proto - -#import "SecDbKeychainSerializedMetadata.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbKeychainSerializedMetadata - -@synthesize ciphertext = _ciphertext; -@synthesize wrappedKey = _wrappedKey; -@synthesize tamperCheck = _tamperCheck; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_ciphertext) - { - [dict setObject:self->_ciphertext forKey:@"ciphertext"]; - } - if (self->_wrappedKey) - { - [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; - } - if (self->_tamperCheck) - { - [dict setObject:self->_tamperCheck forKey:@"tamperCheck"]; - } - return dict; -} - -BOOL SecDbKeychainSerializedMetadataReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadata *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* ciphertext */: - { - NSData *new_ciphertext = PBReaderReadData(reader); - self->_ciphertext = new_ciphertext; - } - break; - case 2 /* wrappedKey */: - { - NSData *new_wrappedKey = PBReaderReadData(reader); - self->_wrappedKey = new_wrappedKey; - } - break; - case 3 /* tamperCheck */: - { - NSString *new_tamperCheck = PBReaderReadString(reader); - self->_tamperCheck = new_tamperCheck; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbKeychainSerializedMetadataReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* ciphertext */ - { - assert(nil != self->_ciphertext); - PBDataWriterWriteDataField(writer, self->_ciphertext, 1); - } - /* wrappedKey */ - { - assert(nil != self->_wrappedKey); - PBDataWriterWriteDataField(writer, self->_wrappedKey, 2); - } - /* tamperCheck */ - { - assert(nil != self->_tamperCheck); - PBDataWriterWriteStringField(writer, self->_tamperCheck, 3); - } -} - -- (void)copyTo:(SecDbKeychainSerializedMetadata *)other -{ - other.ciphertext = _ciphertext; - other.wrappedKey = _wrappedKey; - other.tamperCheck = _tamperCheck; -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbKeychainSerializedMetadata *copy = [[[self class] allocWithZone:zone] init]; - copy->_ciphertext = [_ciphertext copyWithZone:zone]; - copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; - copy->_tamperCheck = [_tamperCheck copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbKeychainSerializedMetadata *other = (SecDbKeychainSerializedMetadata *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_ciphertext && !other->_ciphertext) || [self->_ciphertext isEqual:other->_ciphertext]) - && - ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) - && - ((!self->_tamperCheck && !other->_tamperCheck) || [self->_tamperCheck isEqual:other->_tamperCheck]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_ciphertext hash] - ^ - [self->_wrappedKey hash] - ^ - [self->_tamperCheck hash] - ; -} - -- (void)mergeFrom:(SecDbKeychainSerializedMetadata *)other -{ - if (other->_ciphertext) - { - [self setCiphertext:other->_ciphertext]; - } - if (other->_wrappedKey) - { - [self setWrappedKey:other->_wrappedKey]; - } - if (other->_tamperCheck) - { - [self setTamperCheck:other->_tamperCheck]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h deleted file mode 100644 index 9f74bff0..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h +++ /dev/null @@ -1,44 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedSecretData.proto - -#import -#import - -#ifdef __cplusplus -#define SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION extern "C" -#else -#define SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION extern -#endif - -@interface SecDbKeychainSerializedSecretData : PBCodable -{ - NSData *_ciphertext; - NSData *_secDbBackupWrappedItemKey; - NSString *_tamperCheck; - NSData *_wrappedKey; -} - - -@property (nonatomic, retain) NSData *ciphertext; - -@property (nonatomic, retain) NSData *wrappedKey; - -@property (nonatomic, retain) NSString *tamperCheck; - -@property (nonatomic, readonly) BOOL hasSecDbBackupWrappedItemKey; -@property (nonatomic, retain) NSData *secDbBackupWrappedItemKey; - -// Performs a shallow copy into other -- (void)copyTo:(SecDbKeychainSerializedSecretData *)other; - -// Performs a deep merge from other into self -// If set in other, singular values in self are replaced in self -// Singular composite values are recursively merged -// Repeated values from other are appended to repeated values in self -- (void)mergeFrom:(SecDbKeychainSerializedSecretData *)other; - -SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION BOOL SecDbKeychainSerializedSecretDataReadFrom(__unsafe_unretained SecDbKeychainSerializedSecretData *self, __unsafe_unretained PBDataReader *reader); - -@end - diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m b/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m deleted file mode 100644 index b073d483..00000000 --- a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m +++ /dev/null @@ -1,202 +0,0 @@ -// This file was automatically generated by protocompiler -// DO NOT EDIT! -// Compiled from SecDbKeychainSerializedSecretData.proto - -#import "SecDbKeychainSerializedSecretData.h" -#import -#import -#import - -#if !__has_feature(objc_arc) -# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. -#endif - -@implementation SecDbKeychainSerializedSecretData - -@synthesize ciphertext = _ciphertext; -@synthesize wrappedKey = _wrappedKey; -@synthesize tamperCheck = _tamperCheck; -- (BOOL)hasSecDbBackupWrappedItemKey -{ - return _secDbBackupWrappedItemKey != nil; -} -@synthesize secDbBackupWrappedItemKey = _secDbBackupWrappedItemKey; - -- (NSString *)description -{ - return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; -} - -- (NSDictionary *)dictionaryRepresentation -{ - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - if (self->_ciphertext) - { - [dict setObject:self->_ciphertext forKey:@"ciphertext"]; - } - if (self->_wrappedKey) - { - [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; - } - if (self->_tamperCheck) - { - [dict setObject:self->_tamperCheck forKey:@"tamperCheck"]; - } - if (self->_secDbBackupWrappedItemKey) - { - [dict setObject:self->_secDbBackupWrappedItemKey forKey:@"SecDbBackupWrappedItemKey"]; - } - return dict; -} - -BOOL SecDbKeychainSerializedSecretDataReadFrom(__unsafe_unretained SecDbKeychainSerializedSecretData *self, __unsafe_unretained PBDataReader *reader) { - while (PBReaderHasMoreData(reader)) { - uint32_t tag = 0; - uint8_t aType = 0; - - PBReaderReadTag32AndType(reader, &tag, &aType); - - if (PBReaderHasError(reader)) - break; - - if (aType == TYPE_END_GROUP) { - break; - } - - switch (tag) { - - case 1 /* ciphertext */: - { - NSData *new_ciphertext = PBReaderReadData(reader); - self->_ciphertext = new_ciphertext; - } - break; - case 2 /* wrappedKey */: - { - NSData *new_wrappedKey = PBReaderReadData(reader); - self->_wrappedKey = new_wrappedKey; - } - break; - case 3 /* tamperCheck */: - { - NSString *new_tamperCheck = PBReaderReadString(reader); - self->_tamperCheck = new_tamperCheck; - } - break; - case 4 /* secDbBackupWrappedItemKey */: - { - NSData *new_secDbBackupWrappedItemKey = PBReaderReadData(reader); - self->_secDbBackupWrappedItemKey = new_secDbBackupWrappedItemKey; - } - break; - default: - if (!PBReaderSkipValueWithTag(reader, tag, aType)) - return NO; - break; - } - } - return !PBReaderHasError(reader); -} - -- (BOOL)readFrom:(PBDataReader *)reader -{ - return SecDbKeychainSerializedSecretDataReadFrom(self, reader); -} -- (void)writeTo:(PBDataWriter *)writer -{ - /* ciphertext */ - { - assert(nil != self->_ciphertext); - PBDataWriterWriteDataField(writer, self->_ciphertext, 1); - } - /* wrappedKey */ - { - assert(nil != self->_wrappedKey); - PBDataWriterWriteDataField(writer, self->_wrappedKey, 2); - } - /* tamperCheck */ - { - assert(nil != self->_tamperCheck); - PBDataWriterWriteStringField(writer, self->_tamperCheck, 3); - } - /* secDbBackupWrappedItemKey */ - { - if (self->_secDbBackupWrappedItemKey) - { - PBDataWriterWriteDataField(writer, self->_secDbBackupWrappedItemKey, 4); - } - } -} - -- (void)copyTo:(SecDbKeychainSerializedSecretData *)other -{ - other.ciphertext = _ciphertext; - other.wrappedKey = _wrappedKey; - other.tamperCheck = _tamperCheck; - if (_secDbBackupWrappedItemKey) - { - other.secDbBackupWrappedItemKey = _secDbBackupWrappedItemKey; - } -} - -- (id)copyWithZone:(NSZone *)zone -{ - SecDbKeychainSerializedSecretData *copy = [[[self class] allocWithZone:zone] init]; - copy->_ciphertext = [_ciphertext copyWithZone:zone]; - copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; - copy->_tamperCheck = [_tamperCheck copyWithZone:zone]; - copy->_secDbBackupWrappedItemKey = [_secDbBackupWrappedItemKey copyWithZone:zone]; - return copy; -} - -- (BOOL)isEqual:(id)object -{ - SecDbKeychainSerializedSecretData *other = (SecDbKeychainSerializedSecretData *)object; - return [other isMemberOfClass:[self class]] - && - ((!self->_ciphertext && !other->_ciphertext) || [self->_ciphertext isEqual:other->_ciphertext]) - && - ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) - && - ((!self->_tamperCheck && !other->_tamperCheck) || [self->_tamperCheck isEqual:other->_tamperCheck]) - && - ((!self->_secDbBackupWrappedItemKey && !other->_secDbBackupWrappedItemKey) || [self->_secDbBackupWrappedItemKey isEqual:other->_secDbBackupWrappedItemKey]) - ; -} - -- (NSUInteger)hash -{ - return 0 - ^ - [self->_ciphertext hash] - ^ - [self->_wrappedKey hash] - ^ - [self->_tamperCheck hash] - ^ - [self->_secDbBackupWrappedItemKey hash] - ; -} - -- (void)mergeFrom:(SecDbKeychainSerializedSecretData *)other -{ - if (other->_ciphertext) - { - [self setCiphertext:other->_ciphertext]; - } - if (other->_wrappedKey) - { - [self setWrappedKey:other->_wrappedKey]; - } - if (other->_tamperCheck) - { - [self setTamperCheck:other->_tamperCheck]; - } - if (other->_secDbBackupWrappedItemKey) - { - [self setSecDbBackupWrappedItemKey:other->_secDbBackupWrappedItemKey]; - } -} - -@end - diff --git a/OSX/sec/securityd/SecDbQuery.c b/OSX/sec/securityd/SecDbQuery.c deleted file mode 100644 index ae67d53a..00000000 --- a/OSX/sec/securityd/SecDbQuery.c +++ /dev/null @@ -1,987 +0,0 @@ - -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecDbQuery.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if USE_KEYSTORE -#include -#include -#include -#endif - -/* Upper limit for number of keys in a QUERY dictionary. */ -#define QUERY_KEY_LIMIT_BASE (128) -#ifdef NO_SERVER -#define QUERY_KEY_LIMIT (31 + QUERY_KEY_LIMIT_BASE) -#else -#define QUERY_KEY_LIMIT QUERY_KEY_LIMIT_BASE -#endif - - -static const uint8_t systemKeychainUUID[] = "\xF6\x23\xAE\x5C\xCC\x81\x4C\xAC\x8A\xD4\xF0\x01\x3F\x31\x35\x11"; - -CFDataRef -SecMUSRCopySystemKeychainUUID(void) -{ - return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull); -} - -CFDataRef -SecMUSRGetSystemKeychainUUID(void) -{ - static dispatch_once_t onceToken; - static CFDataRef systemKeychainData = NULL; - dispatch_once(&onceToken, ^{ - systemKeychainData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull); - }); - return systemKeychainData; -} - -CFDataRef -SecMUSRGetSingleUserKeychainUUID(void) -{ - static dispatch_once_t onceToken; - static CFDataRef singleUser = NULL; - dispatch_once(&onceToken, ^{ - singleUser = CFDataCreateWithBytesNoCopy(NULL, NULL, 0, kCFAllocatorNull); - }); - return singleUser; -} - -bool -SecMUSRIsSingleUserView(CFDataRef musr) -{ - return CFEqual(musr, SecMUSRGetSingleUserKeychainUUID()); -} - -static const uint8_t allKeychainViewsUUID[16] = "\xC8\x60\x07\xEC\x89\x62\x4D\xAF\x85\x65\x1F\xE6\x0F\x50\x5D\xB7"; - -CFDataRef -SecMUSRGetAllViews(void) -{ - static dispatch_once_t onceToken; - static CFDataRef allKeychainViewsData = NULL; - dispatch_once(&onceToken, ^{ - allKeychainViewsData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)allKeychainViewsUUID, 16, kCFAllocatorNull); - }); - return allKeychainViewsData; -} - -bool -SecMUSRIsViewAllViews(CFDataRef musr) -{ - return CFEqual(musr, SecMUSRGetAllViews()); -} - -#if TARGET_OS_IPHONE - -CFDataRef -SecMUSRCreateActiveUserUUID(uid_t uid) -{ - uint8_t uuid[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72"; - uint32_t num = htonl(uid); - memcpy(&uuid[12], &num, sizeof(num)); - return CFDataCreate(NULL, uuid, sizeof(uuid)); -} - -CFDataRef -SecMUSRCreateSyncBubbleUserUUID(uid_t uid) -{ - uint8_t uuid[16] = "\x82\x1A\xAB\x9F\xA3\xC8\x4E\x11\xAA\x90\x4C\xE8\x9E\xA6\xD7\xEC"; - uint32_t num = htonl(uid); - memcpy(&uuid[12], &num, sizeof(num)); - return CFDataCreate(NULL, uuid, sizeof(uuid)); -} - -static const uint8_t bothUserAndSystemUUID[12] = "\x36\xC4\xBE\x2E\x99\x0A\x46\x9A\xAC\x89\x09\xA4"; - - -CFDataRef -SecMUSRCreateBothUserAndSystemUUID(uid_t uid) -{ - uint8_t uuid[16]; - memcpy(uuid, bothUserAndSystemUUID, 12); - uint32_t num = htonl(uid); - memcpy(&uuid[12], &num, sizeof(num)); - return CFDataCreate(NULL, uuid, sizeof(uuid)); -} - -bool -SecMUSRGetBothUserAndSystemUUID(CFDataRef musr, uid_t *uid) -{ - if (CFDataGetLength(musr) != 16) - return false; - const uint8_t *uuid = CFDataGetBytePtr(musr); - if (memcmp(uuid, bothUserAndSystemUUID, 12) != 0) - return false; - if (uid) { - uint32_t num; - memcpy(&num, &uuid[12], sizeof(num)); - *uid = htonl(num); - } - return true; -} - -#endif - -/* Inline accessors to attr and match values in a query. */ -CFIndex query_attr_count(const Query *q) -{ - return q->q_attr_end; -} - -Pair query_attr_at(const Query *q, CFIndex ix) -{ - return q->q_pairs[ix]; -} - -CFIndex query_match_count(const Query *q) -{ - return q->q_match_end - q->q_match_begin; -} - -__unused static inline Pair query_match_at(const Query *q, CFIndex ix) -{ - return q->q_pairs[q->q_match_begin + ix]; -} - -/* Private routines used to parse a query. */ - -const SecDbClass *kc_class_with_name(CFStringRef name) { - if (isString(name)) { - if (CFEqual(name, kSecClassGenericPassword)) - return genp_class(); - else if (CFEqual(name, kSecClassInternetPassword)) - return inet_class(); - else if (CFEqual(name, kSecClassCertificate)) - return cert_class(); - else if (CFEqual(name, kSecClassKey)) - return keys_class(); - else if (CFEqual(name, kSecClassIdentity)) - return identity_class(); - } - return NULL; -} - -static void query_set_access_control(Query *q, SecAccessControlRef access_control) { - if (q->q_access_control) { - if (!CFEqual(q->q_access_control, access_control)) { - SecError(errSecItemIllegalQuery, &q->q_error, CFSTR("conflicting kSecAccess and kSecAccessControl attributes")); - } - } else { - /* Store access control virtual attribute. */ - q->q_access_control = (SecAccessControlRef)CFRetain(access_control); - - /* Also set legacy access attribute. */ - CFTypeRef protection = SecAccessControlGetProtection(q->q_access_control); - if (!protection) { - SecError(errSecParam, &q->q_error, CFSTR("kSecAccessControl missing protection")); - return; - } - CFDictionarySetValue(q->q_item, kSecAttrAccessible, protection); - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string or number of length 4. - value (ok) is a caller provided, non NULL CFTypeRef. - */ -void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) -{ - if (CFEqual(desc->name, kSecAttrSynchronizable)) { - q->q_sync = true; - if (CFEqual(value, kSecAttrSynchronizableAny)) - return; /* skip the attribute so it isn't part of the search */ - } - - CFTypeRef attr = NULL; - switch (desc->kind) { - case kSecDbDataAttr: - attr = copyData(value); - break; - case kSecDbBlobAttr: - case kSecDbAccessControlAttr: - attr = copyBlob(value); - break; - case kSecDbDateAttr: - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - attr = copyDate(value); - break; - case kSecDbNumberAttr: - case kSecDbSyncAttr: - case kSecDbTombAttr: - attr = copyNumber(value); - break; - case kSecDbAccessAttr: - case kSecDbStringAttr: - attr = copyString(value); - break; - case kSecDbSHA1Attr: - attr = copySHA1(value); - break; - case kSecDbRowIdAttr: - case kSecDbPrimaryKeyAttr: - case kSecDbEncryptedDataAttr: - case kSecDbUTombAttr: - break; - case kSecDbUUIDAttr: - attr = copyUUID(value); - break; - } - - if (!attr) { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value); - return; - } - - /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */ - if (q->q_item && desc->kind != kSecDbSHA1Attr) { - CFDictionarySetValue(q->q_item, desc->name, attr); - } - - /* Convert attr to (sha1) digest if requested. */ - if (desc->flags & kSecDbSHA1ValueInFlag) { - CFDataRef data = copyData(attr); - CFRelease(attr); - if (!data) { - SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name); - return; - } - - CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH); - CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH); - /* 64 bits cast: worst case is we generate the wrong hash */ - assert((unsigned long)CFDataGetLength(data)kind != kSecDbAccessControlAttr) { - /* Record the new attr key, value in q_pairs. */ - if (q->q_attr_end + 1 < q->q_pairs_count) { - q->q_pairs[q->q_attr_end].key = desc->name; - q->q_pairs[q->q_attr_end++].value = attr; - } else { - SecError(errSecInternal, &q->q_error, CFSTR("q_pairs overflow")); - CFReleaseSafe(attr); - } - } else { - CFReleaseSafe(attr); - } -} - -void query_add_attribute(const void *key, const void *value, Query *q) -{ - if (CFEqual(key, kSecAttrDeriveSyncIDFromItemAttributes)) { - q->q_uuid_from_primary_key = CFBooleanGetValue(value); - return; /* skip the attribute so it isn't part of the search */ - } - - const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); - if (desc) { - query_add_attribute_with_desc(desc, value, q); - - if (desc->kind == kSecDbAccessControlAttr) { - CFDataRef attr = (CFDataRef)CFDictionaryGetValue(q->q_item, desc->name); - if (attr) { - SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error); - if (access_control) { - query_set_access_control(q, access_control); - CFRelease(access_control); - } - } - } - - if (desc->kind == kSecDbAccessAttr) { - SecAccessControlRef access_control = SecAccessControlCreate(kCFAllocatorDefault, &q->q_error); - if (access_control) { - CFStringRef attr = (CFStringRef)CFDictionaryGetValue(q->q_item, desc->name); - if (attr) { - if (SecAccessControlSetProtection(access_control, attr, &q->q_error)) - query_set_access_control(q, access_control); - } - CFRelease(access_control); - } - } - } -} - -void query_add_or_attribute(const void *key, const void *value, Query *q) -{ - const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); - if (desc) { - CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name); - CFMutableArrayRef array = NULL; - if (oldValue) { - if (isArray(oldValue)) { - array = (CFMutableArrayRef)CFRetain(oldValue); - } else { - array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, oldValue); - } - CFDictionaryRemoveValue(q->q_item, desc->name); - } else { - array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - } - if (array) { - query_add_attribute_with_desc(desc, value, q); - CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name); - CFArrayAppendValue(array, newValue); - CFDictionarySetValue(q->q_item, desc->name, array); - CFRelease(array); - } - } -} - -void query_add_not_attribute(const void *key, const void *value, Query *q) -{ - const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); - if (desc) { - CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name); - CFMutableArrayRef array = NULL; - if (oldValue) { - if (isArray(oldValue)) { - array = (CFMutableArrayRef)CFRetain(oldValue); - } else { - // This should never run, as we shouldn't be turning a attr = value into a attr not in (value, value2) - secerror("negating %@ = %@ in query", desc->name, oldValue); - array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, kCFNull); - CFArrayAppendValue(array, oldValue); - } - CFDictionaryRemoveValue(q->q_item, desc->name); - } else { - array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, kCFNull); - } - if (array) { - query_add_attribute_with_desc(desc, value, q); - CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name); - CFArrayAppendValue(array, newValue); - CFDictionarySetValue(q->q_item, desc->name, array); - CFRelease(array); - } - } -} - - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string starting with 'm'. - value (ok) is a caller provided, non NULL CFTypeRef. - */ -static void query_add_match(const void *key, const void *value, Query *q) -{ - /* Record the match key, value in q_pairs. */ - --(q->q_match_begin); - q->q_pairs[q->q_match_begin].key = key; - q->q_pairs[q->q_match_begin].value = value; - - if (CFEqual(kSecMatchLimit, key)) { - /* Figure out what the value for kSecMatchLimit is if specified. */ - if (CFGetTypeID(value) == CFNumberGetTypeID()) { - if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit)) - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value); - } else if (CFEqual(kSecMatchLimitAll, value)) { - q->q_limit = kSecMatchUnlimited; - } else if (CFEqual(kSecMatchLimitOne, value)) { - q->q_limit = 1; - } else { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value); - } - } else if (CFEqual(kSecMatchIssuers, key) && - (CFGetTypeID(value) == CFArrayGetTypeID())) - { - CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if (canonical_issuers) { - CFIndex i, count = CFArrayGetCount(value); - for (i = 0; i < count; i++) { - CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i); - CFDataRef issuer_canonical = NULL; - if (CFDataGetTypeID() == CFGetTypeID(issuer_data)) - issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data); - if (issuer_canonical) { - CFArrayAppendValue(canonical_issuers, issuer_canonical); - CFRelease(issuer_canonical); - } - } - - if (CFArrayGetCount(canonical_issuers) > 0) { - q->q_match_issuer = canonical_issuers; - } else - CFRelease(canonical_issuers); - } - } else if (CFEqual(kSecMatchPolicy, key)) { - if (CFGetTypeID(value) != CFArrayGetTypeID()) { - SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute")); - return; - } - xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value); - if (!policiesArrayXPC) { - SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query")); - return; - } - - CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error); - xpc_release(policiesArrayXPC); - if (!policiesArray) - return; - - if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) { - CFRelease(policiesArray); - SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies")); - return; - } - - query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0)); - CFRelease(policiesArray); - } else if (CFEqual(kSecMatchValidOnDate, key)) { - if (CFGetTypeID(value) == CFNullGetTypeID()) { - CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - query_set_valid_on_date(q, date); - CFRelease(date); - } else if (CFGetTypeID(value) == CFDateGetTypeID()) { - query_set_valid_on_date(q, value); - } else { - SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute")); - return; - } - } else if (CFEqual(kSecMatchTrustedOnly, key)) { - if ((CFGetTypeID(value) == CFBooleanGetTypeID())) { - query_set_trusted_only(q, value); - } else { - SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute")); - return; - } - } -} - -static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) { - const SecDbClass *value; - if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() && - (value = kc_class_with_name(c_name)) && - (q->q_class == 0 || q->q_class == value)) { - q->q_class = value; - return true; - } - - if (error && !*error) - SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name); - - - return false; -} - -static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) { - CFStringRef c_name = NULL; - const void *value = CFDictionaryGetValue(query, kSecClass); - if (isString(value)) { - c_name = value; - } else { - value = CFDictionaryGetValue(query, kSecValuePersistentRef); - if (isData(value)) { - CFDataRef pref = value; - _SecItemParsePersistentRef(pref, &c_name, NULL, NULL); - } - } - - if (c_name && (value = kc_class_with_name(c_name))) { - return value; - } else { - if (c_name) - SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name); - else - SecError(errSecItemClassMissing, error, CFSTR("query missing class name")); - return NULL; - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string starting with 'c'. - value (ok) is a caller provided, non NULL CFTypeRef. - */ -static void query_add_class(const void *key, const void *value, Query *q) -{ - if (CFEqual(key, kSecClass)) { - query_set_class(q, value, &q->q_error); - } else { - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass); - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string starting with 'r'. - value (ok) is a caller provided, non NULL CFTypeRef. - */ -static void query_add_return(const void *key, const void *value, Query *q) -{ - ReturnTypeMask mask; - if (CFGetTypeID(value) != CFBooleanGetTypeID()) { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value); - return; - } - - int set_it = CFEqual(value, kCFBooleanTrue); - - if (CFEqual(key, kSecReturnData)) - mask = kSecReturnDataMask; - else if (CFEqual(key, kSecReturnAttributes)) - mask = kSecReturnAttributesMask; - else if (CFEqual(key, kSecReturnRef)) - mask = kSecReturnRefMask; - else if (CFEqual(key, kSecReturnPersistentRef)) - mask = kSecReturnPersistentRefMask; - else { - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key); - return; - } - - if ((q->q_return_type & mask) && !set_it) { - /* Clear out this bit (it's set so xor with the mask will clear it). */ - q->q_return_type ^= mask; - } else if (!(q->q_return_type & mask) && set_it) { - /* Set this bit. */ - q->q_return_type |= mask; - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string starting with 'u'. - value (ok since q_use_item_list is unused) is a caller provided, non - NULL CFTypeRef. - */ -static void query_add_use(const void *key, const void *value, Query *q) -{ - // Gotta use a string literal because we just outlawed this symbol on iOS - if (CFEqual(key, CFSTR("u_ItemList"))) { - /* TODO: Add sanity checking when we start using this. */ - q->q_use_item_list = value; - } else if (CFEqual(key, kSecUseTombstones)) { - if (CFGetTypeID(value) == CFBooleanGetTypeID()) { - q->q_use_tomb = value; - } else if (CFGetTypeID(value) == CFNumberGetTypeID()) { - q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse; - } else if (CFGetTypeID(value) == CFStringGetTypeID()) { - q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse; - } else { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key); - return; - } - } else if (CFEqual(key, kSecUseCredentialReference)) { - if (isData(value)) { - CFRetainAssign(q->q_use_cred_handle, value); - } else { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key); - return; - } - } else if (CFEqual(key, kSecUseAuthenticationUI)) { - if (isString(value)) { - q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value); - } else { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key); - return; - } -#if TARGET_OS_IPHONE - } else if (CFEqual(key, kSecUseSystemKeychain)) { -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - q->q_keybag = KEYBAG_DEVICE; -#endif - q->q_system_keychain = true; - } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) { - if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) { -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - q->q_keybag = KEYBAG_DEVICE; -#endif - } else { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key); - return; - } -#endif - } else { - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key); - return; - } -} - -static void query_set_data(const void *value, Query *q) { - if (!isData(value)) { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value); - } else { - q->q_data = value; - if (q->q_item) - CFDictionarySetValue(q->q_item, kSecValueData, value); - } -} - -static void query_set_token_persistent_ref(Query *q, CFDictionaryRef token_persistent_ref) { - if (token_persistent_ref) { - query_add_attribute(kSecAttrTokenID, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenID), q); - CFRetainAssign(q->q_token_object_id, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenOID)); - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, string starting with 'u'. - value (ok) is a caller provided, non NULL CFTypeRef. - */ -static void query_add_value(const void *key, const void *value, Query *q) -{ - if (CFEqual(key, kSecValueData)) { - query_set_data(value, q); -#ifdef NO_SERVER - } else if (CFEqual(key, kSecValueRef)) { - q->q_ref = value; - /* TODO: Add value type sanity checking. */ -#endif - } else if (CFEqual(key, kSecValuePersistentRef)) { - CFStringRef c_name; - CFDictionaryRef token_persistent_ref = NULL; - if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id, &token_persistent_ref)) { - query_set_class(q, c_name, &q->q_error); - query_set_token_persistent_ref(q, token_persistent_ref); - CFReleaseNull(token_persistent_ref); - } else - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value); - } else { - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key); - return; - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, unchecked. - value (ok) is a caller provided, unchecked. - */ -static void query_update_applier(const void *key, const void *value, - void *context) -{ - Query *q = (Query *)context; - /* If something went wrong there is no point processing any more args. */ - if (q->q_error) - return; - - /* Make sure we have a string key. */ - if (!isString(key)) { - SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key); - return; - } - - if (!value) { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key); - return; - } - - if (CFEqual(key, CFSTR("musr"))) { - secnotice("item", "update_applier: refusing to update musr"); - return; - } - - if (CFEqual(key, kSecValueData)) { - query_set_data(value, q); - } else { - query_add_attribute(key, value, q); - } -} - -/* AUDIT[securityd](done): - key (ok) is a caller provided, unchecked. - value (ok) is a caller provided, unchecked. - */ -static void query_applier(const void *key, const void *value, void *context) -{ - Query *q = (Query *)context; - /* If something went wrong there is no point processing any more args. */ - if (q->q_error) - return; - - /* Make sure we have a key. */ - if (!key) { - SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key")); - return; - } - - /* Make sure we have a value. */ - if (!value) { - SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key); - return; - } - - /* Figure out what type of key we are dealing with. */ - CFTypeID key_id = CFGetTypeID(key); - if (key_id == CFStringGetTypeID()) { - CFIndex key_len = CFStringGetLength(key); - /* String keys can be different things. The subtype is determined by: - length 4 strings are all attributes. Otherwise the first char - determines the type: - c: class must be kSecClass - m: match like kSecMatchPolicy - r: return like kSecReturnData - u: use keys - v: value - f: callbacks (ignored by the query applier) - */ - if (key_len == 4) { - /* attributes */ - query_add_attribute(key, value, q); - } else if (key_len > 1) { - // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with - // these matching rules. skip it for now, since it isn't filled in anyway. - if(CFEqualSafe(key, CFSTR("persistref"))) { - return; - } - - UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0); - switch (k_first_char) - { - case 'c': /* class */ - query_add_class(key, value, q); - break; - case 'm': /* match */ - query_add_match(key, value, q); - break; - case 'r': /* return */ - query_add_return(key, value, q); - break; - case 'u': /* use */ - query_add_use(key, value, q); - break; - case 'v': /* value */ - query_add_value(key, value, q); - break; - case 'f': - break; - default: - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key); - break; - } - } else { - SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key); - } - } else if (key_id == CFNumberGetTypeID()) { - /* Numeric keys are always (extended) attributes. */ - /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */ - query_add_attribute(key, value, q); - } else { - /* We only support string and number type keys. */ - SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key); - } -} - -static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) { - /* apsd are always dku. */ - if (CFEqual(agrp, CFSTR("com.apple.apsd"))) { - return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate; - } - /* All other certs or in the apple agrp is dk. */ - if (q->q_class == cert_class()) { - /* third party certs are always dk. */ - return kSecAttrAccessibleAlwaysPrivate; - } - /* The rest defaults to ak. */ - return kSecAttrAccessibleWhenUnlocked; -} - -void query_ensure_access_control(Query *q, CFStringRef agrp) { - if (q->q_access_control == 0) { - CFStringRef accessible = query_infer_keyclass(q, agrp); - query_add_attribute(kSecAttrAccessible, accessible, q); - } -} - -bool query_error(Query *q, CFErrorRef *error) { - CFErrorRef tmp = q->q_error; - q->q_error = NULL; - return SecErrorPropagate(tmp, error); -} - -bool query_destroy(Query *q, CFErrorRef *error) { - bool ok = query_error(q, error); - CFIndex ix, attr_count = query_attr_count(q); - for (ix = 0; ix < attr_count; ++ix) { - CFReleaseSafe(query_attr_at(q, ix).value); - } - CFReleaseSafe(q->q_item); - CFReleaseSafe(q->q_musrView); - CFReleaseSafe(q->q_primary_key_digest); - CFReleaseSafe(q->q_match_issuer); - CFReleaseSafe(q->q_access_control); - CFReleaseSafe(q->q_use_cred_handle); - CFReleaseSafe(q->q_caller_access_groups); - CFReleaseSafe(q->q_match_policy); - CFReleaseSafe(q->q_match_valid_on_date); - CFReleaseSafe(q->q_match_trusted_only); - CFReleaseSafe(q->q_token_object_id); - - free(q); - return ok; -} - -bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) { - if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) { - SecKeychainChanged(); - } - return query_destroy(q, error) && ok; -} - -/* Allocate and initialize a Query object for query. */ -Query *query_create(const SecDbClass *qclass, - CFDataRef musr, - CFDictionaryRef query, - CFErrorRef *error) -{ - if (!qclass) { - if (error && !*error) - SecError(errSecItemClassMissing, error, CFSTR("Missing class")); - return NULL; - } - - if (musr == NULL) - musr = SecMUSRGetSingleUserKeychainUUID(); - - /* Number of pairs we need is the number of attributes in this class - plus the number of keys in the dictionary, minus one for each key in - the dictionary that is a regular attribute. */ - CFIndex key_count = SecDbClassAttrCount(qclass); - if (key_count == 0) { - // Identities claim to have 0 attributes, but they really support any keys or cert attribute. - key_count = SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class()); - } - - if (query) { - key_count += CFDictionaryGetCount(query); - SecDbForEachAttr(qclass, attr) { - if (CFDictionaryContainsKey(query, attr->name)) - --key_count; - } - } - - if (key_count > QUERY_KEY_LIMIT) { - if (error && !*error) - { - secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT); - SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit")); - } - return NULL; - } - - Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count); - if (q == NULL) { - if (error && !*error) - SecError(errSecAllocate, error, CFSTR("Out of memory")); - return NULL; - } - - q->q_pairs_count = key_count; - q->q_musrView = (CFDataRef)CFRetain(musr); - q->q_uuid_from_primary_key = false; - q->q_keybag = KEYBAG_DEVICE; - q->q_class = qclass; - q->q_match_begin = q->q_match_end = key_count; - q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - return q; -} - -/* Parse query for a Query object q. */ -static bool query_parse_with_applier(Query *q, CFDictionaryRef query, - CFDictionaryApplierFunction applier, - CFErrorRef *error) { - CFDictionaryApplyFunction(query, applier, q); - return query_error(q, error); -} - -/* Parse query for a Query object q. */ -static bool query_parse(Query *q, CFDictionaryRef query, - CFErrorRef *error) { - return query_parse_with_applier(q, query, query_applier, error); -} - -/* Parse query for a Query object q. */ -bool query_update_parse(Query *q, CFDictionaryRef update, - CFErrorRef *error) { - return query_parse_with_applier(q, update, query_update_applier, error); -} - -Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) { - Query *q; - q = query_create(query_get_class(query, error), musr, query, error); - if (q) { - q->q_limit = limit; - if (!query_parse(q, query, error)) { - query_destroy(q, error); - return NULL; - } - if (!q->q_sync && !q->q_row_id && !q->q_token_object_id) { - /* query did not specify a kSecAttrSynchronizable attribute, - * and did not contain a persistent reference. */ - query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q); - } - } - return q; -} - - -void -query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) { - CFRetainAssign(q->q_caller_access_groups, caller_access_groups); -} - -void -query_set_policy(Query *q, SecPolicyRef policy) { - CFRetainAssign(q->q_match_policy, policy); -} - -void query_set_valid_on_date(Query *q, CFDateRef date) { - CFRetainAssign(q->q_match_valid_on_date, date); -} - -void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) { - CFRetainAssign(q->q_match_trusted_only, trusted_only); -} diff --git a/OSX/sec/securityd/SecDbQuery.h b/OSX/sec/securityd/SecDbQuery.h deleted file mode 100644 index dc132a0e..00000000 --- a/OSX/sec/securityd/SecDbQuery.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecDbQuery.h - The thing that does the stuff with the gibli. - */ - -#ifndef _SECURITYD_SECDBQUERY_H_ -#define _SECURITYD_SECDBQUERY_H_ - -#include "securityd/SecKeybagSupport.h" -#include "securityd/SecDbItem.h" - -__BEGIN_DECLS - -typedef struct Pair *SecDbPairRef; -typedef struct Query *SecDbQueryRef; - -/* Return types. */ -typedef uint32_t ReturnTypeMask; -enum -{ - kSecReturnDataMask = 1 << 0, - kSecReturnAttributesMask = 1 << 1, - kSecReturnRefMask = 1 << 2, - kSecReturnPersistentRefMask = 1 << 3, -}; - -/* Constant indicating there is no limit to the number of results to return. */ -enum -{ - kSecMatchUnlimited = kCFNotFound -}; - -typedef struct Pair -{ - const void *key; - const void *value; -} Pair; - -/* Nothing in this struct is retained since all the - values below are extracted from the dictionary passed in by the - caller. */ -typedef struct Query -{ - /* Class of this query. */ - const SecDbClass *q_class; - - /* Dictionary with all attributes and values in clear (to be encrypted). */ - CFMutableDictionaryRef q_item; - - /* q_pairs is an array of Pair structs. Elements with indices - [0, q_attr_end) contain attribute key value pairs. Elements with - indices [q_match_begin, q_match_end) contain match key value pairs. - Thus q_attr_end is the number of attrs in q_pairs and - q_match_begin - q_match_end is the number of matches in q_pairs. */ - CFIndex q_match_begin; - CFIndex q_match_end; - CFIndex q_attr_end; - - CFErrorRef q_error; - ReturnTypeMask q_return_type; - - CFDataRef q_data; - CFTypeRef q_ref; - sqlite_int64 q_row_id; - - CFArrayRef q_use_item_list; - CFBooleanRef q_use_tomb; - - /* Value of kSecMatchLimit key if present. */ - CFIndex q_limit; - - /* True if query contained a kSecAttrSynchronizable attribute, - * regardless of its actual value. If this is false, then we - * will add an explicit sync=0 to the query. */ - bool q_sync; - - // Set to true if we modified any item as part of executing this query - bool q_changed; - - // Set to true if we modified any synchronizable item as part of executing this query - bool q_sync_changed; - - /* Keybag handle to use for this item. */ - keybag_handle_t q_keybag; - - /* musr view to use when modifying the database */ - CFDataRef q_musrView; - - /* ACL and credHandle passed to the query. q_cred_handle contain LA context object. */ - SecAccessControlRef q_access_control; - CFDataRef q_use_cred_handle; - - // Flag indicating that ui-protected items should be simply skipped - // instead of reporting them to the client as an error. - bool q_skip_acl_items; - - // Set to true if any UUIDs generated by this query should be generated from the SHA2 digest of the item in question - bool q_uuid_from_primary_key; - - // Set this to a callback that, on an add query, will get passed along with the CKKS subsystem and called when the item makes it off-device (or doesn't) - __unsafe_unretained SecBoolCFErrorCallback q_add_sync_callback; - - // SHA1 digest of DER encoded primary key - CFDataRef q_primary_key_digest; - - CFArrayRef q_match_issuer; - - /* Caller acces groups for AKS */ - CFArrayRef q_caller_access_groups; - bool q_system_keychain; - int32_t q_sync_bubble; - bool q_spindump_on_failure; - - //policy for filtering certs and identities - SecPolicyRef q_match_policy; - //date for filtering certs and identities - CFDateRef q_match_valid_on_date; - //trusted only certs and identities - CFBooleanRef q_match_trusted_only; - //token persistent reference for filtering items is represented by token ID (in attrs) and token object ID - CFDataRef q_token_object_id; - - CFIndex q_pairs_count; - Pair q_pairs[]; -} Query; - -Query *query_create(const SecDbClass *qclass, CFDataRef musr, CFDictionaryRef query, CFErrorRef *error); -bool query_destroy(Query *q, CFErrorRef *error); -bool query_error(Query *q, CFErrorRef *error); -Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error); -void query_add_attribute(const void *key, const void *value, Query *q); -void query_add_or_attribute(const void *key, const void *value, Query *q); -void query_add_not_attribute(const void *key, const void *value, Query *q); -void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q); -void query_ensure_access_control(Query *q, CFStringRef agrp); -void query_pre_add(Query *q, bool force_date); -bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error); -CFIndex query_match_count(const Query *q); -CFIndex query_attr_count(const Query *q); -Pair query_attr_at(const Query *q, CFIndex ix); -bool query_update_parse(Query *q, CFDictionaryRef update, CFErrorRef *error); -const SecDbClass *kc_class_with_name(CFStringRef name); -void query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups); -void query_set_policy(Query *q, SecPolicyRef policy); -void query_set_valid_on_date(Query *q, CFDateRef policy); -void query_set_trusted_only(Query *q, CFBooleanRef trusted_only); - -CFDataRef -SecMUSRCopySystemKeychainUUID(void); - -CFDataRef -SecMUSRGetSystemKeychainUUID(void); - -CFDataRef -SecMUSRGetSingleUserKeychainUUID(void); - -bool -SecMUSRIsSingleUserView(CFDataRef uuid); - -CFDataRef -SecMUSRGetAllViews(void); - -bool -SecMUSRIsViewAllViews(CFDataRef musr); - -#if TARGET_OS_IPHONE -CFDataRef -SecMUSRCreateActiveUserUUID(uid_t uid); - -CFDataRef -SecMUSRCreateSyncBubbleUserUUID(uid_t uid); - -CFDataRef -SecMUSRCreateBothUserAndSystemUUID(uid_t uid); - -bool -SecMUSRGetBothUserAndSystemUUID(CFDataRef musr, uid_t *uid); - -#endif - - -__END_DECLS - -#endif /* _SECURITYD_SECDBQUERY_H_ */ diff --git a/OSX/sec/securityd/SecItemBackupServer.c b/OSX/sec/securityd/SecItemBackupServer.c deleted file mode 100644 index 476b3bd9..00000000 --- a/OSX/sec/securityd/SecItemBackupServer.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include -#include -#include "keychain/SecureObjectSync/SOSEnginePriv.h" -#include "keychain/SecureObjectSync/SOSPeer.h" -#include -#include -#include - -#include -#include - -static bool withDataSourceAndEngine(CFErrorRef *error, void (^action)(SOSDataSourceRef ds, SOSEngineRef engine)) { - bool ok = false; - SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); - if (ds) { - SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); - if (engine) { - action(ds, engine); - ok = true; - } - ok &= SOSDataSourceRelease(ds, error); - } - return ok; -} - -int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error) { - __block int fd = -1; - if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { - SOSEngineForPeerID(engine, backupName, error, ^(SOSTransactionRef txn, SOSPeerRef peer) { - fd = SOSPeerHandoffFD(peer, error); - }); - }) && fd >= 0) { - close(fd); - fd = -1; - } - return fd; -} - -bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifestData, CFErrorRef *error) { - __block bool ok = true; - ok &= withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { - ok = SOSEngineSetPeerConfirmedManifest(engine, backupName, keybagDigest, manifestData, error); - }); - return ok; -} - -CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error) { - __block CFArrayRef names = NULL; - if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { - names = SOSEngineCopyBackupPeerNames(engine, error); - })) { - CFReleaseNull(names); - } - return names; -} - -// TODO Move to datasource and remove dsRestoreObject -static bool SOSDataSourceWithBackup(SOSDataSourceRef ds, CFDataRef backup, keybag_handle_t bag_handle, CFErrorRef *error, void(^with)(SOSObjectRef item)) { - __block bool ok = true; - CFPropertyListRef plist = CFPropertyListCreateWithDERData(kCFAllocatorDefault, backup, kCFPropertyListImmutable, NULL, error); - CFDictionaryRef bdict = asDictionary(plist, error); - ok = (bdict != NULL); - if (ok) CFDictionaryForEach(bdict, ^(const void *key, const void *value) { - CFStringRef className = asString(key, error); - if (className) { - const SecDbClass *cls = kc_class_with_name(className); - if (cls) { - CFArrayRef items = asArray(value, error); - CFDataRef edata; - if (items) CFArrayForEachC(items, edata) { - SOSObjectRef item = (SOSObjectRef)SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, cls, edata, bag_handle, error); - if (item) { - with(item); - CFRelease(item); - } else { - ok = false; - } - } else { - ok = false; - } - } else { - ok &= SecError(errSecDecode, error, CFSTR("bad class %@ in backup"), className); - } - } else { - ok = false; - } - }); - CFReleaseSafe(plist); - return ok; -} - -bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error) { - // TODO: Decrypt and merge items in backup to dataSource - - __block bool ok = false; // return false if the bag_handle code fails. - CFDataRef aksKeybag = NULL; - CFMutableSetRef viewSet = NULL; - SOSBackupSliceKeyBagRef backupSliceKeyBag = NULL; - keybag_handle_t bag_handle = bad_keybag_handle; - - require(asData(secret, error), xit); - require(backupSliceKeyBag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, keybag, error), xit); - - if (peerID) { - bag_handle = SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, peerID, secret, error); - } else { - if (SOSBSKBIsDirect(backupSliceKeyBag)) { - bag_handle = SOSBSKBLoadAndUnlockWithDirectSecret(backupSliceKeyBag, secret, error); - } else { - bag_handle = SOSBSKBLoadAndUnlockWithWrappingSecret(backupSliceKeyBag, secret, error); - } - } - require(bag_handle != bad_keybag_handle, xit); - - // TODO: How do we know which views we are allow to restore - //viewSet = SOSAccountCopyRestorableViews(); - - ok = true; // Start from original code start point - otherwise begin in this nest of stuff - ok &= withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { - ok &= SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) { - ok &= SOSDataSourceWithBackup(ds, backup, bag_handle, error, ^(SOSObjectRef item) { - //if (SOSDataSourceIsInViewSet(item, viewSet)) { - SOSObjectRef mergedItem = NULL; - if (SOSDataSourceMergeObject(ds, txn, item, &mergedItem, error)) { - // if mergedItem == item then it was restored otherwise it was rejected by the conflict resolver. - CFReleaseSafe(mergedItem); - } - //} - }); - }); - }); - -xit: - if (bag_handle != bad_keybag_handle) - ok &= ks_close_keybag(bag_handle, error); - - CFReleaseSafe(backupSliceKeyBag); - CFReleaseSafe(aksKeybag); - CFReleaseSafe(viewSet); - - return ok; -} - - - - diff --git a/OSX/sec/securityd/SecItemBackupServer.h b/OSX/sec/securityd/SecItemBackupServer.h deleted file mode 100644 index 04607c60..00000000 --- a/OSX/sec/securityd/SecItemBackupServer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemBackupServer.h - This file declares backup restore functionality for SecItems. - */ - -#ifndef _SECURITYD_SECITEMBACKUPSERVER_H_ -#define _SECURITYD_SECITEMBACKUPSERVER_H_ - -#include -#include - -__BEGIN_DECLS - -int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error); -bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifest, CFErrorRef *error); -CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error); -bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error); - -__END_DECLS - -#endif /* _SECURITYD_SECITEMBACKUPSERVER_H_ */ diff --git a/OSX/sec/securityd/SecItemDataSource.c b/OSX/sec/securityd/SecItemDataSource.c deleted file mode 100644 index 4984c375..00000000 --- a/OSX/sec/securityd/SecItemDataSource.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecItemDataSource.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include - -#include -#include -#include -#include -#include -#include "keychain/SecureObjectSync/SOSDigestVector.h" -#include "keychain/SecureObjectSync/SOSEngine.h" -#include -#include -#include -#include -#include -#include -#include - -/* - * - * - * SecItemDataSource - * - * - */ -typedef struct SecItemDataSource *SecItemDataSourceRef; - -struct SecItemDataSource { - struct SOSDataSource ds; - SecDbRef db; // The database we operate on - CFStringRef name; // The name of the slice of the database we represent. -}; - - -static const SecDbClass *dsSyncedClassesV0Ptrs[] = { - NULL, - NULL, - NULL, -}; -static size_t dsSyncedClassesV0Size = (array_size(dsSyncedClassesV0Ptrs)); - -static const SecDbClass** dsSyncedClassesV0() { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dsSyncedClassesV0Ptrs[0] = genp_class(); - dsSyncedClassesV0Ptrs[1] = inet_class(); - dsSyncedClassesV0Ptrs[2] = keys_class(); - }); - return dsSyncedClassesV0Ptrs; -} - - -static const SecDbClass *dsSyncedClassesPtrs[] = { - NULL, - NULL, - NULL, - NULL, -}; -static const size_t dsSyncedClassesSize = array_size(dsSyncedClassesPtrs); - -static const SecDbClass** dsSyncedClasses() { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dsSyncedClassesPtrs[0] = genp_class(); // genp must be first! - dsSyncedClassesPtrs[1] = inet_class(); - dsSyncedClassesPtrs[2] = keys_class(); - dsSyncedClassesPtrs[3] = cert_class(); - }); - return dsSyncedClassesPtrs; -} - - -static bool SecDbItemSelectSHA1(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col), - void (^row)(sqlite3_stmt *stmt, bool *stop)) { - __block bool ok = true; - bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { - return attr->kind == kSecDbSHA1Attr; - }; - CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql); - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) && - SecDbStep(dbconn, stmt, error, ^(bool *stop){ row(stmt, stop); })); - }); - CFRelease(sql); - } else { - ok = false; - } - return ok; -} - -static SOSManifestRef SecItemDataSourceCopyManifestWithQueries(SecItemDataSourceRef ds, CFArrayRef queries, CFErrorRef *error) { - __block SOSManifestRef manifest = NULL; - __block CFErrorRef localError = NULL; - if (!kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { - __block struct SOSDigestVector dv = SOSDigestVectorInit; - Query *q; - bool ok = true; - CFArrayForEachC(queries, q) { - if (!(ok &= SecDbItemSelectSHA1(q, dbconn, &localError, ^bool(const SecDbAttr *attr) { - return CFDictionaryContainsKey(q->q_item, attr->name); - }, NULL, NULL, ^(sqlite3_stmt *stmt, bool *stop) { - const uint8_t *digest = sqlite3_column_blob(stmt, 0); - size_t digestLen = sqlite3_column_bytes(stmt, 0); - if (digestLen != SOSDigestSize) { - secerror("digest %zu bytes", digestLen); - } else { - SOSDigestVectorAppend(&dv, digest); - } - }))) { - secerror("SecDbItemSelectSHA1 failed: %@", localError); - break; - } - } - if (ok) { - // TODO: This code assumes that the passed in queries do not overlap, otherwise we'd need something to eliminate dupes: - //SOSDigestVectorUniqueSorted(&dv); - manifest = SOSManifestCreateWithDigestVector(&dv, &localError); - } - SOSDigestVectorFree(&dv); - return ok; - })) { - CFReleaseSafe(manifest); - } - CFErrorPropagate(localError, error); - return manifest; -} - -static Query *SecItemDataSourceAppendQuery(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, CFErrorRef *error) { - Query *q = query_create(qclass, NULL, NULL, error); - if (q) { - q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; - q->q_limit = kSecMatchUnlimited; - q->q_keybag = KEYBAG_DEVICE; - query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, q); - query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, q); - - if (noTombstones) { - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - } - - CFArrayAppendValue(queries, q); - } - return q; -} - -static Query *SecItemDataSourceAppendQueryWithClassAndViewHint(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFStringRef viewHint, CFErrorRef *error) { - Query *q = SecItemDataSourceAppendQuery(queries, qclass, noTombstones, error); - if (q) { - // For each attribute in current schema but not in v6, look for the - // default value of those attributes in the query, since old items - // will all have that as their values for these new attributes. - SecDbForEachAttr(qclass, attr) { - if (attr == &v7tkid || attr == &v7vwht) { - // attr is a primary key attribute added in schema version 7 or later - if (!allowTkid || attr != &v7tkid) { - if (attr == &v7vwht && viewHint) { - query_add_attribute_with_desc(attr, viewHint, q); - } else { - CFTypeRef value = SecDbAttrCopyDefaultValue(attr, &q->q_error); - if (value) { - query_add_attribute_with_desc(attr, value, q); - CFRelease(value); - } - } - } - } - } - } - return q; -} - -static Query *SecItemDataSourceAppendQueryWithClass(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFErrorRef *error) { - return SecItemDataSourceAppendQueryWithClassAndViewHint(queries, qclass, noTombstones, allowTkid, NULL, error); -} - -static Query *SecItemDataSourceAppendQueryWithClassAndAgrp(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFStringRef agrp, CFErrorRef *error) { - Query *q = SecItemDataSourceAppendQueryWithClass(queries, qclass, noTombstones, allowTkid, error); - if (q && agrp) { - query_add_attribute(kSecAttrAccessGroup, agrp, q); - } - return q; -} - -static bool SecItemDataSourceAppendQueriesForViewName(SecItemDataSourceRef ds, CFMutableArrayRef queries, CFStringRef compositeViewName, CFErrorRef *error) { - bool ok = true; - CFStringRef viewName; - bool noTombstones = CFStringHasSuffix(compositeViewName, CFSTR("-tomb")); - if (noTombstones) { - viewName = CFStringCreateWithSubstring(kCFAllocatorDefault, compositeViewName, CFRangeMake(0, CFStringGetLength(compositeViewName) - 5)); - } else { - viewName = CFRetain(compositeViewName); - } - - // short-circuit for CKKS-handled views here - if(!SOSViewInSOSSystem(viewName)) { - CFReleaseSafe(viewName); - return ok; - } - - const bool noTKID = false; - const bool allowTKID = true; - if (CFEqual(viewName, kSOSViewKeychainV0)) { - for (size_t class_ix = 0; class_ix < dsSyncedClassesV0Size; ++class_ix) { - SecItemDataSourceAppendQueryWithClass(queries, dsSyncedClassesV0()[class_ix], noTombstones, noTKID, error); - } - } else if (CFEqual(viewName, kSOSViewWiFi)) { - Query *q = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); - if (q) { - query_add_attribute(kSecAttrService, CFSTR("AirPort"), q); - } - } else if (CFEqual(viewName, kSOSViewAutofillPasswords)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, inet_class(), noTombstones, allowTKID, CFSTR("com.apple.cfnetwork"), error); - } else if (CFEqual(viewName, kSOSViewSafariCreditCards)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.safari.credit-cards"), error); - } else if (CFEqual(viewName, kSOSViewiCloudIdentity)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, keys_class(), noTombstones, allowTKID, CFSTR("com.apple.security.sos"), error); - } else if (CFEqual(viewName, kSOSViewBackupBagV0)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.sbd"), error); - } else if (CFEqual(viewName, kSOSViewOtherSyncable)) { - SecItemDataSourceAppendQueryWithClass(queries, cert_class(), noTombstones, allowTKID, error); - - Query *q1_genp = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); - query_add_not_attribute(kSecAttrService, CFSTR("AirPort"), q1_genp); - - Query *q2_genp = SecItemDataSourceAppendQueryWithClass(queries, genp_class(), noTombstones, allowTKID, error); - query_add_not_attribute(kSecAttrAccessGroup, CFSTR("apple"), q2_genp); - query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.safari.credit-cards"), q2_genp); - query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.sbd"), q2_genp); - - Query *q_inet = SecItemDataSourceAppendQueryWithClass(queries, inet_class(), noTombstones, allowTKID, error); - query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.cfnetwork"), q_inet); - - Query *q_keys = SecItemDataSourceAppendQueryWithClass(queries, keys_class(), noTombstones, allowTKID, error); - query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), q_keys); - } else { - // All other viewNames should match on the ViewHint attribute. - for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { - SecItemDataSourceAppendQueryWithClassAndViewHint(queries, dsSyncedClasses()[class_ix], noTombstones, allowTKID, viewName, error); - } - } - - CFReleaseSafe(viewName); - return ok; -} - -static SOSManifestRef SecItemDataSourceCopyManifestWithViewNameSet(SecItemDataSourceRef ds, CFSetRef viewNames, CFErrorRef *error) { - CFMutableArrayRef queries = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - SOSManifestRef manifest = NULL; - __block bool ok = true; - CFSetForEach(viewNames, ^(const void *value) { - CFStringRef viewName = (CFStringRef)value; - ok &= SecItemDataSourceAppendQueriesForViewName(ds, queries, viewName, error); - }); - if (ok) - manifest = SecItemDataSourceCopyManifestWithQueries(ds, queries, error); - Query *q; - CFArrayForEachC(queries, q) { - CFErrorRef localError = NULL; - if (!query_destroy(q, &localError)) { - secerror("query_destroy failed: %@", localError); - CFErrorPropagate(localError, error); - CFReleaseNull(manifest); - } - } - CFReleaseSafe(queries); - return manifest; -} - -// Return the newest object (conflict resolver) -static SecDbItemRef SecItemDataSourceCopyMergedItem(SecDbItemRef item1, SecDbItemRef item2, CFErrorRef *error) { - CFErrorRef localError = NULL; - SecDbItemRef result = NULL; - CFDateRef m1, m2; - const SecDbAttr *desc = SecDbAttrWithKey(SecDbItemGetClass(item1), kSecAttrModificationDate, error); - m1 = SecDbItemGetValue(item1, desc, &localError); - m2 = SecDbItemGetValue(item2, desc, &localError); - if (m1 && m2) switch (CFDateCompare(m1, m2, NULL)) { - case kCFCompareGreaterThan: - result = item1; - break; - case kCFCompareLessThan: - result = item2; - break; - case kCFCompareEqualTo: - { - // Return the item with the smallest digest. - CFDataRef digest1 = SecDbItemGetSHA1(item1, &localError); - CFDataRef digest2 = SecDbItemGetSHA1(item2, &localError); - if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) { - case kCFCompareGreaterThan: - case kCFCompareEqualTo: - result = item2; - break; - case kCFCompareLessThan: - result = item1; - break; - } else if (SecErrorGetOSStatus(localError) == errSecDecode) { - if (digest1) result = item1; - if (digest2) result = item2; - } - break; - } - } else if (SecErrorGetOSStatus(localError) == errSecDecode) { - // If one of the two objects has an unparsable date, - // the object with the parsable date wins. - if (m1) result = item1; - if (m2) result = item2; - } - - if (localError) { - if (!result && error && !*error) - *error = localError; - else - CFRelease(localError); - } - return CFRetainSafe(result); -} - -// -// MARK: DataSource protocol implementation -// - -static CFStringRef dsGetName(SOSDataSourceRef data_source) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - return ds->name; -} - -static void dsAddNotifyPhaseBlock(SOSDataSourceRef data_source, SOSDataSourceNotifyBlock notifyBlock) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - SecDbAddNotifyPhaseBlock(ds->db, ^(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) - { - notifyBlock(&ds->ds, (SOSTransactionRef)dbconn, phase, source, changes); - }); -} - -static SOSManifestRef dsCopyManifestWithViewNameSet(SOSDataSourceRef data_source, CFSetRef viewNameSet, CFErrorRef *error) { - struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source; - return SecItemDataSourceCopyManifestWithViewNameSet(ds, viewNameSet, error); -} - -static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, SOSManifestRef manifest, CFErrorRef *error, void (^handle_object)(CFDataRef key, SOSObjectRef object, bool *stop)) { - struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source; - __block bool result = true; - const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(genp_class(), kSecDbSHA1Attr, error); - if (!sha1Attr) return false; - bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { - return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; - }; - bool (^use_attr_in_where)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { - return attr->kind == kSecDbSHA1Attr; - }; - Query *select_queries[dsSyncedClassesSize] = {}; - CFStringRef select_sql[dsSyncedClassesSize] = {}; - sqlite3_stmt *select_stmts[dsSyncedClassesSize] = {}; - - __block Query **queries = select_queries; - __block CFStringRef *sqls = select_sql; - __block sqlite3_stmt **stmts = select_stmts; - - bool (^readBlock)(SecDbConnectionRef dbconn) = ^bool(SecDbConnectionRef dbconn) - { - // Setup - for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { - result = (result - && (queries[class_ix] = query_create(dsSyncedClasses()[class_ix], NULL, NULL, error)) - && (sqls[class_ix] = SecDbItemCopySelectSQL(queries[class_ix], return_attr, use_attr_in_where, NULL)) - && (stmts[class_ix] = SecDbCopyStmt(dbconn, sqls[class_ix], NULL, error))); - } - - if (result) SOSManifestForEach(manifest, ^(CFDataRef key, bool *stop) { - __block SecDbItemRef item = NULL; - for (size_t class_ix = 0; result && !item && class_ix < dsSyncedClassesSize; ++class_ix) { - CFDictionarySetValue(queries[class_ix]->q_item, sha1Attr->name, key); - result = SecDbItemSelectBind(queries[class_ix], stmts[class_ix], error, use_attr_in_where, NULL); - if (result) { - result &= SecDbStep(dbconn, stmts[class_ix], error, ^(bool *unused_stop) { - item = SecDbItemCreateWithStatement(kCFAllocatorDefault, queries[class_ix]->q_class, stmts[class_ix], KEYBAG_DEVICE, error, return_attr); - }); - } - if (result) - result &= SecDbReset(stmts[class_ix], error); - } - handle_object(key, (SOSObjectRef)item, stop); - CFReleaseSafe(item); - }); - - // Cleanup - for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { - result &= SecDbReleaseCachedStmt(dbconn, sqls[class_ix], stmts[class_ix], error); - CFReleaseSafe(sqls[class_ix]); - if (queries[class_ix]) - result &= query_destroy(queries[class_ix], error); - } - - return true; - }; - - if (txn) { - readBlock((SecDbConnectionRef)txn); - } else { - result &= kc_with_custom_db(false, true, ds->db, error, readBlock); - } - - return result; -} - -static bool dsRelease(SOSDataSourceRef data_source, CFErrorRef *error) { - // We never release our dataSource since it's tracking changes - // to the keychain for the engine and its peers. - return true; -} - -static SOSObjectRef objectCreateWithPropertyList(CFDictionaryRef plist, CFErrorRef *error) { - SecDbItemRef item = NULL; - const SecDbClass *class = NULL; - CFTypeRef cname = CFDictionaryGetValue(plist, kSecClass); - if (cname) { - class = kc_class_with_name(cname); - if (class) { - item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, class, plist, KEYBAG_DEVICE, error); - } else { - SecError(errSecNoSuchClass, error, CFSTR("can find class named: %@"), cname); - } - } else { - SecError(errSecItemClassMissing, error, CFSTR("query missing %@ attribute"), kSecClass); - } - return (SOSObjectRef)item; -} - -static CFDataRef copyObjectDigest(SOSObjectRef object, CFErrorRef *error) { - SecDbItemRef item = (SecDbItemRef) object; - CFDataRef digest = SecDbItemGetSHA1(item, error); - CFRetainSafe(digest); - return digest; -} - -static CFDateRef copyObjectModDate(SOSObjectRef object, CFErrorRef *error) { - SecDbItemRef item = (SecDbItemRef) object; - CFDateRef modDate = SecDbItemGetValueKind(item, kSecDbModificationDateAttr, NULL); - CFRetainSafe(modDate); - return modDate; -} - -static CFDictionaryRef objectCopyPropertyList(SOSObjectRef object, CFErrorRef *error) { - SecDbItemRef item = (SecDbItemRef) object; - CFMutableDictionaryRef secretDataDict = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error); - CFMutableDictionaryRef cryptoDataDict = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); - CFMutableDictionaryRef authDataDict = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); - - if (cryptoDataDict) { - if (authDataDict) { - CFDictionaryForEach(authDataDict, ^(const void *key, const void *value) { - CFDictionarySetValue(cryptoDataDict, key, value); - }); - } - if (secretDataDict) { - CFDictionaryForEach(secretDataDict, ^(const void* key, const void* value) { - CFDictionarySetValue(cryptoDataDict, key, value); - }); - } - CFDictionaryAddValue(cryptoDataDict, kSecClass, SecDbItemGetClass(item)->name); - } - - CFReleaseNull(secretDataDict); - CFReleaseNull(authDataDict); - return cryptoDataDict; -} - -static bool dsWith(SOSDataSourceRef data_source, CFErrorRef *error, SOSDataSourceTransactionSource source, bool onCommitQueue, void(^transaction)(SOSTransactionRef txn, bool *commit)) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - __block bool ok = true; - ok &= kc_with_custom_db(true, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { - return SecDbTransaction(dbconn, - source == kSOSDataSourceAPITransaction ? kSecDbExclusiveTransactionType : kSecDbExclusiveRemoteSOSTransactionType, - error, ^(bool *commit) { - if (onCommitQueue) { - SecDbPerformOnCommitQueue(dbconn, false, ^{ - transaction((SOSTransactionRef)dbconn, commit); - }); - } else { - transaction((SOSTransactionRef)dbconn, commit); - } - }); - }); - return ok; -} - -static bool dsReadWith(SOSDataSourceRef data_source, CFErrorRef *error, SOSDataSourceTransactionSource source, void(^perform)(SOSTransactionRef txn)) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - __block bool ok = true; - ok &= kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { - SecDbPerformOnCommitQueue(dbconn, false, ^{ - perform((SOSTransactionRef)dbconn); - }); - return true; - }); - return ok; -} - -static SOSMergeResult dsMergeObject(SOSTransactionRef txn, SOSObjectRef peersObject, SOSObjectRef *mergedObject, CFErrorRef *error) { - SecDbConnectionRef dbconn = (SecDbConnectionRef)txn; - SecDbItemRef peersItem = (SecDbItemRef)peersObject; - __block SOSMergeResult mr = kSOSMergeFailure; - __block SecDbItemRef mergedItem = NULL; - __block SecDbItemRef replacedItem = NULL; - __block CFErrorRef localError = NULL; - __block bool attemptedMerge = false; - - if (!peersItem || !dbconn) - return kSOSMergeFailure; - if (!SecDbItemSetKeybag(peersItem, KEYBAG_DEVICE, &localError)) { - secnotice("ds", "kSOSMergeFailure => SecDbItemSetKeybag: %@", localError); - CFErrorPropagate(localError, error); - return kSOSMergeFailure; - } - - bool insertedOrReplaced = SecDbItemInsertOrReplace(peersItem, dbconn, &localError, ^(SecDbItemRef myItem, SecDbItemRef *replace) { - // An item with the same primary key as dbItem already exists in the the database. That item is old_item. - // Let the conflict resolver choose which item to keep. - attemptedMerge = true; - mergedItem = SecItemDataSourceCopyMergedItem(peersItem, myItem, &localError); - if (!mergedItem) { - mr = kSOSMergeFailure; - return; // from block - } - if (mergedObject) - *mergedObject = (SOSObjectRef)CFRetain(mergedItem); - if (CFEqual(mergedItem, myItem)) { - // Conflict resolver choose my (local) item - if (SecDbItemIsEngineInternalState(myItem)) - secdebug ("ds", "Conflict resolver chose my (local) item: %@", myItem); - else - secnotice("ds", "Conflict resolver chose my (local) item: %@", myItem); - mr = kSOSMergeLocalObject; - } else { - CFRetainAssign(replacedItem, myItem); - *replace = CFRetainSafe(mergedItem); - if (CFEqual(mergedItem, peersItem)) { - // Conflict resolver chose peer's item - if (SecDbItemIsEngineInternalState(peersItem)) - secdebug ("ds", "Conflict resolver chose peers item: %@", peersItem); - else - secnotice("ds", "Conflict resolver chose peers item: %@", peersItem); - mr = kSOSMergePeersObject; - } else { - // Conflict resolver created a new item; return it to our caller - if (SecDbItemIsEngineInternalState(mergedItem)) - secdebug ("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); - else - secnotice("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); - mr = kSOSMergeCreatedObject; - } - } - }); - - if (insertedOrReplaced && !attemptedMerge) { - // SecDbItemInsertOrReplace succeeded and conflict block was never called -> insert succeeded. - // We have peersItem in the database so we need to report that - secnotice("ds", "Insert succeeded for: %@", peersItem); - mr = kSOSMergePeersObject; - - // Report only if we had an error, too. Shouldn't happen in practice. - if (localError) { - secnotice("ds", "kSOSMergeFailure => kSOSMergePeersObject, %@", localError); - CFReleaseSafe(localError); - } - } - - if (localError && !SecErrorIsSqliteDuplicateItemError(localError)) { - secnotice("ds", "dsMergeObject failed: mr=%ld, %@", mr, localError); - // We should probably always propogate this, but for now we are only logging - // See rdar://problem/26451072 for case where we might need to propogate - if (mr == kSOSMergeFailure) { - CFErrorPropagate(localError, error); - localError = NULL; - } - } - - CFReleaseSafe(mergedItem); - CFReleaseSafe(replacedItem); - CFReleaseSafe(localError); - return mr; -} - - /* - Truthy backup format is a dictionary from sha1 => item. - Each item has class, hash and item data. - - TODO: sha1 is included as binary blob to avoid parsing key. - */ -enum { - kSecBackupIndexHash = 0, - kSecBackupIndexClass, - kSecBackupIndexData, -}; - -static const void *kSecBackupKeys[] = { - [kSecBackupIndexHash] = kSecItemBackupHashKey, - [kSecBackupIndexClass] = kSecItemBackupClassKey, - [kSecBackupIndexData] = kSecItemBackupDataKey -}; - -static CFDictionaryRef objectCopyBackup(SOSObjectRef object, uint64_t handle, CFErrorRef *error) { - const void *values[array_size(kSecBackupKeys)]; - SecDbItemRef item = (SecDbItemRef)object; - CFDictionaryRef backup_item = NULL; - - if ((values[kSecBackupIndexHash] = SecDbItemGetSHA1(item, error))) { - if ((values[kSecBackupIndexData] = SecDbItemCopyEncryptedDataToBackup(item, handle, error))) { - values[kSecBackupIndexClass] = SecDbItemGetClass(item)->name; - backup_item = CFDictionaryCreate(kCFAllocatorDefault, kSecBackupKeys, values, array_size(kSecBackupKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFRelease(values[kSecBackupIndexData]); - } - } - - return backup_item; -} - -static CFDataRef dsCopyStateWithKey(SOSDataSourceRef data_source, CFStringRef key, CFStringRef pdmn, SOSTransactionRef txn, CFErrorRef *error) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrAccessGroup, kSOSInternalAccessGroup, - kSecAttrAccount, key, - kSecAttrService, dataSourceID, - kSecAttrAccessible, pdmn, - kSecAttrSynchronizable, kCFBooleanFalse, - NULL); - CFReleaseSafe(dataSourceID); - __block CFDataRef data = NULL; - SecDbQueryRef query = query_create(genp_class(), NULL, dict, error); - if (query) { - if (query->q_item) CFReleaseSafe(query->q_item); - query->q_item = dict; - bool (^read_it)(SecDbConnectionRef dbconn) = ^(SecDbConnectionRef dbconn) { - return SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { - return CFDictionaryContainsKey(dict, attr->name); - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - secnotice("ds", "found item for key %@@%@", key, pdmn); - data = CFRetainSafe(SecDbItemGetValue(item, &v6v_Data, error)); - }); - }; - if (txn) { - read_it((SecDbConnectionRef) txn); - } else { - kc_with_custom_db(false, true, ds->db, error, read_it); - } - query_destroy(query, error); - } else { - CFReleaseSafe(dict); - } - if (!data) secnotice("ds", "failed to load %@@%@ state: %@", key, pdmn, error ? *error : NULL); - return data; -} - -static CFDataRef dsCopyItemDataWithKeys(SOSDataSourceRef data_source, CFDictionaryRef keys, CFErrorRef *error) { - /* - Values for V0 are: - kSecAttrAccessGroup ==> CFSTR("com.apple.sbd") - kSecAttrAccessible ==> kSecAttrAccessibleWhenUnlocked - kSecAttrAccount ==> CFSTR("SecureBackupPublicKeybag") - kSecAttrService ==> CFSTR("SecureBackupService") - - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrAccessGroup, CFSTR("com.apple.sbd"), - kSecAttrAccount, account, - kSecAttrService, service, - kSecAttrAccessible, pdmn, - kSecAttrSynchronizable, kCFBooleanTrue, - NULL); - */ - - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, keys); - __block CFDataRef data = NULL; - SecDbQueryRef query = query_create(genp_class(), NULL, dict, error); - if (query) { - if (query->q_item) CFReleaseSafe(query->q_item); - query->q_item = dict; - kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { - return SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { - return CFDictionaryContainsKey(dict, attr->name); - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - secnotice("ds", "found item for keys %@", keys); - data = CFRetainSafe(SecDbItemGetValue(item, &v6v_Data, error)); - }); - }); - query_destroy(query, error); - } else { - CFReleaseSafe(dict); - } - if (!data) secnotice("ds", "failed to load item %@: %@", keys, error ? *error : NULL); - return data; -} - -static bool dsSetStateWithKey(SOSDataSourceRef data_source, SOSTransactionRef txn, CFStringRef key, CFStringRef pdmn, CFDataRef state, CFErrorRef *error) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrAccessGroup, kSOSInternalAccessGroup, - kSecAttrAccount, key, - kSecAttrService, dataSourceID, - kSecAttrAccessible, pdmn, - kSecAttrSynchronizable, kCFBooleanFalse, - kSecValueData, state, - NULL); - CFReleaseSafe(dataSourceID); - SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); - SOSMergeResult mr = dsMergeObject(txn, (SOSObjectRef)item, NULL, error); - if (mr == kSOSMergeFailure) secerror("failed to save %@@%@ state: %@", key, pdmn, error ? *error : NULL); - CFReleaseSafe(item); - CFReleaseSafe(dict); - return mr != kSOSMergeFailure; -} - -static bool dsDeleteStateWithKey(SOSDataSourceRef data_source, CFStringRef key, CFStringRef pdmn, SOSTransactionRef txn, CFErrorRef *error) { - SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; - CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, - kSecAttrAccessGroup, kSOSInternalAccessGroup, - kSecAttrAccount, key, - kSecAttrService, dataSourceID, - kSecAttrAccessible, pdmn, - kSecAttrSynchronizable, kCFBooleanFalse, - NULL); - CFReleaseSafe(dataSourceID); - SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); - bool ok = SecDbItemDoDeleteSilently(item, (SecDbConnectionRef)txn, error); - CFReleaseNull(dict); - CFReleaseSafe(item); - return ok; -} - -static bool dsRestoreObject(SOSTransactionRef txn, uint64_t handle, CFDictionaryRef item, CFErrorRef *error) { - CFStringRef item_class = CFDictionaryGetValue(item, kSecItemBackupClassKey); - CFDataRef data = CFDictionaryGetValue(item, kSecItemBackupDataKey); - const SecDbClass *dbclass = NULL; - - if (!item_class || !data) - return SecError(errSecDecode, error, CFSTR("no class or data in object")); - - dbclass = kc_class_with_name(item_class); - if (!dbclass) - return SecError(errSecDecode, error, CFSTR("no such class %@; update kc_class_with_name "), item_class); - - SecDbItemRef dbitem = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, data, (keybag_handle_t)handle, error); - bool ok = dbitem && (dsMergeObject(txn, (SOSObjectRef)dbitem, NULL, error) != kSOSMergeFailure); - CFReleaseSafe(dbitem); - return ok; -} - -SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, CFStringRef name, CFErrorRef *error) { - SecItemDataSourceRef ds = calloc(1, sizeof(struct SecItemDataSource)); - ds->ds.dsGetName = dsGetName; - ds->ds.dsAddNotifyPhaseBlock = dsAddNotifyPhaseBlock; - ds->ds.dsCopyManifestWithViewNameSet = dsCopyManifestWithViewNameSet; - ds->ds.dsCopyStateWithKey = dsCopyStateWithKey; - ds->ds.dsCopyItemDataWithKeys = dsCopyItemDataWithKeys; - - ds->ds.dsForEachObject = dsForEachObject; - ds->ds.dsWith = dsWith; - ds->ds.dsReadWith = dsReadWith; - ds->ds.dsRelease = dsRelease; - - ds->ds.dsMergeObject = dsMergeObject; - ds->ds.dsSetStateWithKey = dsSetStateWithKey; - ds->ds.dsDeleteStateWithKey = dsDeleteStateWithKey; - ds->ds.dsRestoreObject = dsRestoreObject; - - // Object field accessors - ds->ds.objectCopyDigest = copyObjectDigest; - ds->ds.objectCopyModDate = copyObjectModDate; - - // Object encode and decode. - ds->ds.objectCreateWithPropertyList = objectCreateWithPropertyList; - ds->ds.objectCopyPropertyList = objectCopyPropertyList; - ds->ds.objectCopyBackup = objectCopyBackup; - - ds->db = CFRetainSafe(db); - ds->name = CFRetainSafe(name); - - // Do this after the ds is fully setup so the engine can query us right away. - ds->ds.engine = SOSEngineCreate(&ds->ds, error); - if (!ds->ds.engine) { - free(ds); - ds = NULL; - } - return &ds->ds; -} - -static CFStringRef SecItemDataSourceFactoryCopyName(SOSDataSourceFactoryRef factory) -{ - // This is the name of the v0 datasource, a.k.a. "ak" - return kSecAttrAccessibleWhenUnlocked; -} - -struct SecItemDataSourceFactory { - struct SOSDataSourceFactory factory; - CFMutableDictionaryRef dsCache; - dispatch_queue_t queue; - SecDbRef db; -}; - -static SOSDataSourceRef SecItemDataSourceFactoryCopyDataSource(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, CFErrorRef *error) -{ - struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory; - __block SOSDataSourceRef dataSource = NULL; - dispatch_sync(f->queue, ^{ - dataSource = (SOSDataSourceRef)CFDictionaryGetValue(f->dsCache, dataSourceName); - if (!dataSource && f->db) { - dataSource = (SOSDataSourceRef)SecItemDataSourceCreate(f->db, dataSourceName, error); - CFDictionarySetValue(f->dsCache, dataSourceName, dataSource); - } - }); - return dataSource; -} - -static void SecItemDataSourceFactoryDispose(SOSDataSourceFactoryRef factory) -{ - // Nothing to do here. -} - -static void SecItemDataSourceFactoryCircleChanged(SOSDataSourceFactoryRef factory, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs) { - CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(factory, dsName, NULL); - if (engine) - SOSEngineCircleChanged(engine, myPeerID, trustedPeerIDs, untrustedPeerIDs); - CFReleaseSafe(dsName); -} - -// Fire up the SOSEngines so they can -static bool SOSDataSourceFactoryStartYourEngines(SOSDataSourceFactoryRef factory) { -#if OCTAGON - if(!SecCKKSTestDisableSOS() && !SecCKKSTestsEnabled()) { -#endif // OCTAGON - bool ok = true; - CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); - CFErrorRef localError = NULL; - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(factory, dsName, &localError); - if (!ds) - secerror("create_datasource %@ failed %@", dsName, localError); - CFReleaseNull(localError); - SOSDataSourceRelease(ds, &localError); - CFReleaseNull(localError); - CFReleaseNull(dsName); - return ok; -#if OCTAGON - } else { - return false; - } -#endif // OCTAGON -} - -static SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) { - struct SecItemDataSourceFactory *dsf = calloc(1, sizeof(struct SecItemDataSourceFactory)); - dsf->factory.copy_name = SecItemDataSourceFactoryCopyName; - dsf->factory.create_datasource = SecItemDataSourceFactoryCopyDataSource; - dsf->factory.release = SecItemDataSourceFactoryDispose; - dsf->factory.circle_changed = SecItemDataSourceFactoryCircleChanged; - - dsf->dsCache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); - dsf->queue = dispatch_queue_create("dsf queue", DISPATCH_QUEUE_SERIAL); - dsf->db = CFRetainSafe(db); - if (!SOSDataSourceFactoryStartYourEngines(&dsf->factory)) - secerror("Failed to start engines, gonna lose the race."); - return &dsf->factory; -} - -SOSDataSourceFactoryRef SecItemDataSourceFactoryGetShared(SecDbRef db) { - static dispatch_once_t sDSFQueueOnce; - static dispatch_queue_t sDSFQueue; - static CFMutableDictionaryRef sDSTable = NULL; - - dispatch_once(&sDSFQueueOnce, ^{ - sDSFQueue = dispatch_queue_create("dataSourceFactory queue", DISPATCH_QUEUE_SERIAL); - sDSTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); - }); - - __block SOSDataSourceFactoryRef result = NULL; - dispatch_sync(sDSFQueue, ^{ - if(db) { - CFStringRef dbPath = SecDbGetPath(db); - if(dbPath) { - result = (SOSDataSourceFactoryRef) CFDictionaryGetValue(sDSTable, dbPath); - - if(!result) { - result = SecItemDataSourceFactoryCreate(db); - CFDictionaryAddValue(sDSTable, dbPath, result); - } - } - } - }); - - return result; -} - -// TODO: These should move to SecItemServer.c - -void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object) { - SOSObjectRef item = objectCreateWithPropertyList(object, NULL); - if (item) { - CFStringRef itemDesc = CFCopyDescription(item); - if (itemDesc) { - CFStringAppend(desc, itemDesc); - CFReleaseSafe(itemDesc); - } - CFRelease(item); - } -} - -SOSManifestRef SOSCreateManifestWithBackup(CFDictionaryRef backup, CFErrorRef *error) -{ - __block struct SOSDigestVector dv = SOSDigestVectorInit; - if (backup) { - CFDictionaryForEach(backup, ^void (const void * key, const void * value) { - if (isDictionary(value)) { - /* converting key back to binary blob is horrible */ - CFDataRef sha1 = CFDictionaryGetValue(value, kSecItemBackupHashKey); - if (isData(sha1) && CFDataGetLength(sha1) == CCSHA1_OUTPUT_SIZE) - SOSDigestVectorAppend(&dv, CFDataGetBytePtr(sha1)); - } - }); - } - SOSManifestRef manifest = SOSManifestCreateWithDigestVector(&dv, error); - SOSDigestVectorFree(&dv); - return manifest; -} diff --git a/OSX/sec/securityd/SecItemDataSource.h b/OSX/sec/securityd/SecItemDataSource.h deleted file mode 100644 index fab2678e..00000000 --- a/OSX/sec/securityd/SecItemDataSource.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemDataSource.h - The functions provided in SecDbItem provide an implementation of a - SOSDataSource required by the Secure Object Syncing code. - */ - -#ifndef _SECURITYD_SECITEMDATASOURCE_H_ -#define _SECURITYD_SECITEMDATASOURCE_H_ - -#include "keychain/SecureObjectSync/SOSDataSource.h" -#include - -__BEGIN_DECLS - -SOSDataSourceFactoryRef SecItemDataSourceFactoryGetShared(SecDbRef db); - -SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, CFStringRef name, CFErrorRef *error); - -SOSManifestRef SOSCreateManifestWithBackup(CFDictionaryRef backup, CFErrorRef *error); - -// Hack to log objects from inside SOS code -void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object); - - -__END_DECLS - -#endif /* _SECURITYD_SECITEMDATASOURCE_H_ */ diff --git a/OSX/sec/securityd/SecItemDb.c b/OSX/sec/securityd/SecItemDb.c deleted file mode 100644 index 865202cc..00000000 --- a/OSX/sec/securityd/SecItemDb.c +++ /dev/null @@ -1,2212 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecItemDb.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#if TARGET_DARWINOS -#undef OCTAGON -#undef SECUREOBJECTSYNC -#undef SHAREDWEBCREDENTIALS -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sec_action.h" - -#include "keychain/ckks/CKKS.h" - -#define kSecBackupKeybagUUIDKey CFSTR("keybag-uuid") - -const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, - CFTypeRef key, - CFErrorRef *error) { - /* Special case: identites can have all attributes of either cert - or keys. */ - if (c == identity_class()) { - const SecDbAttr *desc; - if (!(desc = SecDbAttrWithKey(cert_class(), key, 0))) - desc = SecDbAttrWithKey(keys_class(), key, error); - return desc; - } - - if (isString(key)) { - SecDbForEachAttr(c, a) { - if (CFEqual(a->name, key)) - return a; - } - if (CFEqual(kSecUseDataProtectionKeychain, key)) { - return NULL; /* results in no ops for this attribute */ - } - } - - SecError(errSecNoSuchAttr, error, CFSTR("attribute %@ not found in class %@"), key, c->name); - - return NULL; -} - -bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)(void)) { - return kc_transaction_type(dbt, kSecDbExclusiveTransactionType, error, perform); -} - -bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)(void)) { - __block bool ok = true; - return ok && SecDbTransaction(dbt, type, error, ^(bool *commit) { - ok = *commit = perform(); - }); -} - -static CFStringRef SecDbGetKindSQL(SecDbAttrKind kind) { - switch (kind) { - case kSecDbBlobAttr: - case kSecDbDataAttr: - case kSecDbUUIDAttr: - case kSecDbSHA1Attr: - case kSecDbPrimaryKeyAttr: - case kSecDbEncryptedDataAttr: - return CFSTR("BLOB"); - case kSecDbAccessAttr: - case kSecDbStringAttr: - return CFSTR("TEXT"); - case kSecDbNumberAttr: - case kSecDbSyncAttr: - case kSecDbTombAttr: - return CFSTR("INTEGER"); - case kSecDbDateAttr: - case kSecDbCreationDateAttr: - case kSecDbModificationDateAttr: - return CFSTR("REAL"); - case kSecDbRowIdAttr: - return CFSTR("INTEGER PRIMARY KEY AUTOINCREMENT"); - case kSecDbAccessControlAttr: - case kSecDbUTombAttr: - /* This attribute does not exist in the DB. */ - return NULL; - } -} - -static void SecDbAppendUnique(CFMutableStringRef sql, CFStringRef value, bool *haveUnique) { - assert(haveUnique); - if (!*haveUnique) - CFStringAppend(sql, CFSTR("UNIQUE(")); - - SecDbAppendElement(sql, value, haveUnique); -} - -static void SecDbAppendCreateTableWithClass(CFMutableStringRef sql, const SecDbClass *c) { - CFStringAppendFormat(sql, 0, CFSTR("CREATE TABLE %@("), c->name); - SecDbForEachAttrWithMask(c,desc,kSecDbInFlag) { - CFStringAppendFormat(sql, 0, CFSTR("%@ %@"), desc->name, SecDbGetKindSQL(desc->kind)); - if (desc->flags & kSecDbNotNullFlag) - CFStringAppend(sql, CFSTR(" NOT NULL")); - if (desc->flags & kSecDbDefault0Flag) - CFStringAppend(sql, CFSTR(" DEFAULT 0")); - if (desc->flags & kSecDbDefaultEmptyFlag) - CFStringAppend(sql, CFSTR(" DEFAULT ''")); - CFStringAppend(sql, CFSTR(",")); - } - - bool haveUnique = false; - SecDbForEachAttrWithMask(c,desc,kSecDbPrimaryKeyFlag | kSecDbInFlag) { - SecDbAppendUnique(sql, desc->name, &haveUnique); - } - if (haveUnique) - CFStringAppend(sql, CFSTR(")")); - - CFStringAppend(sql, CFSTR(");")); - - // Create indices - SecDbForEachAttrWithMask(c,desc, kSecDbIndexFlag | kSecDbInFlag) { - if (desc->kind == kSecDbSyncAttr) { - CFStringAppendFormat(sql, 0, CFSTR("CREATE INDEX %@%@0 ON %@(%@) WHERE %@=0;"), c->name, desc->name, c->name, desc->name, desc->name); - } else { - CFStringAppendFormat(sql, 0, CFSTR("CREATE INDEX %@%@ ON %@(%@);"), c->name, desc->name, c->name, desc->name); - } - } -} - -static void SecDbAppendDropTableWithClass(CFMutableStringRef sql, const SecDbClass *c) { - CFStringAppendFormat(sql, 0, CFSTR("DROP TABLE %@;"), c->name); -} - -static CFDataRef SecPersistentRefCreateWithItem(SecDbItemRef item, CFErrorRef *error) { - sqlite3_int64 row_id = SecDbItemGetRowId(item, error); - if (row_id) - return _SecItemCreatePersistentRef(SecDbItemGetClass(item)->name, row_id, item->attributes); - return NULL; -} - -bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error) -{ - __block bool ok = true; - CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); - - if (classIndexesForNewTables) { - CFArrayForEach(classIndexesForNewTables, ^(const void* index) { - const SecDbClass* class = schema->classes[(int)index]; - SecDbAppendCreateTableWithClass(sql, class); - }); - } - else { - for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { - SecDbAppendCreateTableWithClass(sql, *pclass); - } - } - - if (includeVersion) { - CFStringAppendFormat(sql, NULL, CFSTR("INSERT INTO tversion(version,minor) VALUES(%d, %d);"), - schema->majorVersion, schema->minorVersion); - } - CFStringPerformWithCString(sql, ^(const char *sql_string) { - ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL), - SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string); - }); - CFReleaseSafe(sql); - return ok; -} - -bool SecItemDbDeleteSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFErrorRef *error) -{ - __block bool ok = true; - CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); - for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { - SecDbAppendDropTableWithClass(sql, *pclass); - } - CFStringPerformWithCString(sql, ^(const char *sql_string) { - ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL), - SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string); - }); - CFReleaseSafe(sql); - return ok; -} - -CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error) { - CFTypeRef a_result; - - if (return_type == 0) { - /* Caller isn't interested in any results at all. */ - a_result = kCFNull; - } else if (return_type == kSecReturnDataMask) { - a_result = SecDbItemGetCachedValueWithName(item, kSecValueData); - if (a_result) { - CFRetainSafe(a_result); - } else { - a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0); - } - } else if (return_type == kSecReturnPersistentRefMask) { - a_result = SecPersistentRefCreateWithItem(item, error); - } else { - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(item)); - /* We need to return more than one value. */ - if (return_type & kSecReturnRefMask) { - CFDictionarySetValue(dict, kSecClass, SecDbItemGetClass(item)->name); - } - CFOptionFlags mask = (((return_type & kSecReturnDataMask || return_type & kSecReturnRefMask) ? kSecDbReturnDataFlag : 0) | - ((return_type & kSecReturnAttributesMask || return_type & kSecReturnRefMask) ? kSecDbReturnAttrFlag : 0)); - SecDbForEachAttr(SecDbItemGetClass(item), desc) { - if ((desc->flags & mask) != 0) { - CFTypeRef value = SecDbItemGetValue(item, desc, error); - if (value && !CFEqual(kCFNull, value)) { - CFDictionarySetValue(dict, desc->name, value); - } else if (value == NULL) { - CFReleaseNull(dict); - break; - } - } - } - CFDictionaryRemoveValue(dict, kSecAttrUUID); - - if (return_type & kSecReturnPersistentRefMask) { - CFDataRef pref = SecPersistentRefCreateWithItem(item, error); - CFDictionarySetValue(dict, kSecValuePersistentRef, pref); - CFReleaseSafe(pref); - } - - a_result = dict; - } - - return a_result; -} - -/* AUDIT[securityd](done): - attributes (ok) is a caller provided dictionary, only its cf type has - been checked. - */ -bool -s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error) -{ - if (query_match_count(q) != 0) - return errSecItemMatchUnsupported; - - /* Add requires a class to be specified unless we are adding a ref. */ - if (q->q_use_item_list) - return errSecUseItemListUnsupported; - - /* Actual work here. */ - SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, q->q_class, q->q_item, KEYBAG_DEVICE, error); - if (!item) - return false; - if (SecDbItemIsTombstone(item)) - SecDbItemSetValue(item, &v7utomb, q->q_use_tomb ? q->q_use_tomb : kCFBooleanTrue, NULL); - - bool ok = true; - if (q->q_data) - ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), q->q_data, error); - if (q->q_row_id) - ok = SecDbItemSetRowId(item, q->q_row_id, error); - if (q->q_musrView) - ok = SecDbItemSetValueWithName(item, CFSTR("musr"), q->q_musrView, error); - SecDbItemSetCredHandle(item, q->q_use_cred_handle); - -#if OCTAGON - if(SecCKKSIsEnabled() && !SecCKKSTestDisableAutomaticUUID()) { - s3dl_item_make_new_uuid(item, q->q_uuid_from_primary_key, error); - - if(q->q_add_sync_callback) { - CFTypeRef uuid = SecDbItemGetValue(item, &v10itemuuid, error); - if(uuid) { - CKKSRegisterSyncStatusCallback(uuid, q->q_add_sync_callback); - } else { - secerror("Couldn't fetch UUID from item; can't call callback"); - } - } - } -#endif - - if (ok) - ok = SecDbItemInsert(item, dbt, error); - - if (ok) { - if (result && q->q_return_type) { - *result = SecDbItemCopyResult(item, q->q_return_type, error); - } - } - if (!ok && error && *error) { - if (CFEqual(CFErrorGetDomain(*error), kSecDbErrorDomain) && CFErrorGetCode(*error) == SQLITE_CONSTRAINT) { - CFReleaseNull(*error); - SecError(errSecDuplicateItem, error, CFSTR("duplicate item %@"), item); - } else if (CFEqual(CFErrorGetDomain(*error), kSecErrorDomain) && CFErrorGetCode(*error) == errSecDecode) { //handle situation when item have pdmn=akpu but passcode is not set - CFTypeRef value = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error); - if (value && CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { - CFReleaseNull(*error); - SecError(errSecAuthFailed, error, CFSTR("authentication failed")); - } - } - } - - if (ok) { - q->q_changed = true; - if (SecDbItemIsSyncable(item)) - q->q_sync_changed = true; - } - - secdebug("dbitem", "inserting item %@%s%@", item, ok ? "" : "failed: ", ok || error == NULL ? (CFErrorRef)CFSTR("") : *error); - - CFRelease(item); - - return ok; -} - -bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error) { - if(!item) { - return false; - } - - // Set the item UUID. - CFUUIDRef uuid = NULL; - // Were we asked to make the UUID static? - if (uuid_from_primary_key) { - // This UUID isn't used in any security mechanism, so we can - // just use the first bits of the SHA256 hash. - CFDataRef pkhash = SecDbKeychainItemCopySHA256PrimaryKey(item, error); - if(CFDataGetLength(pkhash) >= 16) { - UInt8 uuidBytes[16]; - CFRange range = CFRangeMake(0, 16); - CFDataGetBytes(pkhash, range, uuidBytes); - - uuid = CFUUIDCreateWithBytes(NULL, - uuidBytes[ 0], - uuidBytes[ 1], - uuidBytes[ 2], - uuidBytes[ 3], - uuidBytes[ 4], - uuidBytes[ 5], - uuidBytes[ 6], - uuidBytes[ 7], - uuidBytes[ 8], - uuidBytes[ 9], - uuidBytes[10], - uuidBytes[11], - uuidBytes[12], - uuidBytes[13], - uuidBytes[14], - uuidBytes[15]); - } - CFReleaseNull(pkhash); - } - if(uuid == NULL) { - uuid = CFUUIDCreate(NULL); - } - SecDbItemSetValueWithName(item, kSecAttrUUID, uuid, error); - CFReleaseNull(uuid); - return true; -} - -typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context); - -static CFDataRef -s3dl_copy_data_from_col(sqlite3_stmt *stmt, int col, CFErrorRef *error) { - return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col), - sqlite3_column_bytes(stmt, col), - kCFAllocatorNull); -} - -static bool -s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col, CFArrayRef accessGroups, - CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error) { - CFDataRef edata = NULL; - bool ok = false; - require(edata = s3dl_copy_data_from_col(stmt, col, error), out); - ok = s3dl_item_from_data(edata, q, accessGroups, item, access_control, keyclass, error); - -out: - CFReleaseSafe(edata); - return ok; -} - -struct s3dl_query_ctx { - Query *q; - CFArrayRef accessGroups; - SecDbConnectionRef dbt; - CFTypeRef result; - int found; -}; - -/* Return whatever the caller requested based on the value of q->q_return_type. - keys and values must be 3 larger than attr_count in size to accomadate the - optional data, class and persistent ref results. This is so we can use - the CFDictionaryCreate() api here rather than appending to a - mutable dictionary. */ -static CF_RETURNS_RETAINED CFTypeRef -handle_result(Query *q, - CFMutableDictionaryRef item, - sqlite_int64 rowid) -{ - CFTypeRef a_result; - CFDataRef data; - data = CFDictionaryGetValue(item, kSecValueData); - CFDataRef pref = NULL; - if (q->q_return_type & kSecReturnPersistentRefMask) { - pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); - } - if (q->q_return_type == 0) { - /* Caller isn't interested in any results at all. */ - a_result = kCFNull; - } else if (q->q_return_type == kSecReturnDataMask) { - if (data) { - a_result = data; - CFRetain(a_result); - } else { - a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0); - } - } else if (q->q_return_type == kSecReturnPersistentRefMask) { - a_result = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); - } else { - /* We need to return more than one value. */ - if (q->q_return_type & kSecReturnRefMask) { - CFDictionarySetValue(item, kSecClass, q->q_class->name); - } else if ((q->q_return_type & kSecReturnAttributesMask)) { - if (!(q->q_return_type & kSecReturnDataMask)) { - CFDictionaryRemoveValue(item, kSecValueData); - } - - // Add any attributes which are supposed to be returned, are not present in the decrypted blob, - // and have a way to generate themselves. - SecDbItemRef itemRef = NULL; - SecDbForEachAttrWithMask(q->q_class, attr, kSecDbReturnAttrFlag) { - if(!CFDictionaryGetValue(item, attr->name) && attr->copyValue) { - CFErrorRef cferror = NULL; - if(!itemRef) { - itemRef = SecDbItemCreateWithAttributes(NULL, q->q_class, item, KEYBAG_DEVICE, &cferror); - } - if(!cferror && itemRef) { - if (attr->kind != kSecDbSHA1Attr || (q->q_return_type & kSecReturnDataMask)) { // we'll skip returning the sha1 attribute unless the client has also asked us to return data, because without data our sha1 could be invalid - CFTypeRef attrValue = attr->copyValue(itemRef, attr, &cferror); - if (!cferror && attrValue) { - CFDictionarySetValue(item, attr->name, attrValue); - } - CFReleaseNull(attrValue); - } - } - CFReleaseNull(cferror); - } - } - CFReleaseNull(itemRef); - - CFDictionaryRemoveValue(item, kSecAttrUUID); - } else { - CFRetainSafe(data); - CFDictionaryRemoveAllValues(item); - if ((q->q_return_type & kSecReturnDataMask) && data) { - CFDictionarySetValue(item, kSecValueData, data); - } - CFReleaseSafe(data); - } - if (q->q_return_type & kSecReturnPersistentRefMask && pref != NULL) { - CFDictionarySetValue(item, kSecValuePersistentRef, pref); - } - - a_result = item; - CFRetain(item); - } - CFReleaseSafe(pref); - return a_result; -} - -static void s3dl_merge_into_dict(const void *key, const void *value, void *context) { - CFDictionarySetValue(context, key, value); -} - -static bool checkTokenObjectID(CFDataRef token_object_id, CFDataRef value_data) { - bool equalOID = false; - require_quiet(value_data, out); - CFDictionaryRef itemValue = SecTokenItemValueCopy(value_data, NULL); - require_quiet(itemValue, out); - CFDataRef oID = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey); - equalOID = CFEqualSafe(token_object_id, oID); - CFRelease(itemValue); -out: - return equalOID; -} - -static void s3dl_query_row(sqlite3_stmt *stmt, void *context) { - struct s3dl_query_ctx *c = context; - Query *q = c->q; - ReturnTypeMask saved_mask = q->q_return_type; - - sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); - CFMutableDictionaryRef item = NULL; - bool ok; - -decode: - ok = s3dl_item_from_col(stmt, q, 1, c->accessGroups, &item, NULL, NULL, &q->q_error); - if (!ok) { - OSStatus status = SecErrorGetOSStatus(q->q_error); - // errSecDecode means the item is corrupted, stash it for delete. - if (status == errSecDecode) { - secwarning("ignoring corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, rowid, q->q_error); - { - CFStringRef tablename = CFStringCreateCopy(kCFAllocatorDefault, q->q_class->name); - // Can't get rid of this item on the read path. Let's come back from elsewhere. - dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ - __block CFErrorRef localErr = NULL; - __block bool ok = true; - ok &= kc_with_dbt(true, &localErr, ^bool(SecDbConnectionRef dbt) { - CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DELETE FROM %@ WHERE rowid=%lli"), tablename, rowid); - ok &= SecDbPrepare(dbt, sql, &localErr, ^(sqlite3_stmt *stmt) { - ok &= SecDbStep(dbt, stmt, &localErr, NULL); - }); - - if (!ok || localErr) { - secerror("Failed to delete corrupt item, %@ row %lli: %@", tablename, rowid, localErr); - } else { - secnotice("item", "Deleted corrupt rowid %lli from table %@", rowid, tablename); - } - CFReleaseNull(localErr); - CFReleaseNull(sql); - CFReleaseSafe(tablename); - return ok; - }); - }); - - CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL); - CFMutableStringRef edatastring = CFStringCreateMutable(kCFAllocatorDefault, 0); - if(edatastring) { - CFStringAppendEncryptedData(edatastring, edata); - secnotice("item", "corrupted edata=%@", edatastring); - } - CFReleaseSafe(edata); - CFReleaseSafe(edatastring); - } - CFReleaseNull(q->q_error); // This item was never here, keep going - } else if (status == errSecAuthNeeded) { - secwarning("Authentication is needed for %@,rowid=%" PRId64 " (%" PRIdOSStatus "): %@", q->q_class->name, rowid, status, q->q_error); - } else if (status == errSecInteractionNotAllowed) { - static dispatch_once_t kclockedtoken; - static sec_action_t kclockedaction; - dispatch_once(&kclockedtoken, ^{ - kclockedaction = sec_action_create("ratelimiterdisabledlogevent", 1); - sec_action_set_handler(kclockedaction, ^{ - secerror("decode item failed, keychain is locked (%d)", (int)errSecInteractionNotAllowed); - }); - }); - sec_action_perform(kclockedaction); - } else if (status == errSecMissingEntitlement) { - // That's fine, let's pretend the item never existed for this query. - // We may find other, better items for the caller! - CFReleaseNull(q->q_error); - } else { - secerror("decode %@,rowid=%" PRId64 " failed (%" PRIdOSStatus "): %@", q->q_class->name, rowid, status, q->q_error); - } - // q->q_error will be released appropriately by a call to query_error - return; - } - - if (!item) - goto out; - - if (CFDictionaryContainsKey(item, kSecAttrTokenID) && (q->q_return_type & kSecReturnDataMask) == 0) { - // For token-based items, to get really meaningful set of attributes we must provide also data field, so augment mask - // and restart item decoding cycle. - q->q_return_type |= kSecReturnDataMask; - CFReleaseNull(item); - goto decode; - } - - if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, CFDictionaryGetValue(item, kSecValueData))) - goto out; - - if (q->q_class == identity_class()) { - // TODO: Use col 2 for key rowid and use both rowids in persistent ref. - - CFMutableDictionaryRef key; - /* TODO : if there is a errSecDecode error here, we should cleanup */ - if (!s3dl_item_from_col(stmt, q, 3, c->accessGroups, &key, NULL, NULL, &q->q_error) || !key) - goto out; - - CFDataRef certData = CFDictionaryGetValue(item, kSecValueData); - if (certData) { - CFDictionarySetValue(key, kSecAttrIdentityCertificateData, certData); - CFDictionaryRemoveValue(item, kSecValueData); - } - - CFDataRef certTokenID = CFDictionaryGetValue(item, kSecAttrTokenID); - if (certTokenID) { - CFDictionarySetValue(key, kSecAttrIdentityCertificateTokenID, certTokenID); - CFDictionaryRemoveValue(item, kSecAttrTokenID); - } - CFDictionaryApplyFunction(item, s3dl_merge_into_dict, key); - CFRelease(item); - item = key; - } - - if (!match_item(c->dbt, q, c->accessGroups, item)) - goto out; - - CFTypeRef a_result = handle_result(q, item, rowid); - if (a_result) { - if (a_result == kCFNull) { - /* Caller wasn't interested in a result, but we still - count this row as found. */ - CFRelease(a_result); // Help shut up clang - } else if (q->q_limit == 1) { - c->result = a_result; - } else { - CFArrayAppendValue((CFMutableArrayRef)c->result, a_result); - CFRelease(a_result); - } - c->found++; - } - -out: - q->q_return_type = saved_mask; - CFReleaseSafe(item); -} - -static void -SecDbAppendWhereROWID(CFMutableStringRef sql, - CFStringRef col, sqlite_int64 row_id, - bool *needWhere) { - if (row_id > 0) { - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppendFormat(sql, NULL, CFSTR("%@=%lld"), col, row_id); - } -} - -static void -SecDbAppendWhereAttrs(CFMutableStringRef sql, const Query *q, bool *needWhere) { - CFIndex ix, attr_count = query_attr_count(q); - for (ix = 0; ix < attr_count; ++ix) { - SecDbAppendWhereOrAndEquals(sql, query_attr_at(q, ix).key, needWhere); - } -} - -static void -SecDbAppendWhereAccessGroups(CFMutableStringRef sql, - CFStringRef col, - CFArrayRef accessGroups, - bool *needWhere) { - CFIndex ix, ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - return; - } - - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppend(sql, col); - CFStringAppend(sql, CFSTR(" IN (?")); - for (ix = 1; ix < ag_count; ++ix) { - CFStringAppend(sql, CFSTR(",?")); - } - CFStringAppend(sql, CFSTR(")")); -} - -static bool -isQueryOverAllMUSRViews(CFTypeRef musrView) -{ - return SecMUSRIsViewAllViews(musrView); -} - -static bool -isQueryOverSingleUserView(CFTypeRef musrView) -{ - return isNull(musrView); -} - -#if TARGET_OS_IPHONE -static bool -isQueryOverBothUserAndSystem(CFTypeRef musrView, uid_t *uid) -{ - return SecMUSRGetBothUserAndSystemUUID(musrView, uid); -} -#endif - -static void -SecDbAppendWhereMusr(CFMutableStringRef sql, - const Query *q, - bool *needWhere) -{ - SecDbAppendWhereOrAnd(sql, needWhere); - -#if TARGET_OS_IPHONE - if (isQueryOverBothUserAndSystem(q->q_musrView, NULL)) { - CFStringAppend(sql, CFSTR("(musr = ? OR musr = ?)")); - } else -#endif - if (isQueryOverAllMUSRViews(q->q_musrView)) { - /* query over all items, regardless of view */ - } else if (isQueryOverSingleUserView(q->q_musrView)) { - CFStringAppend(sql, CFSTR("musr = ?")); - } else { - CFStringAppend(sql, CFSTR("musr = ?")); - } -} - -static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q, - CFArrayRef accessGroups) { - bool needWhere = true; - SecDbAppendWhereROWID(sql, CFSTR("ROWID"), q->q_row_id, &needWhere); - SecDbAppendWhereAttrs(sql, q, &needWhere); - SecDbAppendWhereMusr(sql, q, &needWhere); - SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere); -} - -static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) { - if (limit != kSecMatchUnlimited) - CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %" PRIdCFIndex), limit); -} - -static CFStringRef s3dl_create_select_sql(Query *q, CFArrayRef accessGroups) { - CFMutableStringRef sql = CFStringCreateMutable(NULL, 0); - if (q->q_class == identity_class()) { - CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, %@" - ", rowid,data FROM " - "(SELECT cert.rowid AS crowid, cert.labl AS labl," - " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid," - " keys.*,cert.data AS %@" - " FROM keys, cert" - " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"), - kSecAttrIdentityCertificateData, kSecAttrIdentityCertificateData); - SecDbAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0); - /* The next 3 SecDbAppendWhere calls are in the same order as in - SecDbAppendWhereClause(). This makes sqlBindWhereClause() work, - as long as we do an extra sqlBindAccessGroups first. */ - SecDbAppendWhereROWID(sql, CFSTR("crowid"), q->q_row_id, 0); - CFStringAppend(sql, CFSTR(")")); - bool needWhere = true; - SecDbAppendWhereAttrs(sql, q, &needWhere); - SecDbAppendWhereMusr(sql, q, &needWhere); - SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere); - } else { - CFStringAppend(sql, CFSTR("SELECT rowid, data FROM ")); - CFStringAppend(sql, q->q_class->name); - SecDbAppendWhereClause(sql, q, accessGroups); - } - //do not append limit for all queries which needs filtering - if (q->q_match_issuer == NULL && q->q_match_policy == NULL && q->q_match_valid_on_date == NULL && q->q_match_trusted_only == NULL && q->q_token_object_id == NULL) { - SecDbAppendLimit(sql, q->q_limit); - } - - return sql; -} - -static bool sqlBindMusr(sqlite3_stmt *stmt, const Query *q, int *pParam, CFErrorRef *error) { - int param = *pParam; - bool result = true; -#if TARGET_OS_IPHONE - uid_t uid; - - if (isQueryOverBothUserAndSystem(q->q_musrView, &uid)) { - /* network extensions are special and get to query both user and system views */ - CFDataRef systemUUID = SecMUSRGetSystemKeychainUUID(); - result = SecDbBindObject(stmt, param++, systemUUID, error); - if (result) { - CFDataRef activeUser = SecMUSRCreateActiveUserUUID(uid); - result = SecDbBindObject(stmt, param++, activeUser, error); - CFReleaseNull(activeUser); - } - } else -#endif - if (isQueryOverAllMUSRViews(q->q_musrView)) { - /* query over all items, regardless of view */ - } else if (isQueryOverSingleUserView(q->q_musrView)) { - CFDataRef singleUUID = SecMUSRGetSingleUserKeychainUUID(); - result = SecDbBindObject(stmt, param++, singleUUID, error); - } else { - result = SecDbBindObject(stmt, param++, q->q_musrView, error); - } - - *pParam = param; - return result; -} - - -static bool sqlBindAccessGroups(sqlite3_stmt *stmt, CFArrayRef accessGroups, - int *pParam, CFErrorRef *error) { - bool result = true; - int param = *pParam; - CFIndex ix, count = accessGroups ? CFArrayGetCount(accessGroups) : 0; - for (ix = 0; ix < count; ++ix) { - result = SecDbBindObject(stmt, param++, - CFArrayGetValueAtIndex(accessGroups, ix), - error); - if (!result) - break; - } - *pParam = param; - return result; -} - -static bool sqlBindWhereClause(sqlite3_stmt *stmt, const Query *q, - CFArrayRef accessGroups, int *pParam, CFErrorRef *error) { - bool result = true; - int param = *pParam; - CFIndex ix, attr_count = query_attr_count(q); - for (ix = 0; ix < attr_count; ++ix) { - result = SecDbBindObject(stmt, param++, query_attr_at(q, ix).value, error); - if (!result) - break; - } - - if (result) { - result = sqlBindMusr(stmt, q, ¶m, error); - } - - /* Bind the access group to the sql. */ - if (result) { - result = sqlBindAccessGroups(stmt, accessGroups, ¶m, error); - } - - *pParam = param; - return result; -} - -bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error, - void (^handle_row)(SecDbItemRef item, bool *stop)) { - __block bool ok = true; - /* Sanity check the query. */ - if (query->q_ref) - return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries")); - - bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { - // The attributes here must match field list hardcoded in s3dl_select_sql used below, which is - // "rowid, data" - return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; - }; - - CFStringRef sql = s3dl_create_select_sql(query, accessGroups); - ok = sql; - if (sql) { - ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { - /* Bind the values being searched for to the SELECT statement. */ - int param = 1; - if (query->q_class == identity_class()) { - /* Bind the access groups to cert.agrp. */ - ok &= sqlBindAccessGroups(stmt, accessGroups, ¶m, error); - } - if (ok) - ok &= sqlBindWhereClause(stmt, query, accessGroups, ¶m, error); - if (ok) { - SecDbStep(dbconn, stmt, error, ^(bool *stop) { - SecDbItemRef itemFromStatement = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr); - if (itemFromStatement) { - CFTransferRetained(itemFromStatement->credHandle, query->q_use_cred_handle); - if (match_item(dbconn, query, accessGroups, itemFromStatement->attributes)) - handle_row(itemFromStatement, stop); - CFReleaseNull(itemFromStatement); - } else { - secerror("failed to create item from stmt: %@", error ? *error : (CFErrorRef)"no error"); - if (error) { - CFReleaseNull(*error); - } - //*stop = true; - //ok = false; - } - }); - } - }); - CFRelease(sql); - } - - return ok; -} - -static bool -s3dl_query(s3dl_handle_row handle_row, - void *context, CFErrorRef *error) -{ - struct s3dl_query_ctx *c = context; - SecDbConnectionRef dbt = c->dbt; - Query *q = c->q; - CFArrayRef accessGroups = c->accessGroups; - - /* Sanity check the query. */ - if (q->q_ref) - return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries")); - - /* Actual work here. */ - if (q->q_limit == 1) { - c->result = NULL; - } else { - c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - } - CFStringRef sql = s3dl_create_select_sql(q, accessGroups); - bool ok = SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) { - bool sql_ok = true; - /* Bind the values being searched for to the SELECT statement. */ - int param = 1; - if (q->q_class == identity_class()) { - /* Bind the access groups to cert.agrp. */ - sql_ok = sqlBindAccessGroups(stmt, accessGroups, ¶m, error); - } - if (sql_ok) - sql_ok = sqlBindWhereClause(stmt, q, accessGroups, ¶m, error); - if (sql_ok) { - SecDbForEach(dbt, stmt, error, ^bool (int row_index) { - handle_row(stmt, context); - - bool needs_auth = q->q_error && CFErrorGetCode(q->q_error) == errSecAuthNeeded; - if (q->q_skip_acl_items && needs_auth) - // Skip items needing authentication if we are told to do so. - CFReleaseNull(q->q_error); - - bool stop = q->q_limit != kSecMatchUnlimited && c->found >= q->q_limit; - stop = stop || (q->q_error && !needs_auth); - return !stop; - }); - } - return sql_ok; - }); - - CFRelease(sql); - - // First get the error from the query, since errSecDuplicateItem from an - // update query should superceed the errSecItemNotFound below. - if (!query_error(q, error)) - ok = false; - if (ok && c->found == 0) { - ok = SecError(errSecItemNotFound, error, CFSTR("no matching items found")); - if (q->q_spindump_on_failure) { - __security_stackshotreport(CFSTR("ItemNotFound"), __sec_exception_code_LostInMist); - } - } - - return ok; -} - -bool -s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, - CFArrayRef accessGroups, CFErrorRef *error) -{ - struct s3dl_query_ctx ctx = { - .q = q, .accessGroups = accessGroups, .dbt = dbt, - }; - if (q->q_row_id && query_attr_count(q)) - return SecError(errSecItemIllegalQuery, error, - CFSTR("attributes to query illegal; both row_id and other attributes can't be searched at the same time")); - if (q->q_token_object_id && query_attr_count(q) != 1) - return SecError(errSecItemIllegalQuery, error, - CFSTR("attributes to query illegal; both token persitent ref and other attributes can't be searched at the same time")); - - // Only copy things that aren't tombstones unless the client explicitly asks otherwise. - if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - bool ok = s3dl_query(s3dl_query_row, &ctx, error); - if (ok && result) - *result = ctx.result; - else - CFReleaseSafe(ctx.result); - - return ok; -} - -typedef void (^s3dl_item_digest_callback)(CFDataRef persistantReference, CFDataRef encryptedData); - -struct s3dl_digest_ctx { - Query *q; - SecDbConnectionRef dbt; - s3dl_item_digest_callback item_callback; -}; - -static void s3dl_query_row_digest(sqlite3_stmt *stmt, void *context) { - struct s3dl_query_ctx *c = context; - Query *q = c->q; - - sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); - CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL); - CFDataRef persistant_reference = _SecItemCreatePersistentRef(q->q_class->name, rowid, NULL); - CFDataRef digest = NULL; - - if (edata) { - digest = CFDataCopySHA256Digest(edata, NULL); - } - - if (digest && persistant_reference) { - CFDictionaryRef item = CFDictionaryCreateForCFTypes(NULL, - kSecValuePersistentRef, persistant_reference, - kSecValueData, digest, - NULL); - if (item) - CFArrayAppendValue((CFMutableArrayRef)c->result, item); - CFReleaseNull(item); - c->found++; - } else { - secinfo("item", "rowid %lu in %@ failed to create pref/digest", (unsigned long)rowid, q->q_class->name); - } - CFReleaseNull(digest); - CFReleaseNull(edata); - CFReleaseNull(persistant_reference); -} - - -bool -s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error) -{ - struct s3dl_query_ctx ctx = { - .q = q, .dbt = dbt, .accessGroups = accessGroups, - }; - // Force to always return an array - q->q_limit = kSecMatchUnlimited; - // This interface only queries live data - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - bool ok = s3dl_query(s3dl_query_row_digest, &ctx, error); - if (ok && result) - *result = (CFArrayRef)ctx.result; - else - CFReleaseSafe(ctx.result); - - return ok; -} - -/* First remove key from q->q_pairs if it's present, then add the attribute again. */ -static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) { - if (CFDictionaryContainsKey(q->q_item, desc->name)) { - CFIndex ix; - for (ix = 0; ix < q->q_attr_end; ++ix) { - if (CFEqual(desc->name, q->q_pairs[ix].key)) { - CFReleaseSafe(q->q_pairs[ix].value); - --q->q_attr_end; - for (; ix < q->q_attr_end; ++ix) { - q->q_pairs[ix] = q->q_pairs[ix + 1]; - } - CFDictionaryRemoveValue(q->q_item, desc->name); - break; - } - } - } - query_add_attribute_with_desc(desc, value, q); -} - -/* Update modification_date if needed. */ -static void query_pre_update(Query *q) { - SecDbForEachAttr(q->q_class, desc) { - if (desc->kind == kSecDbModificationDateAttr) { - CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); - query_set_attribute_with_desc(desc, now, q); - CFReleaseSafe(now); - } - } -} - -/* Make sure all attributes that are marked as not_null have a value. If - force_date is false, only set mdat and cdat if they aren't already set. */ -void query_pre_add(Query *q, bool force_date) { - CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); - SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInFlag) { - if (desc->kind == kSecDbCreationDateAttr || - desc->kind == kSecDbModificationDateAttr) { - if (force_date) { - query_set_attribute_with_desc(desc, now, q); - } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) { - query_add_attribute_with_desc(desc, now, q); - } - } else if ((desc->flags & kSecDbNotNullFlag) && - !CFDictionaryContainsKey(q->q_item, desc->name)) { - CFTypeRef value = NULL; - if (desc->flags & kSecDbDefault0Flag) { - if (desc->kind == kSecDbDateAttr) - value = CFDateCreate(kCFAllocatorDefault, 0.0); - else { - SInt32 vzero = 0; - value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero); - } - } else if (desc->flags & kSecDbDefaultEmptyFlag) { - if (desc->kind == kSecDbDataAttr || desc->kind == kSecDbUUIDAttr) - value = CFDataCreate(kCFAllocatorDefault, NULL, 0); - else { - value = CFSTR(""); - CFRetain(value); - } - } - if (value) { - /* Safe to use query_add_attribute here since the attr wasn't - set yet. */ - query_add_attribute_with_desc(desc, value, q); - CFRelease(value); - } - } - } - CFReleaseSafe(now); -} - -// Return a tri state value false->never make a tombstone, true->always make a -// tombstone, NULL->make a tombstone, but delete it if the tombstone itself is not currently being synced. -static CFBooleanRef s3dl_should_make_tombstone(Query *q, bool item_is_syncable, SecDbItemRef item) { - if (q->q_use_tomb) - return q->q_use_tomb; - else if (item_is_syncable && !SecDbItemIsTombstone(item)) - return NULL; - else - return kCFBooleanFalse; -} -/* AUDIT[securityd](done): - attributesToUpdate (ok) is a caller provided dictionary, - only its cf types have been checked. - */ -bool -s3dl_query_update(SecDbConnectionRef dbt, Query *q, - CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error) -{ - /* Sanity check the query. */ - if (query_match_count(q) != 0) - return SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported in attributes to update")); - if (q->q_ref) - return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported in attributes to update")); - if (q->q_row_id && query_attr_count(q)) - return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both row_id and other attributes can't be updated at the same time")); - if (q->q_token_object_id && query_attr_count(q) != 1) - return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both token persistent ref and other attributes can't be updated at the same time")); - - __block bool result = true; - Query *u = query_create(q->q_class, NULL, attributesToUpdate, error); - if (u == NULL) return false; - require_action_quiet(query_update_parse(u, attributesToUpdate, error), errOut, result = false); - query_pre_update(u); - result &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - // Make sure we only update real items, not tombstones, unless the client explicitly asks otherwise. - if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - result &= SecDbItemQuery(q, accessGroups, dbt, error, ^(SecDbItemRef item, bool *stop) { - // We always need to know the error here. - CFErrorRef localError = NULL; - if (q->q_token_object_id) { - const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); - CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); - if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) - return; - } - // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. - const SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL); - CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, NULL)); - SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, u->q_item, &localError); - SecDbItemSetValue(item, sha1attr, storedSHA1, NULL); - CFReleaseSafe(storedSHA1); - if (SecErrorGetOSStatus(localError) == errSecDecode) { - // We just ignore this, and treat as if item is not found. - secwarning("deleting corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError); - CFReleaseNull(localError); - if (!SecDbItemDelete(item, dbt, false, &localError)) { - secerror("failed to delete corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError); - CFReleaseNull(localError); - } - CFReleaseNull(new_item); - return; - } - if (new_item != NULL && u->q_access_control != NULL) - SecDbItemSetAccessControl(new_item, u->q_access_control, &localError); - result = SecErrorPropagate(localError, error) && new_item; - if (new_item) { - bool item_is_sync = SecDbItemIsSyncable(item); - result = SecDbItemUpdate(item, new_item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), q->q_uuid_from_primary_key, error); - if (result) { - q->q_changed = true; - if (item_is_sync || SecDbItemIsSyncable(new_item)) - q->q_sync_changed = true; - } - CFRelease(new_item); - } - }); - if (!result) - *commit = false; - }); - if (result && !q->q_changed) - result = SecError(errSecItemNotFound, error, CFSTR("No items updated")); -errOut: - if (!query_destroy(u, error)) - result = false; - return result; -} - -static bool SecDbItemNeedAuth(SecDbItemRef item, CFErrorRef *error) -{ - CFErrorRef localError = NULL; - if (!SecDbItemEnsureDecrypted(item, true, &localError) && localError && CFErrorGetCode(localError) == errSecAuthNeeded) { - if (error) - *error = localError; - return true; - } - - CFReleaseSafe(localError); - return false; -} - -bool -s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error) -{ - __block bool ok = true; - __block bool needAuth = false; - // Only delete things that aren't tombstones, unless the client explicitly asks otherwise. - if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - ok &= SecDbItemSelect(q, dbt, error, NULL, ^bool(const SecDbAttr *attr) { - return false; - },^bool(CFMutableStringRef sql, bool *needWhere) { - SecDbAppendWhereClause(sql, q, accessGroups); - return true; - },^bool(sqlite3_stmt * stmt, int col) { - return sqlBindWhereClause(stmt, q, accessGroups, &col, error); - }, ^(SecDbItemRef item, bool *stop) { - // Check if item for token persitence ref - if (q->q_token_object_id) { - const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); - CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); - if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) - return; - } - // Check if item need to be authenticated by LocalAuthentication - item->cryptoOp = kAKSKeyOpDelete; - if (SecDbItemNeedAuth(item, error)) { - needAuth = true; - return; - } - // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. - const SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL); - CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, NULL)); - bool item_is_sync = SecDbItemIsSyncable(item); - SecDbItemSetValue(item, sha1attr, storedSHA1, NULL); - CFReleaseSafe(storedSHA1); - ok = SecDbItemDelete(item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), error); - if (ok) { - q->q_changed = true; - if (item_is_sync) - q->q_sync_changed = true; - } - }); - if (ok && !q->q_changed && !needAuth) { - ok = SecError(errSecItemNotFound, error, CFSTR("Delete failed to delete anything")); - } - return ok && !needAuth; -} - -static bool -matchAnyString(CFStringRef needle, CFStringRef *haystack) -{ - while (*haystack) { - if (CFEqual(needle, *haystack)) - return true; - haystack++; - } - return false; -} - -/* Return true iff the item in question should not be backed up, nor restored, - but when restoring a backup the original version of the item should be - added back to the keychain again after the restore completes. */ -bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser) { - CFNumberRef sysb = CFDictionaryGetValue(item, kSecAttrSysBound); - if (isNumber(sysb)) { - int32_t num = 0; - if (!CFNumberGetValue(sysb, kCFNumberSInt32Type, &num)) - return false; - if (num == kSecSecAttrSysBoundNot) { - return false; - } else if (num == kSecSecAttrSysBoundPreserveDuringRestore) { - return true; - } - return true; - } - - CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup); - if (!isString(agrp)) - return false; - - if (CFEqualSafe(agrp, kSOSInternalAccessGroup)) { - secdebug("backup", "found sysbound item: %@", item); - return true; - } - - if (CFEqual(agrp, CFSTR("lockdown-identities"))) { - secdebug("backup", "found sys_bound item: %@", item); - return true; - } - - if (CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount); - - if (isString(service) && isString(account)) { - static CFStringRef mcAccounts[] = { - CFSTR("Public"), - CFSTR("Private"), - NULL, - }; - - if (CFEqual(service, CFSTR("com.apple.managedconfiguration")) - && matchAnyString(account, mcAccounts)) - { - secdebug("backup", "found sys_bound item: %@", item); - return true; - } - } - - if (isString(service) && CFEqual(service, CFSTR("com.apple.account.CloudKit.token"))) { - secdebug("backup", "found sys_bound item: %@", item); - return true; - } - - if (isString(service) && CFEqual(service, CFSTR("com.apple.account.idms.continuation-key"))) { - secdebug("backup", "found sys_bound item: %@", item); - return true; - } - } - - if (multiUser && CFEqual(agrp, CFSTR("com.apple.apsd")) && cls == genp_class()) { - static CFStringRef pushServices[] = { - CFSTR("push.apple.com"), - CFSTR("push.apple.com,PerAppToken.v0"), - NULL - }; - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - - if (isString(service) && matchAnyString(service, pushServices)) { - secdebug("backup", "found sys_bound item: %@", item); - return true; - } - } - - if (multiUser && CFEqual(agrp, CFSTR("appleaccount")) && cls == genp_class()) { - static CFStringRef accountServices[] = { - CFSTR("com.apple.appleaccount.fmf.token"), /* temporary tokens while accout is being setup */ - CFSTR("com.apple.appleaccount.fmf.apptoken"), - CFSTR("com.apple.appleaccount.fmip.siritoken"), - CFSTR("com.apple.appleaccount.cloudkit.token"), - NULL - }; - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - - if (isString(service) && matchAnyString(service, accountServices)) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - } - - if (multiUser && CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { - static CFStringRef accountServices[] = { - /* accounts, remove with rdar://37595482 */ - CFSTR("com.apple.account.AppleAccount.token"), - CFSTR("com.apple.account.AppleAccount.password"), - CFSTR("com.apple.account.AppleAccount.rpassword"), - CFSTR("com.apple.account.idms.token"), - CFSTR("com.apple.account.idms.heartbeat-token"), - CFSTR("com.apple.account.idms.continuation-key"), - CFSTR("com.apple.account.CloudKit.token"), - CFSTR("com.apple.account.IdentityServices.password"), /* accountsd for ids */ - CFSTR("com.apple.account.IdentityServices.rpassword"), - CFSTR("com.apple.account.IdentityServices.token"), - /* IDS stuff */ - CFSTR("BackupIDSAccountToken"), - CFSTR("com.apple.ids"), - CFSTR("ids"), - CFSTR("IDS"), - NULL - }; - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - - if (isString(service) && matchAnyString(service, accountServices)) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - if (isString(service) && CFStringHasPrefix(service, CFSTR("com.apple.gs."))) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - if (isString(service) && CFEqual(service, CFSTR("com.apple.facetime"))) { - CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount); - if (isString(account) && CFEqual(account, CFSTR("registrationV1"))) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - } - } - - /* accounts, remove with rdar://37595482 */ - if (multiUser && CFEqual(agrp, CFSTR("com.apple.ind")) && cls == genp_class()) { - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - if (isString(service) && CFEqual(service, CFSTR("com.apple.ind.registration"))) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - } - - if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == genp_class()) { - static CFStringRef accountServices[] = { - CFSTR("ids"), - NULL - }; - CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); - - if (isString(service) && matchAnyString(service, accountServices)) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - } - - if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == keys_class()) { - static CFStringRef exactMatchingLabel[] = { - CFSTR("iMessage Encryption Key"), - CFSTR("iMessage Signing Key"), - }; - CFStringRef label = CFDictionaryGetValue(item, kSecAttrLabel); - if (isString(label)) { - if (matchAnyString(label, exactMatchingLabel)) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - } - } - - if (multiUser && CFEqual(agrp, CFSTR("com.apple.rapport")) && cls == genp_class()) { - secdebug("backup", "found exact sys_bound item: %@", item); - return true; - } - - secdebug("backup", "found non sys_bound item: %@", item); - return false; -} - -/* Delete all items from the current keychain. If this is not an in - place upgrade we don't delete items in the 'lockdown-identities' - access group, this ensures that an import or restore of a backup - will never overwrite an existing activation record. */ -static bool SecServerDeleteAll(SecDbConnectionRef dbt, CFErrorRef *error) { - secwarning("SecServerDeleteAll"); - - return kc_transaction(dbt, error, ^{ - - bool ok = (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) && - SecDbExec(dbt, CFSTR("DELETE from inet;"), error) && - SecDbExec(dbt, CFSTR("DELETE from cert;"), error) && - SecDbExec(dbt, CFSTR("DELETE from keys;"), error)); - return ok; - }); -} - -#if TARGET_OS_IPHONE - -static bool DeleteAllFromTableForMUSRView(SecDbConnectionRef dbt, - CFStringRef sql, - CFDataRef musr, - bool keepU, - CFErrorRef *error) -{ - sqlite3_stmt *stmt = NULL; - CFStringRef sql2 = NULL; - bool ok = false; - - if (keepU) { - sql2 = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ AND pdmn NOT IN ('aku','akpu','cku','dku')"), sql); - } else { - sql2 = CFRetain(sql); - } - require(sql2, fail); - - stmt = SecDbCopyStmt(dbt, sql2, NULL, error); - require(stmt, fail); - - ok = SecDbBindObject(stmt, 1, musr, error); - require(ok, fail); - - ok = SecDbStep(dbt, stmt, error, ^(bool *stop) { }); - require(ok, fail); - -fail: - if (stmt) { - ok = SecDbFinalize(stmt, error); - } - if (!ok) - secwarning("DeleteAllFromTableForMUSRView failed for %@ for musr: %@: %@", sql2, musr, error ? *error : NULL); - - CFReleaseNull(sql2); - - return ok; -} - -bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool keepU, CFErrorRef *error) { - secwarning("SecServerDeleteAllForUser for user: %@ keepU %s", musrView, keepU ? "yes" : "no"); - - return kc_transaction(dbt, error, ^{ - bool ok; - - ok = (DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM genp WHERE musr = ?"), musrView, keepU, error) && - DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM inet WHERE musr = ?"), musrView, keepU, error) && - DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM cert WHERE musr = ?"), musrView, keepU, error) && - DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM keys WHERE musr = ?"), musrView, keepU, error)); - - return ok; - }); -} -#endif - - -struct s3dl_export_row_ctx { - struct s3dl_query_ctx qc; - keybag_handle_t dest_keybag; - enum SecItemFilter filter; - bool multiUser; -}; - -static void s3dl_export_row(sqlite3_stmt *stmt, void *context) { - struct s3dl_export_row_ctx *c = context; - Query *q = c->qc.q; - SecAccessControlRef access_control = NULL; - CFErrorRef localError = NULL; - - /* Skip akpu items when backing up, those are intentionally lost across restores. The same applies to SEP-based keys */ - bool skip_akpu_or_token = c->filter == kSecBackupableItemFilter; - - sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); - CFMutableDictionaryRef allAttributes = NULL; - CFMutableDictionaryRef metadataAttributes = NULL; - CFMutableDictionaryRef secretStuff = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - keyclass_t keyclass = 0; - bool ok = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups, &allAttributes, &access_control, &keyclass, &localError); - - if (ok) { - metadataAttributes = CFDictionaryCreateMutableCopy(NULL, 0, allAttributes); - SecDbForEachAttrWithMask(q->q_class, desc, kSecDbReturnDataFlag) { - CFTypeRef value = CFDictionaryGetValue(metadataAttributes, desc->name); - if (value) { - CFDictionarySetValue(secretStuff, desc->name, value); - CFDictionaryRemoveValue(metadataAttributes, desc->name); - } - } - } - - bool is_akpu = access_control ? CFEqualSafe(SecAccessControlGetProtection(access_control), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) - // Mask generation, only look at class per se - : (keyclass & key_class_last) == key_class_akpu; - bool is_token = (ok && allAttributes != NULL) ? CFDictionaryContainsKey(allAttributes, kSecAttrTokenID) : false; - - if (ok && allAttributes && !(skip_akpu_or_token && (is_akpu || is_token))) { - /* Only export sysbound items if do_sys_bound is true, only export non sysbound items otherwise. */ - bool do_sys_bound = c->filter == kSecSysBoundItemFilter; - if (c->filter == kSecNoItemFilter || - SecItemIsSystemBound(allAttributes, q->q_class, c->multiUser) == do_sys_bound) { - /* Re-encode the item. */ - secdebug("item", "export rowid %llu item: %@", rowid, allAttributes); - /* The code below could be moved into handle_row. */ - CFDataRef pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, allAttributes); - if (pref) { - if (c->dest_keybag != KEYBAG_NONE) { - CFMutableDictionaryRef auth_attribs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInAuthenticatedDataFlag) { - CFTypeRef value = CFDictionaryGetValue(metadataAttributes, desc->name); - if(value) { - CFDictionaryAddValue(auth_attribs, desc->name, value); - CFDictionaryRemoveValue(metadataAttributes, desc->name); - } - } - - /* Encode and encrypt the item to the specified keybag. */ - CFDataRef edata = NULL; - bool encrypted = ks_encrypt_data(c->dest_keybag, access_control, q->q_use_cred_handle, secretStuff, metadataAttributes, auth_attribs, &edata, false, &q->q_error); - CFDictionaryRemoveAllValues(allAttributes); - CFRelease(auth_attribs); - if (encrypted) { - CFDictionarySetValue(allAttributes, kSecValueData, edata); - CFReleaseSafe(edata); - } else { - seccritical("ks_encrypt_data %@,rowid=%" PRId64 ": failed: %@", q->q_class->name, rowid, q->q_error); - CFReleaseNull(q->q_error); - } - } - if (CFDictionaryGetCount(allAttributes)) { - CFDictionarySetValue(allAttributes, kSecValuePersistentRef, pref); - CFArrayAppendValue((CFMutableArrayRef)c->qc.result, allAttributes); - c->qc.found++; - } - CFReleaseSafe(pref); - } - } - } else { - OSStatus status = SecErrorGetOSStatus(localError); - - if (status == errSecInteractionNotAllowed && is_akpu) { - if (skip_akpu_or_token) { - secdebug("item", "Skipping akpu item for backup"); - } else { // Probably failed to decrypt sysbound item. Should never be an akpu item in backup. - secerror("Encountered akpu item we cannot export (filter %d), skipping. %@", c->filter, localError); - // TODO: Find out who is doing this somehow and make them not do this - } - // We expect akpu items to be inaccessible when the device is locked. - CFReleaseNull(localError); - } else { - /* This happens a lot when trying to migrate keychain before first unlock, so only a notice */ - /* If the error is "corrupted item" then we just ignore it, otherwise we save it in the query */ - secinfo("item","Could not export item for rowid %llu: %@", rowid, localError); - - if (status == errSecDecode) { - CFReleaseNull(localError); - } else { - CFReleaseSafe(q->q_error); - q->q_error = localError; - } - } - } - CFReleaseNull(access_control); - CFReleaseNull(allAttributes); - CFReleaseNull(metadataAttributes); - CFReleaseNull(secretStuff); -} - -static CFStringRef -SecCreateKeybagUUID(keybag_handle_t keybag) -{ -#if !TARGET_HAS_KEYSTORE - return NULL; -#else - char uuidstr[37]; - uuid_t uuid; - if (aks_get_bag_uuid(keybag, uuid) != KERN_SUCCESS) - return NULL; - uuid_unparse_lower(uuid, uuidstr); - return CFStringCreateWithCString(NULL, uuidstr, kCFStringEncodingUTF8); -#endif -} - - -CFDictionaryRef -SecServerCopyKeychainPlist(SecDbConnectionRef dbt, - SecurityClient *client, - keybag_handle_t src_keybag, - keybag_handle_t dest_keybag, - enum SecItemFilter filter, - CFErrorRef *error) { - CFMutableDictionaryRef keychain; - keychain = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - unsigned class_ix; - bool inMultiUser = false; - CFStringRef keybaguuid = NULL; - Query q = { .q_keybag = src_keybag, - .q_musrView = NULL - }; - - if (!keychain) { - if (error && !*error) - SecError(errSecAllocate, error, CFSTR("Can't create keychain dictionary")); - goto errOut; - } - - q.q_return_type = - kSecReturnDataMask | - kSecReturnAttributesMask | - kSecReturnPersistentRefMask; - q.q_limit = kSecMatchUnlimited; - q.q_skip_acl_items = true; - - -#if TARGET_OS_IPHONE - if (client && client->inMultiUser) { - q.q_musrView = SecMUSRCreateActiveUserUUID(client->uid); - inMultiUser = true; - } else -#endif - { - q.q_musrView = SecMUSRGetSingleUserKeychainUUID(); - CFRetain(q.q_musrView); - - keybaguuid = SecCreateKeybagUUID(dest_keybag); - if (keybaguuid) { - CFDictionarySetValue(keychain, kSecBackupKeybagUUIDKey, keybaguuid); - } - } - - /* Get rid of this duplicate. */ - const SecDbClass *SecDbClasses[] = { - genp_class(), - inet_class(), - cert_class(), - keys_class() - }; - - for (class_ix = 0; class_ix < array_size(SecDbClasses); - ++class_ix) { - q.q_class = SecDbClasses[class_ix]; - struct s3dl_export_row_ctx ctx = { - .qc = { .q = &q, .dbt = dbt }, - .dest_keybag = dest_keybag, .filter = filter, - .multiUser = inMultiUser, - }; - - secnotice("item", "exporting %ssysbound class '%@'", filter != kSecSysBoundItemFilter ? "non-" : "", q.q_class->name); - - CFErrorRef localError = NULL; - if (s3dl_query(s3dl_export_row, &ctx, &localError)) { - secnotice("item", "exporting class '%@' complete", q.q_class->name); - if (CFArrayGetCount(ctx.qc.result)) { - SecSignpostBackupCount(SecSignpostImpulseBackupClassCount, q.q_class->name, CFArrayGetCount(ctx.qc.result), filter); - CFDictionaryAddValue(keychain, q.q_class->name, ctx.qc.result); - } - - } else { - OSStatus status = (OSStatus)CFErrorGetCode(localError); - if (status == errSecItemNotFound) { - secnotice("item", "exporting class '%@' complete (no items)", q.q_class->name); - CFRelease(localError); - } else { - secerror("exporting class '%@' failed: %@", q.q_class->name, localError); - if (error) { - CFReleaseSafe(*error); - *error = localError; - } else { - CFRelease(localError); - } - CFReleaseNull(keychain); - CFReleaseNull(ctx.qc.result); - break; - } - } - CFReleaseNull(ctx.qc.result); - } - -errOut: - CFReleaseNull(q.q_musrView); - CFReleaseNull(keybaguuid); - - return keychain; -} - -struct SecServerImportClassState { - SecDbConnectionRef dbt; - CFErrorRef error; - keybag_handle_t src_keybag; - keybag_handle_t dest_keybag; - SecurityClient *client; - enum SecItemFilter filter; -}; - -struct SecServerImportItemState { - const SecDbClass *class; - struct SecServerImportClassState *s; -}; - -static void -SecServerImportItem(const void *value, void *context) -{ - struct SecServerImportItemState *state = (struct SecServerImportItemState *)context; - bool inMultiUser = false; -#if TARGET_OS_IPHONE - if (state->s->client->inMultiUser) - inMultiUser = true; -#endif - - if (state->s->error) - return; - - if (!isDictionary(value)) { - SecError(errSecParam, &state->s->error, CFSTR("value %@ is not a dictionary"), value); - return; - } - - CFDictionaryRef dict = (CFDictionaryRef)value; - - secdebug("item", "Import Item : %@", dict); - - SecDbItemRef item = NULL; - - /* This is sligthly confusing: - - During upgrade all items are exported with KEYBAG_NONE. - - During restore from backup, existing sys_bound items are exported with KEYBAG_NONE, and are exported as dictionary of attributes. - - Item in the actual backup are export with a real keybag, and are exported as encrypted v_Data and v_PersistentRef - */ - if (state->s->src_keybag == KEYBAG_NONE) { - item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, state->class, dict, state->s->dest_keybag, &state->s->error); - } else { - item = SecDbItemCreateWithBackupDictionary(kCFAllocatorDefault, state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error); - } - - /* If item is NULL here, control flow ends up at the end where error is cleared. */ - if (item && !SecDbItemEnsureDecrypted(item, true, &state->s->error)) { - secdebug("item", "Failed to import item because of decryption failure: %@", state->s->error); - CFReleaseNull(item); - /* No early return; as just above, go to the end where error is cleared. */ - } - - /* We use the kSecSysBoundItemFilter to indicate that we don't - * preserve rowid's during import. - */ - if (item && item->attributes && state->s->filter == kSecBackupableItemFilter) { - CFTypeRef pdmu; - - /* We don't filter non sys_bound items during import since we know we - * will never have any in this case. - */ - if (SecItemIsSystemBound(item->attributes, state->class, inMultiUser)) { - secdebug("item", "skipping backup of item: %@", dict); - CFReleaseNull(item); - return; - } - - /* - * Don't bother with u items when in edu mode since our current backup system - * don't keep track of items that blongs to the device (u) but rather just - * merge them into one blob. - */ - if (inMultiUser && (pdmu = CFDictionaryGetValue(item->attributes, kSecAttrAccessible))) { - if (CFEqual(pdmu, kSecAttrAccessibleWhenUnlockedThisDeviceOnly) || - CFEqual(pdmu, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) || - CFEqual(pdmu, kSecAttrAccessibleWhenUnlockedThisDeviceOnly) || - CFEqual(pdmu, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) - { - secdebug("item", "Skipping KU item : %@", dict); - CFReleaseNull(item); - return; - } - } - - /* Avoid importing token-based items. Although newer backups should not have them, - * older (iOS9, iOS10.0) produced backups with token-based items. - */ - if (CFDictionaryContainsKey(item->attributes, kSecAttrTokenID)) { - secdebug("item", "Skipping token-based item : %@", dict); - CFReleaseNull(item); - return; - } - } - - /* - * - */ - - if (item && item->attributes) { - CFDataRef musr = NULL; - CFDataRef musrBackup = CFDictionaryGetValue(item->attributes, kSecAttrMultiUser); - CFDataRef systemKeychainUUID = SecMUSRGetSystemKeychainUUID(); - bool systemKeychain = CFEqualSafe(musrBackup, systemKeychainUUID); - -#if TARGET_OS_IPHONE - if (state->s->client && state->s->client->inMultiUser) { - if (systemKeychain) { - secwarning("system keychain not allowed in multi user mode for item: %@", item); - } else { - musr = SecMUSRCreateActiveUserUUID(state->s->client->uid); - } - } else -#endif - { - if (systemKeychain) { - musr = SecMUSRCopySystemKeychainUUID(); - } else { - musr = SecMUSRGetSingleUserKeychainUUID(); - CFRetainSafe(musr); - } - } - if (musr == NULL) { - CFReleaseNull(item); - } else { - SecDbItemSetValueWithName(item, CFSTR("musr"), musr, &state->s->error); - CFRelease(musr); - } - } - - /* - * - */ - - if (item) { - bool insertStatus; - - if(state->s->filter != kSecSysBoundItemFilter) { - SecDbItemExtractRowIdFromBackupDictionary(item, dict, &state->s->error); - } - SecDbItemInferSyncable(item, &state->s->error); - insertStatus = SecDbItemInsert(item, state->s->dbt, &state->s->error); - if (!insertStatus) { - /* - When running in EduMode, multiple users share the same - keychain and unfortionaly the rowid is used a - persistant reference and is part of the contraints (its - UNIQUE), so lets clear the rowid and try to insert the - entry again. - - This even happens for normal operation because of - SysBound entries, so in case of a failure, lets try - again to insert the record. - */ - SecDbItemClearRowId(item, NULL); - SecDbItemInsert(item, state->s->dbt, &state->s->error); - } - } - - /* Reset error if we had one, since we just skip the current item - and continue importing what we can. */ - if (state->s->error) { - secwarning("Failed to import an item (%@) of class '%@': %@ - ignoring error.", - item, state->class->name, state->s->error); - CFReleaseNull(state->s->error); - } - - CFReleaseSafe(item); -} - -static void SecServerImportClass(const void *key, const void *value, - void *context) { - struct SecServerImportClassState *state = - (struct SecServerImportClassState *)context; - if (state->error) - return; - if (!isString(key)) { - SecError(errSecParam, &state->error, CFSTR("class name %@ is not a string"), key); - return; - } - /* ignore the Keybag UUID */ - if (CFEqual(key, kSecBackupKeybagUUIDKey)) - return; - const SecDbClass *class = kc_class_with_name(key); - if (!class) { - secwarning("Ignoring unknown key class '%@'", key); - return; - } - if (class == identity_class()) { - SecError(errSecParam, &state->error, CFSTR("attempt to import an identity")); - return; - } - struct SecServerImportItemState item_state = { - .class = class, .s = state, - }; - if (isArray(value)) { - CFArrayRef items = (CFArrayRef)value; - secwarning("Import %ld items of class %@ (filter %d)", (long)CFArrayGetCount(items), key, state->filter); - SecSignpostBackupCount(SecSignpostImpulseRestoreClassCount, class->name, CFArrayGetCount(items), state->filter); - CFArrayApplyFunction(items, CFRangeMake(0, CFArrayGetCount(items)), - SecServerImportItem, &item_state); - } else if (isDictionary(value)) { - CFDictionaryRef item = (CFDictionaryRef)value; - secwarning("Import %ld items of class %@ (filter %d)", (long)1, key, state->filter); - SecSignpostBackupCount(SecSignpostImpulseRestoreClassCount, class->name, 1, state->filter); - SecServerImportItem(item, &item_state); - } else { - secwarning("Unknown value type for class %@ (filter %d)", key, state->filter); - } -} - -bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, SecurityClient *client, - keybag_handle_t src_keybag, keybag_handle_t dest_keybag, - CFDictionaryRef keychain, enum SecItemFilter filter, - bool removeKeychainContent, CFErrorRef *error) { - CFStringRef keybaguuid = NULL; - bool ok = true; - - CFDictionaryRef sys_bound = NULL; - if (filter == kSecBackupableItemFilter) { - /* Grab a copy of all the items for which SecItemIsSystemBound() - returns true. */ - require(sys_bound = SecServerCopyKeychainPlist(dbt, client, KEYBAG_DEVICE, - KEYBAG_NONE, kSecSysBoundItemFilter, - error), errOut); - } - - /* - * Validate the uuid of the source keybag matches what we have in the backup - */ - keybaguuid = SecCreateKeybagUUID(src_keybag); - if (keybaguuid) { - CFStringRef uuid = CFDictionaryGetValue(keychain, kSecBackupKeybagUUIDKey); - if (isString(uuid)) { - require_action(CFEqual(keybaguuid, uuid), errOut, - SecError(errSecDecode, error, CFSTR("Keybag UUID (%@) mismatch with backup (%@)"), - keybaguuid, uuid)); - } - } - -#if TARGET_OS_IOS - /* - * Shared iPad is very special, it always delete's the user keychain, and never merge content - */ - if (client->inMultiUser) { - CFDataRef musrView = SecMUSRCreateActiveUserUUID(client->uid); - require_action(musrView, errOut, ok = false); - require_action(ok = SecServerDeleteAllForUser(dbt, musrView, true, error), errOut, CFReleaseNull(musrView)); - CFReleaseNull(musrView); - } else -#endif - { - /* - * Delete everything in the keychain. - * We don't want this if we're restoring backups because we probably already synced stuff over - */ - if (removeKeychainContent) { - require(ok = SecServerDeleteAll(dbt, error), errOut); - } else { - // Custom hack to support bluetooth's workflow for 11.3. Should be removed in a future release. - __block CFErrorRef btError = NULL; - bool deletedBT = kc_transaction(dbt, &btError, ^bool{ - -#define EXCLUDE_AGRPS "'com.apple.security.sos', 'com.apple.security.sos-usercredential', 'com.apple.security.ckks', 'com.apple.security.egoIdentities', 'com.apple.security.octagon'" - - bool tok = SecDbExec(dbt, CFSTR("DELETE FROM genp WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); - tok &= SecDbExec(dbt, CFSTR("DELETE FROM inet WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); - tok &= SecDbExec(dbt, CFSTR("DELETE FROM cert WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); - tok &= SecDbExec(dbt, CFSTR("DELETE FROM keys WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); - -#undef EXCLUDE_AGRPS - return tok; - }); - if (!deletedBT) { - secerror("Unable to delete nonsyncable items prior to keychain restore: %@", btError); - } else { - secnotice("restore", "Successfully deleted nonsyncable items"); - } - CFReleaseNull(btError); - } - } - - struct SecServerImportClassState state = { - .dbt = dbt, - .src_keybag = src_keybag, - .dest_keybag = dest_keybag, - .client = client, - .filter = filter, - }; - /* Import the provided items, preserving rowids. */ - secwarning("Restoring backup items '%ld'", (long)CFDictionaryGetCount(keychain)); - CFDictionaryApplyFunction(keychain, SecServerImportClass, &state); - - if (sys_bound) { - state.src_keybag = KEYBAG_NONE; - /* Import the items we preserved with random rowids. */ - state.filter = kSecSysBoundItemFilter; - secwarning("Restoring sysbound items '%ld'", (long)CFDictionaryGetCount(sys_bound)); - CFDictionaryApplyFunction(sys_bound, SecServerImportClass, &state); - } - if (state.error) { - if (error) { - CFReleaseSafe(*error); - *error = state.error; - } else { - CFRelease(state.error); - } - ok = false; - } - - // If CKKS had spun up, it's very likely that we just deleted its data. - // Tell it to perform a local resync. -#if OCTAGON - SecCKKSPerformLocalResync(); -#endif - -errOut: - CFReleaseSafe(sys_bound); - CFReleaseSafe(keybaguuid); - - return ok; -} - -CFStringRef -SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error) -{ - CFStringRef uuid = CFDictionaryGetValue(keychain, kSecBackupKeybagUUIDKey); - if (!isString(uuid)) { - SecError(errSecDecode, error, CFSTR("Missing or invalid %@ in backup dictionary"), kSecBackupKeybagUUIDKey); - return NULL; - } - return uuid; -} - -#pragma mark - key rolling support -#if USE_KEYSTORE - -struct check_generation_ctx { - struct s3dl_query_ctx query_ctx; - uint32_t current_generation; -}; - -static void check_generation(sqlite3_stmt *stmt, void *context) { - struct check_generation_ctx *c = context; - CFDataRef blob = NULL; - size_t blobLen = 0; - const uint8_t *cursor = NULL; - uint32_t version; - keyclass_t keyclass; - uint32_t current_generation = c->current_generation; - - require(blob = s3dl_copy_data_from_col(stmt, 1, &c->query_ctx.q->q_error), out); - blobLen = CFDataGetLength(blob); - cursor = CFDataGetBytePtr(blob); - - /* Check for underflow, ensuring we have at least one full AES block left. */ - if (blobLen < sizeof(version) + sizeof(keyclass)) { - SecError(errSecDecode, &c->query_ctx.q->q_error, CFSTR("check_generation: Check for underflow")); - goto out; - } - - version = *((uint32_t *)cursor); - cursor += sizeof(version); - - (void) version; // TODO: do something with the version number. - - keyclass = *((keyclass_t *)cursor); - - // TODO: export get_key_gen macro - if (((keyclass & ~key_class_last) == 0) != (current_generation == 0)) { - c->query_ctx.found++; - } - - CFReleaseSafe(blob); - return; - -out: - c->query_ctx.found++; - CFReleaseSafe(blob); -} - -bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, CFErrorRef *error) { - CFErrorRef localError = NULL; - struct check_generation_ctx ctx = { .query_ctx = { .dbt = dbt }, .current_generation = current_generation }; - - const SecDbClass *classes[] = { - genp_class(), - inet_class(), - keys_class(), - cert_class(), - }; - - for (size_t class_ix = 0; class_ix < array_size(classes); ++class_ix) { - Query *q = query_create(classes[class_ix], NULL, NULL, &localError); - if (!q) - return false; - - ctx.query_ctx.q = q; - q->q_limit = kSecMatchUnlimited; - - bool ok = s3dl_query(check_generation, &ctx, &localError); - query_destroy(q, NULL); - CFReleaseNull(ctx.query_ctx.result); - - if (!ok && localError && (CFErrorGetCode(localError) == errSecItemNotFound)) { - CFReleaseNull(localError); - continue; - } - secerror("Class %@ not up to date", classes[class_ix]->name); - return false; - } - return true; -} - -bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, SecurityClient *client, CFErrorRef *error) { - return SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - __block bool ok = false; - uint32_t keystore_generation_status; - - /* can we migrate to new class keys right now? */ - if (!aks_generation(KEYBAG_DEVICE, generation_noop, &keystore_generation_status) && - (keystore_generation_status & generation_change_in_progress)) { - - /* take a lock assertion */ - bool operated_while_unlocked = SecAKSDoWithUserBagLockAssertion(error, ^{ - CFErrorRef localError = NULL; - CFDictionaryRef backup = SecServerCopyKeychainPlist(dbt, NULL, - KEYBAG_DEVICE, KEYBAG_NONE, kSecNoItemFilter, &localError); - if (backup) { - if (localError) { - secerror("Ignoring export error: %@ during roll export", localError); - CFReleaseNull(localError); - } - // 'true' argument: we're replacing everything with newly wrapped entries so remove the old stuff - ok = SecServerImportKeychainInPlist(dbt, client, KEYBAG_NONE, - KEYBAG_DEVICE, backup, kSecNoItemFilter, true, &localError); - if (localError) { - secerror("Ignoring export error: %@ during roll export", localError); - CFReleaseNull(localError); - } - CFRelease(backup); - } - }); - if (!operated_while_unlocked) - ok = false; - } else { - ok = SecError(errSecBadReq, error, CFSTR("No key roll in progress.")); - } - - *commit = ok; - }); -} -#endif diff --git a/OSX/sec/securityd/SecItemDb.h b/OSX/sec/securityd/SecItemDb.h deleted file mode 100644 index 9cb34658..00000000 --- a/OSX/sec/securityd/SecItemDb.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemDb.h - A Database full of SecDbItems. - */ - -#ifndef _SECURITYD_SECITEMDB_H_ -#define _SECURITYD_SECITEMDB_H_ - -#include - -struct SecurityClient; - -__BEGIN_DECLS - -bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error); - -bool SecItemDbDeleteSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFErrorRef *error); - -CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error); - -bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, - bool (^return_attr)(const SecDbAttr *attr), - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col), - void (^handle_row)(SecDbItemRef item, bool *stop)); - -CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query, - bool (^return_attr)(const SecDbAttr *attr), - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)); -bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error, - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col)); - -bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error, - void (^handle_row)(SecDbItemRef item, bool *stop)); - -void query_pre_add(Query *q, bool force_date); - -bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser); - -// -// MARK: backup restore stuff -// - -/* Forward declaration of import export SPIs. */ -enum SecItemFilter { - kSecNoItemFilter, - kSecSysBoundItemFilter, - kSecBackupableItemFilter, -}; - -CFDictionaryRef SecServerCopyKeychainPlist(SecDbConnectionRef dbt, - struct SecurityClient *client, - keybag_handle_t src_keybag, - keybag_handle_t dest_keybag, - enum SecItemFilter filter, - CFErrorRef *error); -bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, - struct SecurityClient *client, - keybag_handle_t src_keybag, - keybag_handle_t dest_keybag, - CFDictionaryRef keychain, - enum SecItemFilter filter, - bool removeKeychainContent, - CFErrorRef *error); - -CFStringRef -SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error); - - -#if TARGET_OS_IPHONE -bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool keepU, CFErrorRef *error); -#endif - -bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)(void)); -bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)(void)); -bool s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, - CFArrayRef accessGroups, CFErrorRef *error); -bool s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error); -bool s3dl_query_update(SecDbConnectionRef dbt, Query *q, - CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error); -bool s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error); -bool s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error); - -const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, CFTypeRef key, CFErrorRef *error); - -bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, CFErrorRef *error); -bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, struct SecurityClient *client, CFErrorRef *error); - -// We'd love to take a query here, but switching layers at the callsite means we don't have it -bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error); - -__END_DECLS - -#endif /* _SECURITYD_SECITEMDB_H_ */ diff --git a/OSX/sec/securityd/SecItemSchema.c b/OSX/sec/securityd/SecItemSchema.c deleted file mode 100644 index 5b5b7dce..00000000 --- a/OSX/sec/securityd/SecItemSchema.c +++ /dev/null @@ -1,2992 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecItemSchema.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include "SecItemSchema.h" -#include -#include -#include "CheckV12DevEnabled.h" - -// MARK - -// MARK Keychain version 6 schema - -#define __FLAGS(ARG, ...) SECDBFLAGS(__VA_ARGS__) -#define SECDBFLAGS(ARG, ...) __FLAGS_##ARG | __FLAGS(__VA_ARGS__) - -#define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N,U,V,Y) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N|__FLAGS_##U|__FLAGS_##V|__FLAGS_##Y) - -#define __FLAGS_ 0 -#define __FLAGS_P kSecDbPrimaryKeyFlag -#define __FLAGS_L kSecDbInFlag -#define __FLAGS_I kSecDbIndexFlag -#define __FLAGS_S kSecDbSHA1ValueInFlag -#define __FLAGS_A kSecDbReturnAttrFlag -#define __FLAGS_D kSecDbReturnDataFlag -#define __FLAGS_R kSecDbReturnRefFlag -#define __FLAGS_C kSecDbInCryptoDataFlag -#define __FLAGS_H kSecDbInHashFlag -#define __FLAGS_B kSecDbInBackupFlag -#define __FLAGS_Z kSecDbDefault0Flag -#define __FLAGS_E kSecDbDefaultEmptyFlag -#define __FLAGS_N kSecDbNotNullFlag -#define __FLAGS_U kSecDbInAuthenticatedDataFlag -#define __FLAGS_V0 kSecDbSyncPrimaryKeyV0 -#define __FLAGS_V2 (kSecDbSyncPrimaryKeyV0 | kSecDbSyncPrimaryKeyV2) -#define __FLAGS_Y kSecDbSyncFlag - -// ,----------------- P : Part of primary key -// / ,---------------- L : Stored in local database -// / / ,--------------- I : Attribute wants an index in the database -// / / / ,-------------- S : SHA1 hashed attribute value in database (implies L) -// / / / / ,------------- A : Returned to client as attribute in queries -// / / / / / ,------------ D : Returned to client as data in queries -// / / / / / / ,----------- R : Returned to client as ref/persistent ref in queries -// / / / / / / / ,---------- C : Part of encrypted blob -// / / / / / / / / ,--------- H : Attribute is part of item SHA1 hash (Implied by C) -// / / / / / / / / / ,-------- B : Attribute is part of iTunes/iCloud backup bag -// / / / / / / / / / / ,------- Z : Attribute has a default value of 0 -// / / / / / / / / / / / ,------ E : Attribute has a default value of "" or empty data -// / / / / / / / / / / / / ,----- N : Attribute must have a value -// / / / / / / / / / / / / / ,---- U : Attribute is stored in authenticated, but not necessarily encrypted data -// / / / / / / / / / / / / / / ,--- V0: Sync primary key version -// / / / / / / / / / / / / / / / ,- Y : Attribute should be synced -// | | | | | | | | | | | | | | | | -// common to all | | | | | | | | | | | | | | | | -SECDB_ATTR(v6rowid, "rowid", RowId, SecDbFlags( ,L, , , , ,R, , ,B, , , , , , ), NULL, NULL); -SECDB_ATTR(v6cdat, "cdat", CreationDate, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), SecDbKeychainItemCopyCurrentDate, NULL); -SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), SecDbKeychainItemCopyCurrentDate, NULL); -SECDB_ATTR(v6labl, "labl", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6data, "data", EncryptedData, SecDbFlags( ,L, , , , , , , ,B, , , , , , ), SecDbKeychainItemCopyEncryptedData, NULL); -SECDB_ATTR(v6agrp, "agrp", String, SecDbFlags(P,L,I, ,A, , , ,H, , , ,N,U,V0,Y), NULL, NULL); -SECDB_ATTR(v6pdmn, "pdmn", Access, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6sync, "sync", Sync, SecDbFlags(P,L,I, ,A, , , ,H, ,Z, ,N,U,V0, ), NULL, NULL); -SECDB_ATTR(v6tomb, "tomb", Tomb, SecDbFlags( ,L, , , , , , ,H, ,Z, ,N,U, ,Y), NULL, NULL); -SECDB_ATTR(v6sha1, "sha1", SHA1, SecDbFlags( ,L,I, ,A, ,R, , , , , , , , ,Y), SecDbKeychainItemCopySHA1, NULL); -SECDB_ATTR(v6accc, "accc", AccessControl, SecDbFlags( , , , ,A, , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v6v_Data, "v_Data", Data, SecDbFlags( , , , , ,D, ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey, SecDbFlags( , , , , , , , , , , , , , , , ), SecDbKeychainItemCopyPrimaryKey, NULL); -SECDB_ATTR(v7vwht, "vwht", String, SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL); -SECDB_ATTR(v7tkid, "tkid", String, SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL); -SECDB_ATTR(v7utomb, "u_Tomb", UTomb, SecDbFlags( , , , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v8musr, "musr", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N,U, ,Y), NULL, NULL); -// genp and inet and keys | | | | | | | | | | | | | | | | -SECDB_ATTR(v6crtr, "crtr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6alis, "alis", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -// genp and inet | | | | | | | | | | | | | | | | -SECDB_ATTR(v6desc, "desc", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6icmt, "icmt", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6type, "type", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6invi, "invi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6nega, "nega", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6cusi, "cusi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6prot, "prot", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6scrp, "scrp", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6acct, "acct", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -// genp only | | | | | | | | | | | | | | | | -SECDB_ATTR(v6svce, "svce", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6gena, "gena", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -// inet only | | | | | | | | | | | | | | | | -SECDB_ATTR(v6sdmn, "sdmn", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6srvr, "srvr", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6ptcl, "ptcl", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6atyp, "atyp", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6port, "port", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6path, "path", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -// cert only | | | | | | | | | | | | | | | | -SECDB_ATTR(v6ctyp, "ctyp", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6cenc, "cenc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6subj, "subj", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6issr, "issr", Data, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6slnr, "slnr", Data, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6skid, "skid", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6pkhh, "pkhh", Data, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -// cert attributes that share names with common ones but have different flags -SECDB_ATTR(v6certalis, "alis", Blob, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); -// keys only | | | | | | | | | | | | | | | | -SECDB_ATTR(v6kcls, "kcls", Number, SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6perm, "perm", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6priv, "priv", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6modi, "modi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6klbl, "klbl", Data, SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6atag, "atag", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6bsiz, "bsiz", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6esiz, "esiz", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6sdat, "sdat", Date, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6edat, "edat", Date, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6sens, "sens", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6asen, "asen", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6extr, "extr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6next, "next", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6encr, "encr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6decr, "decr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6drve, "drve", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6sign, "sign", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6vrfy, "vrfy", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6snrc, "snrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6vyrc, "vyrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6wrap, "wrap", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v6unwp, "unwp", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -// keys attributes that share names with common ones but have different flags -SECDB_ATTR(v6keytype, "type", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -SECDB_ATTR(v6keycrtr, "crtr", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); -// | | | | | | | | | | | | | | | -SECDB_ATTR(v6version, "version", Number, SecDbFlags(P,L,I, , , , , , , , , ,N, , ,Y), NULL, NULL); -SECDB_ATTR(v91minor, "minor", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , ,Y), NULL, NULL); - -SECDB_ATTR(v10_1pcsservice, "pcss", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v10_1pcspublickey, "pcsk", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); -SECDB_ATTR(v10_1pcspublicidentity,"pcsi", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); - -SECDB_ATTR(v10itemuuid, "UUID", String, SecDbFlags( ,L,I, , , , , , , , , , ,U, , ), NULL, NULL); -SECDB_ATTR(v10syncuuid, "UUID", String, SecDbFlags(P,L,I, , , , , , , , , , ,U, , ), NULL, NULL); -SECDB_ATTR(v10parentKeyUUID, "parentKeyUUID", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10currentKeyUUID,"currentKeyUUID",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10wrappedkey, "wrappedkey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10encrypteditem, "encitem", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10gencount, "gencount", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); -SECDB_ATTR(v10action, "action", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10state, "state", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10waituntiltime, "waituntil", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10encodedCKRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_1wasCurrent, "wascurrent", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10accessgroup, "accessgroup", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10keyclass, "keyclass", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10currentkey, "currentkey", Number, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10ckzone, "ckzone", String, SecDbFlags(P,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10ckzonecreated, "ckzonecreated", Number, SecDbFlags( ,L, , , , , , , , ,Z, , ,N, , ), NULL, NULL); -SECDB_ATTR(v10ckzonesubscribed,"ckzonesubscribed", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); -SECDB_ATTR(v10ratelimiter, "ratelimiter", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10changetoken, "changetoken", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10lastfetchtime, "lastfetch", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10itempersistentref,"persistref", UUID, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10sysbound, "sysb", Number, SecDbFlags( ,L, , ,A, , ,C,H, ,Z, , , , , ), NULL, NULL); -SECDB_ATTR(v10encryptionver, "encver", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N,U, , ), NULL, NULL); - -SECDB_ATTR(v10primaryKey, "primaryKey", String, SecDbFlags(P,L,I, ,A, , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10publickeyHash, "publickeyHash", Blob, SecDbFlags(P,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10publickey, "publickey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10backupData, "backupData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); - -SECDB_ATTR(v10_1digest, "digest", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1signatures, "signatures", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1signerID, "signerID", String, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1leafIDs, "leafIDs", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1peerManIDs, "peerManifests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1entryDigests,"entryDigests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_2currentItems,"currentItems", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_2futureData, "futureData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_2schema, "schema", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); -SECDB_ATTR(v10_1encRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v10_1keyArchiveHash, "key_archive_hash", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_1keyArchive, "key_archive", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_1archivedKey, "archived_key", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_1keyArchiveName, "keyarchive_name", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_1optionalEncodedCKRecord, "ckrecord", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_1archiveEscrowID,"archive_escrowid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v10_1itempersistentref,"persistref", UUID, SecDbFlags( ,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); - -SECDB_ATTR(v10_1currentItemUUID,"currentItemUUID",String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_4currentItemUUID,"currentItemUUID",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_1currentPtrIdentifier,"identifier",String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v10_2device, "device", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2peerid, "peerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2circleStatus,"circlestatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2keyState, "keystate", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2currentTLK, "currentTLK", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2currentClassA,"currentClassA",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_2currentClassC,"currentClassC",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v10_4lastFixup, "lastfixup", Number, SecDbFlags( ,L, , , , , , , , ,Z, , ,N, , ), NULL, NULL); - -SECDB_ATTR(v10_5senderPeerID,"senderpeerid", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_5recvPeerID, "recvpeerid", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_5recvPubKey, "recvpubenckey", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_5curve, "curve", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_5poisoned, "poisoned", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_5epoch, "epoch", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); -SECDB_ATTR(v10_5signature, "signature", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v10_5version, "version", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N,U, , ), NULL, NULL); - -SECDB_ATTR(v11_1osversion, "osversion", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v11_1lastunlock, "lastunlock", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v11_2actualKeyclass, "actualKeyclass", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v11_5octagonpeerid, "octagonpeerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v11_5octagonStatus, "octagonstatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); - -SECDB_ATTR(v12_backupUUIDPrimary, "backupUUID", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v12_backupUUID, "backupUUID", UUID, SecDbFlags( ,L,I, , , , , , , , ,E, , , , ), NULL, NULL); -SECDB_ATTR(v12_backupBag, "backupbag", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v12_defaultValue, "defaultvalue", Number, SecDbFlags( ,L,I, , , , , , , ,Z, , , , , ), NULL, NULL); -SECDB_ATTR(v12_keyClassSigningKey, "signingkey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v12_recoveryType, "recoverytype", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v12_recoverySet, "recoveryset", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); -SECDB_ATTR(v12_metadatakeydata, "metadatakeydata", Blob, SecDbFlags( ,L, , , , , , , , , ,E, , , , ), NULL, NULL); - -const SecDbClass v12_backupbags_class = { - .name = CFSTR("backupbags"), - .itemclass = false, - .attrs = { - &v12_backupUUIDPrimary, // primary - &v12_backupBag, - &v12_defaultValue, - 0 - } -}; - -const SecDbClass v12_backupkeyclasssigningkeys_class = { - .name = CFSTR("backupkeyclasssigningkeys"), - .itemclass = false, - .attrs = { - &v10keyclass, // primary - &v12_backupUUIDPrimary, // primary - &v12_keyClassSigningKey, - 0 - } -}; - -const SecDbClass v12_backuprecoverysets_class = { - .name = CFSTR("backuprecoverysets"), - .itemclass = false, - .attrs = { - &v12_backupUUIDPrimary, // primary - &v12_recoveryType, // primary - &v12_recoverySet, - 0 - } -}; - -const SecDbClass v12_metadatakeys_class = { - .name = CFSTR("metadatakeys"), - .itemclass = false, - .attrs = { - &v10keyclass, - &v11_2actualKeyclass, - &v6data, - &v12_metadatakeydata, - 0 - } -}; - -const SecDbClass v12_genp_class = { - .name = CFSTR("genp"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - &v12_backupUUID, - 0 - }, -}; - -const SecDbClass v12_inet_class = { - .name = CFSTR("inet"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - &v12_backupUUID, - 0 - }, -}; - -const SecDbClass v12_cert_class = { - .name = CFSTR("cert"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - &v12_backupUUID, - 0 - }, -}; - -const SecDbClass v12_keys_class = { - .name = CFSTR("keys"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - &v12_backupUUID, - 0 - } -}; - -const SecDbClass v11_5_ckdevicestate_class = { - .name = CFSTR("ckdevicestate"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10_2device, - &v11_1osversion, - &v11_1lastunlock, - &v10_2peerid, - &v10_2circleStatus, - &v11_5octagonpeerid, - &v11_5octagonStatus, - &v10_2keyState, - &v10_2currentTLK, - &v10_2currentClassA, - &v10_2currentClassC, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v11_2_metadatakeys_class = { - .name = CFSTR("metadatakeys"), - .itemclass = false, - .attrs = { - &v10keyclass, - &v11_2actualKeyclass, - &v6data, - 0 - } -}; - -const SecDbClass v11_1_ckdevicestate_class = { - .name = CFSTR("ckdevicestate"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10_2device, - &v11_1osversion, - &v11_1lastunlock, - &v10_2peerid, - &v10_2circleStatus, - &v10_2keyState, - &v10_2currentTLK, - &v10_2currentClassA, - &v10_2currentClassC, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v11_metadatakeys_class = { - .name = CFSTR("metadatakeys"), - .itemclass = false, - .attrs = { - &v10keyclass, - &v6data, - 0 - } -}; - -const SecDbClass v10_5_tlkshare_class = { - .name = CFSTR("tlkshare"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10_5senderPeerID, - &v10_5recvPeerID, - &v10_5recvPubKey, - &v10_5curve, - &v10_5poisoned, - &v10_5epoch, - &v10wrappedkey, - &v10_5signature, - &v10_1encRecord, - &v10_5version, - 0 - } -}; - - -const SecDbClass v10_4_current_item_class = { - .name = CFSTR("currentitems"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10_1currentPtrIdentifier, - &v10_4currentItemUUID, - &v10state, - &v10encodedCKRecord, - 0 - } -}; - -const SecDbClass v10_4_ckstate_class = { - .name = CFSTR("ckstate"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10ckzonecreated, - &v10ckzonesubscribed, - &v10lastfetchtime, - &v10changetoken, - &v10ratelimiter, - &v10_4lastFixup, - 0 - } -}; - -const SecDbClass v10_3_ckdevicestate_class = { - .name = CFSTR("ckdevicestate"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10_2device, - &v10_2peerid, - &v10_2circleStatus, - &v10_2keyState, - &v10_2currentTLK, - &v10_2currentClassA, - &v10_2currentClassC, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_2_ckmanifest_class = { - .name = CFSTR("ckmanifest"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10gencount, - &v10_1digest, - &v10_1signatures, - &v10_1signerID, - &v10_1leafIDs, - &v10_1peerManIDs, - &v10_2currentItems, - &v10_2futureData, - &v10_2schema, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_2_pending_manifest_class = { - .name = CFSTR("pending_manifest"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10gencount, - &v10_1digest, - &v10_1signatures, - &v10_1signerID, - &v10_1leafIDs, - &v10_1peerManIDs, - &v10_2currentItems, - &v10_2futureData, - &v10_2schema, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_1_ckmanifest_class = { - .name = CFSTR("ckmanifest"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10gencount, - &v10_1digest, - &v10_1signatures, - &v10_1signerID, - &v10_1leafIDs, - &v10_1peerManIDs, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_1_pending_manifest_class = { - .name = CFSTR("pending_manifest"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10gencount, - &v10_1digest, - &v10_1signatures, - &v10_1signerID, - &v10_1leafIDs, - &v10_1peerManIDs, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_1_ckmanifest_leaf_class = { - .name = CFSTR("ckmanifest_leaf"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10_1digest, - &v10_1entryDigests, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_1_pending_manifest_leaf_class = { - .name = CFSTR("pending_manifest_leaf"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10_1digest, - &v10_1entryDigests, - &v10_1encRecord, - 0 - } -}; - -const SecDbClass v10_1_genp_class = { - .name = CFSTR("genp"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - 0 - }, -}; - -const SecDbClass v10_1_inet_class = { - .name = CFSTR("inet"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - 0 - }, -}; - -const SecDbClass v10_1_cert_class = { - .name = CFSTR("cert"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - 0 - }, -}; - -const SecDbClass v10_1_keys_class = { - .name = CFSTR("keys"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10sysbound, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - &v10_1itempersistentref, - 0 - } -}; - -const SecDbClass v10_0_tversion_class = { - .name = CFSTR("tversion"), - .itemclass = false, - .attrs = { - &v6rowid, - &v6version, - &v91minor, - 0 - } -}; - -const SecDbClass v10_2_outgoing_queue_class = { - .name = CFSTR("outgoingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10waituntiltime, - &v10accessgroup, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - &v10_1optionalEncodedCKRecord, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - 0 - } -}; - -const SecDbClass v10_2_incoming_queue_class = { - .name = CFSTR("incomingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - &v10_1optionalEncodedCKRecord, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - 0 - } -}; - - -const SecDbClass v10_1_outgoing_queue_class = { - .name = CFSTR("outgoingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10waituntiltime, - &v10accessgroup, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - 0 - } -}; - -const SecDbClass v10_1_incoming_queue_class = { - .name = CFSTR("incomingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - 0 - } -}; - - -const SecDbClass v10_0_outgoing_queue_class = { - .name = CFSTR("outgoingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10waituntiltime, - &v10accessgroup, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - 0 - } -}; - -const SecDbClass v10_0_incoming_queue_class = { - .name = CFSTR("incomingqueue"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10action, - &v10state, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encryptionver, - 0 - } -}; - -const SecDbClass v10_0_sync_key_class = { - .name = CFSTR("synckeys"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10keyclass, - &v10currentkey, - &v10parentKeyUUID, - &v10state, - &v10wrappedkey, - &v10encodedCKRecord, - 0 - } -}; - -// Stores the "Current Key" records, and parentKeyUUID refers to items in the synckeys table -// Wouldn't foreign keys be nice? -const SecDbClass v10_0_current_key_class = { - .name = CFSTR("currentkeys"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10keyclass, - &v10currentKeyUUID, - &v10encodedCKRecord, - 0 - } -}; - -const SecDbClass v10_1_current_item_class = { - .name = CFSTR("currentitems"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10_1currentPtrIdentifier, - &v10_1currentItemUUID, - &v10state, - &v10encodedCKRecord, - 0 - } -}; - -const SecDbClass v10_1_ckmirror_class = { - .name = CFSTR("ckmirror"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encodedCKRecord, - &v10encryptionver, - &v10_1wasCurrent, - &v10_1pcsservice, - &v10_1pcspublickey, - &v10_1pcspublicidentity, - 0 - } -}; - -const SecDbClass v10_0_ckmirror_class = { - .name = CFSTR("ckmirror"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10syncuuid, - &v10parentKeyUUID, - &v10gencount, - &v10wrappedkey, - &v10encrypteditem, - &v10encodedCKRecord, - &v10encryptionver, - 0 - } -}; - -const SecDbClass v10_0_ckstate_class = { - .name = CFSTR("ckstate"), - .itemclass = false, - .attrs = { - &v10ckzone, - &v10ckzonecreated, - &v10ckzonesubscribed, - &v10lastfetchtime, - &v10changetoken, - &v10ratelimiter, - 0 - } -}; - -/* Backup table */ -/* Primary keys: v10primaryKey, v8musr */ -/* This table is currently unused */ -const SecDbClass v10_0_item_backup_class = { - .name = CFSTR("item_backup"), - .itemclass = false, - .attrs = { - &v6rowid, - &v10primaryKey, // Primary key of the original item, from v6v_pk - &v8musr, // - &v6sha1, // Hash of the original item - &v10backupData, // Data wrapped to backup keybag - &v6pkhh, // Hash of the public key of the backup bag [v10publickeyHash] - 0 - } -}; - -/* Backup Keybag table */ -/* Primary keys: v10publickeyHash, v8musr */ -/* This table is currently unused */ -const SecDbClass v10_0_backup_keybag_class = { - .name = CFSTR("backup_keybag"), - .itemclass = false, - .attrs = { - &v6rowid, - &v10publickeyHash, // Hash of the public key of the backup bag - &v8musr, // - &v10publickey, // Public key for the asymmetric backup bag - &v6agrp, // Used for backup agent - 0 - } -}; - -const SecDbClass v10_1_backup_keyarchive_class = { - .name = CFSTR("backup_keyarchive"), - .itemclass = false, - .attrs = { - &v10_1keyArchiveHash, // Hash of the key archive - &v8musr, // - &v10_1keyArchive, // Serialised key archive - &v10ckzone, - &v10_1optionalEncodedCKRecord, - &v10_1archiveEscrowID, - 0 - } -}; - -const SecDbClass v10_1_current_archived_keys_class = { - .name = CFSTR("archived_key_backup"), - .itemclass = false, - .attrs = { - &v6pdmn, - &v10syncuuid, - &v8musr, - &v6agrp, - &v10_1keyArchiveHash, - &v10_1archivedKey, - &v10ckzone, - &v10_1optionalEncodedCKRecord, - &v10_1archiveEscrowID, - 0 - } -}; - -const SecDbClass v10_1_current_keyarchive_class = { - .name = CFSTR("currentkeyarchives"), - .itemclass = false, - .attrs = { - &v10_1keyArchiveHash, - &v10_1keyArchiveName, - 0 - } -}; - -/* An identity which is really a cert + a key, so all cert and keys attrs are - allowed. */ -const SecDbClass v_identity_class = { - .name = CFSTR("idnt"), - .itemclass = true, - .attrs = { - 0 - }, -}; - -/* - * Version 12.0 - * Add backup/restore mechanism - */ -const SecDbSchema v12_0_schema = { - .majorVersion = 12, - .minorVersion = 0, - .classes = { - &v12_genp_class, - &v12_inet_class, - &v12_cert_class, - &v12_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_5_ckdevicestate_class, - &v10_5_tlkshare_class, - &v12_metadatakeys_class, - &v12_backupbags_class, - &v12_backupkeyclasssigningkeys_class, - &v12_backuprecoverysets_class, - 0 - } -}; - -/* - * Version 11.5 (Add octagon fields to device state) - */ -const SecDbSchema v11_5_schema = { - .majorVersion = 11, - .minorVersion = 5, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_5_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_2_metadatakeys_class, - 0 - } -}; - - -/* - * Version 11.4 (Add some more indexes) - */ -const SecDbSchema v11_4_schema = { - .majorVersion = 11, - .minorVersion = 4, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_1_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_2_metadatakeys_class, - 0 - } -}; - -/* - * Version 11.3 (no changes, restores the use of indexes in upgrade code. Gotta go fast!) - */ -const SecDbSchema v11_3_schema = { - .majorVersion = 11, - .minorVersion = 3, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_1_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_2_metadatakeys_class, - 0 - } -}; - -/* - * Version 11.2 - */ -const SecDbSchema v11_2_schema = { - .majorVersion = 11, - .minorVersion = 2, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_1_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_2_metadatakeys_class, - 0 - } -}; - -/* - * Version 11.1 - */ -const SecDbSchema v11_1_schema = { - .majorVersion = 11, - .minorVersion = 1, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v11_1_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_metadatakeys_class, - 0 - } -}; - -/* - * Version 11 - */ -const SecDbSchema v11_schema = { - .majorVersion = 11, - .minorVersion = 0, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v10_3_ckdevicestate_class, - &v10_5_tlkshare_class, - &v11_metadatakeys_class, - 0 - } -}; - - -/* - * Version 10.5 - */ -const SecDbSchema v10_5_schema = { - .majorVersion = 10, - .minorVersion = 5, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v10_3_ckdevicestate_class, - &v10_5_tlkshare_class, - 0 - } -}; - -/* - * Version 10.4 - */ -const SecDbSchema v10_4_schema = { - .majorVersion = 10, - .minorVersion = 4, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_4_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_4_current_item_class, - &v10_3_ckdevicestate_class, - 0 - } -}; - -/* - * Version 10.3 - */ -const SecDbSchema v10_3_schema = { - .majorVersion = 10, - .minorVersion = 3, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_0_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_1_current_item_class, - &v10_3_ckdevicestate_class, - 0 - } -}; - -/* - * Version 10.2 - */ -const SecDbSchema v10_2_schema = { - .majorVersion = 10, - .minorVersion = 2, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_2_outgoing_queue_class, - &v10_2_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_0_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_2_ckmanifest_class, - &v10_2_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_1_current_item_class, - 0 - } -}; - -/* - * Version 10.1 - */ -const SecDbSchema v10_1_schema = { - .majorVersion = 10, - .minorVersion = 1, - .classes = { - &v10_1_genp_class, - &v10_1_inet_class, - &v10_1_cert_class, - &v10_1_keys_class, - &v10_0_tversion_class, - &v10_1_outgoing_queue_class, - &v10_1_incoming_queue_class, - &v10_0_sync_key_class, - &v10_1_ckmirror_class, - &v10_0_current_key_class, - &v10_0_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - &v10_1_ckmanifest_class, - &v10_1_pending_manifest_class, - &v10_1_ckmanifest_leaf_class, - &v10_1_backup_keyarchive_class, - &v10_1_current_keyarchive_class, - &v10_1_current_archived_keys_class, - &v10_1_pending_manifest_leaf_class, - &v10_1_current_item_class, - 0 - } -}; - -/* - * Version 10.0 - */ - -const SecDbClass v10_0_genp_class = { - .name = CFSTR("genp"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10itempersistentref, - &v10sysbound, - 0 - }, -}; - -const SecDbClass v10_0_inet_class = { - .name = CFSTR("inet"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10itempersistentref, - &v10sysbound, - 0 - }, -}; - -const SecDbClass v10_0_cert_class = { - .name = CFSTR("cert"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10itempersistentref, - &v10sysbound, - 0 - }, -}; - -const SecDbClass v10_0_keys_class = { - .name = CFSTR("keys"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - &v10itemuuid, - &v10itempersistentref, - &v10sysbound, - 0 - } -}; - -const SecDbSchema v10_0_schema = { - .majorVersion = 10, - .minorVersion = 0, - .classes = { - &v10_0_genp_class, - &v10_0_inet_class, - &v10_0_cert_class, - &v10_0_keys_class, - &v10_0_tversion_class, - &v10_0_outgoing_queue_class, - &v10_0_incoming_queue_class, - &v10_0_sync_key_class, - &v10_0_ckmirror_class, - &v10_0_current_key_class, - &v10_0_ckstate_class, - &v10_0_item_backup_class, - &v10_0_backup_keybag_class, - 0 - } -}; - -const SecDbClass v9_1_tversion_class = { - .name = CFSTR("tversion91"), - .itemclass = false, - .attrs = { - &v6rowid, - &v6version, - &v91minor, - 0 - } -}; - -const SecDbClass v9_1_genp_class = { - .name = CFSTR("genp91"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9_1_inet_class = { - .name = CFSTR("inet91"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9_1_cert_class = { - .name = CFSTR("cert91"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9_1_keys_class = { - .name = CFSTR("keys91"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - } -}; - -/* - * Version 9.1 (iOS 10.0 and OSX 10.11.8/10.12 addded minor version. - */ -const SecDbSchema v9_1_schema = { - .majorVersion = 9, - .minorVersion = 1, - .classes = { - &v9_1_genp_class, - &v9_1_inet_class, - &v9_1_cert_class, - &v9_1_keys_class, - &v9_1_tversion_class, - 0 - } -}; - -const SecDbClass v9genp_class = { - .name = CFSTR("genp9"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9inet_class = { - .name = CFSTR("inet9"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9cert_class = { - .name = CFSTR("cert9"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v9keys_class = { - .name = CFSTR("keys9"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - } -}; - -const SecDbClass v5tversion_class = { - .name = CFSTR("tversion5"), - .itemclass = false, - .attrs = { - &v6version, - 0 - } -}; - -/* Version 9 (iOS 9.3 and OSX 10.11.5) database schema - * Same contents as v8 tables; table names changed to force upgrade - * and correct default values in table. - */ -const SecDbSchema v9_schema = { - .majorVersion = 9, - .classes = { - &v9genp_class, - &v9inet_class, - &v9cert_class, - &v9keys_class, - &v5tversion_class, - 0 - } -}; - -// Version 8 (Internal release iOS 9.3 and OSX 10.11.5) database schema -const SecDbClass v8genp_class = { - .name = CFSTR("genp8"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v8inet_class = { - .name = CFSTR("inet8"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v8cert_class = { - .name = CFSTR("cert8"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - }, -}; - -const SecDbClass v8keys_class = { - .name = CFSTR("keys8"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - &v8musr, - 0 - } -}; - -const SecDbSchema v8_schema = { - .majorVersion = 8, - .classes = { - &v8genp_class, - &v8inet_class, - &v8cert_class, - &v8keys_class, - &v5tversion_class, - 0 - } -}; - -// Version 7 (iOS 9 and OSX 10.11) database schema -const SecDbClass v7genp_class = { - .name = CFSTR("genp7"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - 0 - }, -}; - -const SecDbClass v7inet_class = { - .name = CFSTR("inet7"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - 0 - }, -}; - -const SecDbClass v7cert_class = { - .name = CFSTR("cert7"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - 0 - }, -}; - -const SecDbClass v7keys_class = { - .name = CFSTR("keys7"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v7vwht, - &v7tkid, - &v6v_Data, - &v6v_pk, - &v6accc, - &v7utomb, - 0 - } -}; - - -const SecDbSchema v7_schema = { - .majorVersion = 7, - .classes = { - &v7genp_class, - &v7inet_class, - &v7cert_class, - &v7keys_class, - &v5tversion_class, - 0 - } -}; - - -// Version 6 (iOS 7 and OSX 10.9) database schema -static const SecDbClass v6genp_class = { - .name = CFSTR("genp6"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v6v_Data, - &v6v_pk, - &v6accc, - 0 - }, -}; - -static const SecDbClass v6inet_class = { - .name = CFSTR("inet6"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v6v_Data, - &v6v_pk, - &v6accc, - 0 - }, -}; - -static const SecDbClass v6cert_class = { - .name = CFSTR("cert6"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v6v_Data, - &v6v_pk, - &v6accc, - 0 - }, -}; - -static const SecDbClass v6keys_class = { - .name = CFSTR("keys6"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6sync, - &v6tomb, - &v6sha1, - &v6v_Data, - &v6v_pk, - &v6accc, - 0 - } -}; - -static const SecDbSchema v6_schema = { - .majorVersion = 6, - .classes = { - &v6genp_class, - &v6inet_class, - &v6cert_class, - &v6keys_class, - &v5tversion_class, - 0 - } -}; - - -// Version 5 (iOS 5 & iOS 6) database schema. -static const SecDbClass v5genp_class = { - .name = CFSTR("genp5"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6svce, - &v6gena, - &v6data, - &v6agrp, - &v6pdmn, - &v6v_Data, - 0 - }, -}; - -static const SecDbClass v5inet_class = { - .name = CFSTR("inet5"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6desc, - &v6icmt, - &v6crtr, - &v6type, - &v6scrp, - &v6labl, - &v6alis, - &v6invi, - &v6nega, - &v6cusi, - &v6prot, - &v6acct, - &v6sdmn, - &v6srvr, - &v6ptcl, - &v6atyp, - &v6port, - &v6path, - &v6data, - &v6agrp, - &v6pdmn, - &v6v_Data, - 0 - }, -}; - -static const SecDbClass v5cert_class = { - .name = CFSTR("cert5"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6ctyp, - &v6cenc, - &v6labl, - &v6certalis, - &v6subj, - &v6issr, - &v6slnr, - &v6skid, - &v6pkhh, - &v6data, - &v6agrp, - &v6pdmn, - &v6v_Data, - 0 - }, -}; - -static const SecDbClass v5keys_class = { - .name = CFSTR("keys5"), - .itemclass = true, - .attrs = { - &v6rowid, - &v6cdat, - &v6mdat, - &v6kcls, - &v6labl, - &v6alis, - &v6perm, - &v6priv, - &v6modi, - &v6klbl, - &v6atag, - &v6keycrtr, - &v6keytype, - &v6bsiz, - &v6esiz, - &v6sdat, - &v6edat, - &v6sens, - &v6asen, - &v6extr, - &v6next, - &v6encr, - &v6decr, - &v6drve, - &v6sign, - &v6vrfy, - &v6snrc, - &v6vyrc, - &v6wrap, - &v6unwp, - &v6data, - &v6agrp, - &v6pdmn, - &v6v_Data, - 0 - } -}; - -static const SecDbSchema v5_schema = { - .majorVersion = 5, - .classes = { - &v5genp_class, - &v5inet_class, - &v5cert_class, - &v5keys_class, - &v5tversion_class, - 0 - } -}; - -SecDbSchema const * const * kc_schemas = NULL; - -const SecDbSchema *v10_kc_schemas_dev[] = { - &v12_0_schema, - &v11_5_schema, - &v11_4_schema, - &v11_3_schema, - &v11_2_schema, - &v11_1_schema, - &v11_schema, - &v10_5_schema, - &v10_4_schema, - &v10_3_schema, - &v10_2_schema, - &v10_1_schema, - &v10_0_schema, - &v9_1_schema, - &v9_schema, - &v8_schema, - &v7_schema, - &v6_schema, - &v5_schema, - 0 -}; - -const SecDbSchema *v10_kc_schemas[] = { - &v11_5_schema, - &v11_4_schema, - &v11_3_schema, - &v11_2_schema, - &v11_1_schema, - &v11_schema, - &v10_5_schema, - &v10_4_schema, - &v10_3_schema, - &v10_2_schema, - &v10_1_schema, - &v10_0_schema, - &v9_1_schema, - &v9_schema, - &v8_schema, - &v7_schema, - &v6_schema, - &v5_schema, - 0 -}; - -const SecDbSchema * const * all_schemas() { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - if (checkV12DevEnabled()) { - secwarning("SecItemSchema: v12 development enabled, returning experimental schema"); - } else { - secnotice("SecItemSchema", "v12 development disabled, returning production schemas"); - } - }); - if (checkV12DevEnabled() != 0) { - return v10_kc_schemas_dev; - } else { - return v10_kc_schemas; - } -} - -const SecDbSchema* current_schema() { - // For now, the current schema is the first in the list. - return all_schemas()[0]; -} - -// class accessors for current schema. -static const SecDbClass* find_class(const SecDbSchema* schema, CFStringRef class_name) { - for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { - if( CFEqualSafe((*pclass)->name, class_name) ) { - return *pclass; - } - } - return NULL; -} - -const SecDbClass* genp_class() { - static const SecDbClass* genp = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - genp = find_class(current_schema(), CFSTR("genp")); - }); - return genp; -} -const SecDbClass* inet_class() { - static const SecDbClass* inet = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - inet = find_class(current_schema(), CFSTR("inet")); - }); - return inet; -} -const SecDbClass* cert_class() { - static const SecDbClass* cert = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - cert = find_class(current_schema(), CFSTR("cert")); - }); - return cert; -} -const SecDbClass* keys_class() { - static const SecDbClass* keys = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - keys = find_class(current_schema(), CFSTR("keys")); - }); - return keys; -} - -// Not really a class per-se -const SecDbClass* identity_class() { - return &v_identity_class; -} - -// Class with 1 element in it which is the database version-> -const SecDbClass* tversion_class() { - static const SecDbClass* tversion = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - tversion = find_class(current_schema(), CFSTR("tversion")); - }); - return tversion; -} - - diff --git a/OSX/sec/securityd/SecItemSchema.h b/OSX/sec/securityd/SecItemSchema.h deleted file mode 100644 index 637553f7..00000000 --- a/OSX/sec/securityd/SecItemSchema.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemSchema.h - The thing that does the stuff with the gibli. - */ - -#ifndef _SECURITYD_SECITEMSCHEMA_H_ -#define _SECURITYD_SECITEMSCHEMA_H_ - -#include - -__BEGIN_DECLS - -const SecDbSchema* current_schema(void); -const SecDbSchema * const * all_schemas(void); - -// class accessors for current schema -const SecDbClass* genp_class(void); -const SecDbClass* inet_class(void); -const SecDbClass* cert_class(void); -const SecDbClass* keys_class(void); - -// Not really a class per-se -const SecDbClass* identity_class(void); - -// Class with 1 element in it which is the database version. -const SecDbClass* tversion_class(void); - -// Direct attribute accessors -// If you change one of these, update it here -extern const SecDbAttr v6v_Data; - -extern const SecDbAttr v6agrp; -extern const SecDbAttr v6desc; -extern const SecDbAttr v6svce; -extern const SecDbAttr v7vwht; -extern const SecDbAttr v7tkid; -extern const SecDbAttr v7utomb; -extern const SecDbAttr v8musr; -extern const SecDbAttr v10itemuuid; -extern const SecDbAttr v10itempersistentref; - -// TODO: Directly expose other important attributes like -// kSecItemSyncAttr, kSecItemTombAttr, kSecItemCdatAttr, kSecItemMdatAttr, kSecItemDataAttr -// This will prevent having to do lookups in SecDbItem for things by kind. - -__END_DECLS - -#endif /* _SECURITYD_SECITEMSCHEMA_H_ */ diff --git a/OSX/sec/securityd/SecItemServer.c b/OSX/sec/securityd/SecItemServer.c deleted file mode 100644 index 79cde4cb..00000000 --- a/OSX/sec/securityd/SecItemServer.c +++ /dev/null @@ -1,3951 +0,0 @@ -/* - * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecItemServer.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#if TARGET_DARWINOS -#undef OCTAGON -#undef SECUREOBJECTSYNC -#undef SHAREDWEBCREDENTIALS -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#import "keychain/SecureObjectSync/SOSChangeTracker.h" -#include "keychain/SecureObjectSync/SOSDigestVector.h" -#include "keychain/SecureObjectSync/SOSEngine.h" -#include -#include -#include -#include -#include -#include - -#include -#import "keychain/ot/OT.h" -#import "keychain/ot/OTConstants.h" -#import "keychain/escrowrequest/EscrowRequestServerHelpers.h" - -#if USE_KEYSTORE - -#if __has_include() -#include -#else -#include "OSX/utilities/SecAKSWrappers.h" -#endif - -#if __has_include() -#include -#endif - -#include - -#endif - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include "swcagent_client.h" -#include "SecPLWrappers.h" - -#if TARGET_OS_IOS && !TARGET_OS_BRIDGE -#include -#endif - -#include - - -#include "Analytics/Clients/LocalKeychainAnalytics.h" - -/* Changed the name of the keychain changed notification, for testing */ -static const char *g_keychain_changed_notification = kSecServerKeychainChangedNotification; - -void SecItemServerSetKeychainChangedNotification(const char *notification_name) -{ - g_keychain_changed_notification = notification_name; -} - -void SecKeychainChanged() { - static dispatch_once_t once; - static sec_action_t action; - - dispatch_once(&once, ^{ - action = sec_action_create("SecKeychainChanged", 1); - sec_action_set_handler(action, ^{ - uint32_t result = notify_post(g_keychain_changed_notification); - if (result == NOTIFY_STATUS_OK) - secnotice("item", "Sent %s", g_keychain_changed_notification); - else - secerror("notify_post %s returned: %" PRIu32, g_keychain_changed_notification, result); - }); - }); - - sec_action_perform(action); -} - -/* Return the current database version in *version. */ -bool SecKeychainDbGetVersion(SecDbConnectionRef dbt, int *version, CFErrorRef *error) -{ - __block bool ok = true; - __block CFErrorRef localError = NULL; - __block bool found = false; - - /* - * First check for the version table itself - */ - - ok &= SecDbPrepare(dbt, CFSTR("SELECT name FROM sqlite_master WHERE type='table' AND name='tversion'"), &localError, ^(sqlite3_stmt *stmt) { - ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { - found = true; - *stop = true; - }); - }); - require_action(ok, out, SecDbError(SQLITE_CORRUPT, error, CFSTR("Failed to read sqlite_master table: %@"), localError)); - if (!found) { - secnotice("upgr", "no tversion table, will setup a new database: %@", localError); - *version = 0; - goto out; - } - - /* - * Now build up major.minor - */ - - ok &= SecDbPrepare(dbt, CFSTR("SELECT version FROM tversion"), &localError, ^(sqlite3_stmt *stmt) { - ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { - *version = sqlite3_column_int(stmt, 0); - if (*version) - *stop = true; - }); - }); - if (ok && (*version & 0xffff) >= 9) { - ok &= SecDbPrepare(dbt, CFSTR("SELECT minor FROM tversion WHERE version = ?"), &localError, ^(sqlite3_stmt *stmt) { - ok = SecDbBindInt(stmt, 1, *version, &localError) && - SecDbStep(dbt, stmt, NULL, ^(bool *stop) { - int64_t minor = sqlite3_column_int64(stmt, 0); - *version |= ((minor & 0xff) << 8) | ((minor & 0xff0000) << 8); - *stop = true; - }); - }); - ok = true; - } -out: - secnotice("upgr", "database version is: 0x%08x : %d : %@", *version, ok, localError); - CFReleaseSafe(localError); - - - return ok; -} - -static bool -isClassD(SecDbItemRef item) -{ - CFTypeRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); - - if (CFEqualSafe(accessible, kSecAttrAccessibleAlwaysPrivate) || CFEqualSafe(accessible, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) - return true; - return false; -} - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - -static int64_t -measureDuration(struct timeval *start) -{ - struct timeval stop; - int64_t duration; - - gettimeofday(&stop, NULL); - - duration = (stop.tv_sec-start->tv_sec) * 1000; - duration += (stop.tv_usec / 1000) - (start->tv_usec / 1000); - - return SecBucket2Significant(duration); -} - -static void -measureUpgradePhase1(struct timeval *start, bool success, int64_t itemsMigrated) -{ - int64_t duration = measureDuration(start); - - if (success) { - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated); - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration); - } else { - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated); - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration); - } -} - -static void -measureUpgradePhase2(struct timeval *start, int64_t itemsMigrated) -{ - int64_t duration = measureDuration(start); - - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated); - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-time"), duration); -} -#endif /* TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */ - -static bool DBClassesAreEqual(const SecDbClass* class1, const SecDbClass* class2) -{ - if (CFEqual(class1->name, class2->name) && class1->itemclass == class2->itemclass) { - int attrIndex = 0; - const SecDbAttr* class1Attr = class1->attrs[attrIndex]; - const SecDbAttr* class2Attr = class2->attrs[attrIndex]; - - while (class1Attr && class2Attr) { - if (CFEqual(class1Attr->name, class2Attr->name) && class1Attr->kind == class2Attr->kind && class1Attr->flags == class2Attr->flags && class1Attr->copyValue == class2Attr->copyValue && class1Attr->setValue == class2Attr->setValue) { - attrIndex++; - class1Attr = class1->attrs[attrIndex]; - class2Attr = class2->attrs[attrIndex]; - } - else { - return false; - } - } - - // if everything has checked out to this point, and we've hit the end of both class's attr list, then they're equal - if (class1Attr == NULL && class2Attr == NULL) { - return true; - } - } - - return false; -} - -static bool ShouldRenameTable(const SecDbClass* class1, const SecDbClass* class2, int oldTableVersion) -{ - return oldTableVersion < 10 || !DBClassesAreEqual(class1, class2); -} - -#define SCHEMA_VERSION(schema) ((((schema)->minorVersion) << 8) | ((schema)->majorVersion)) -#define VERSION_MAJOR(version) ((version) & 0xff) -#define VERSION_MINOR(version) (((version) >> 8) & 0xff) -#define VERSION_NEW(version) ((version) & 0xffff) -#define VERSION_OLD(version) (((version) >> 16) & 0xffff) - -// Goes through all tables represented by old_schema and tries to migrate all items from them into new (current version) tables. -static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSchema, CFErrorRef *error) -{ - int oldVersion = SCHEMA_VERSION(oldSchema); - const SecDbSchema *newSchema = current_schema(); - int newVersion = SCHEMA_VERSION(newSchema); - __block bool ok = true; - SecDbClass const *const *oldClass; - SecDbClass const *const *newClass; - SecDbQueryRef query = NULL; - CFMutableStringRef sql = NULL; - SecDbClass* renamedOldClass = NULL; -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - __block int64_t itemsMigrated = 0; - struct timeval start; - - gettimeofday(&start, NULL); -#endif - - // Rename existing tables to names derived from old schema names - sql = CFStringCreateMutable(NULL, 0); - bool oldClassDone = false; - CFMutableArrayRef classIndexesForNewTables = CFArrayCreateMutable(NULL, 0, NULL); - int classIndex = 0; - for (oldClass = oldSchema->classes, newClass = newSchema->classes; - *newClass != NULL; classIndex++, oldClass++, newClass++) { - if (!oldClassDone) { - oldClassDone |= (*oldClass) == NULL; // Check if the new schema has more tables than the old - } - - if (!oldClassDone && !CFEqual((*oldClass)->name, (*newClass)->name) && ShouldRenameTable(*oldClass, *newClass, oldSchema->majorVersion)) { - CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); - CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); - - } else if (!oldClassDone && !DBClassesAreEqual(*oldClass, *newClass)) { - CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); - CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); - } - - if(oldClassDone && *newClass) { - // These should be no-ops, unless you're upgrading a previously-upgraded database with an invalid version number - CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE IF EXISTS %@;"), (*newClass)->name); - - if (classIndexesForNewTables) { - CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); - } - } - } - - if(CFStringGetLength(sql) > 0) { - require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1AlterTables, error ? *error : NULL)); - } - CFReleaseNull(sql); - - // Drop indices that that new schemas will use - sql = CFStringCreateMutable(NULL, 0); - for (newClass = newSchema->classes; *newClass != NULL; newClass++) { - SecDbForEachAttrWithMask((*newClass), desc, kSecDbIndexFlag | kSecDbInFlag) { - CFStringAppendFormat(sql, 0, CFSTR("DROP INDEX IF EXISTS %@%@;"), (*newClass)->name, desc->name); - if (desc->kind == kSecDbSyncAttr) { - CFStringAppendFormat(sql, 0, CFSTR("DROP INDEX IF EXISTS %@%@0;"), (*newClass)->name, desc->name); - } - } - } - require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1DropIndices, error ? *error : NULL)); - CFReleaseNull(sql); - - // Create tables for new schema. - require_action_quiet(ok &= SecItemDbCreateSchema(dbt, newSchema, classIndexesForNewTables, false, error), out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1CreateSchema, error ? *error : NULL)); - // Go through all classes of current schema to transfer all items to new tables. - for (oldClass = oldSchema->classes, newClass = newSchema->classes; - *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { - - if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { - continue; - } - - secnotice("upgr", "Upgrading table %@", (*oldClass)->name); - - // Create a new 'old' class with a new 'old' name. - int count = 0; - SecDbForEachAttr(*oldClass, attr) { - count++; - } - if(renamedOldClass) { - CFReleaseNull(renamedOldClass->name); - free(renamedOldClass); - } - renamedOldClass = (SecDbClass*) malloc(sizeof(SecDbClass) + sizeof(SecDbAttr*)*(count+1)); - renamedOldClass->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@_old"), (*oldClass)->name); - renamedOldClass->itemclass = (*oldClass)->itemclass; - for(; count >= 0; count--) { - renamedOldClass->attrs[count] = (*oldClass)->attrs[count]; - } - - // SecDbItemSelect only works for item classes. - if((*oldClass)->itemclass) { - // Prepare query to iterate through all items in cur_class. - if (query != NULL) - query_destroy(query, NULL); - require_quiet(query = query_create(renamedOldClass, SecMUSRGetAllViews(), NULL, error), out); - - ok &= SecDbItemSelect(query, dbt, error, ^bool(const SecDbAttr *attr) { - // We are interested in all attributes which are physically present in the DB. - return (attr->flags & kSecDbInFlag) != 0; - }, ^bool(const SecDbAttr *attr) { - // No filtering please. - return false; - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - CFErrorRef localError = NULL; - - #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - itemsMigrated++; - #endif - // Switch item to the new class. - item->class = *newClass; - - if (isClassD(item)) { - // Decrypt the item. - ok &= SecDbItemEnsureDecrypted(item, true, &localError); - require_quiet(ok, out); - - // Delete SHA1 field from the item, so that it is newly recalculated before storing - // the item into the new table. - require_quiet(ok &= SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), - kCFNull, error), out); - } else { - // Leave item encrypted, do not ever try to decrypt it since it will fail. - item->_edataState = kSecDbItemAlwaysEncrypted; - } - // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute - // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. - // - if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) && - SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) { - secnotice("upgr", "dropping item during schema upgrade due to agrp=com.apple.token: %@", item); - } else { - // Insert new item into the new table. - if (!SecDbItemInsert(item, dbt, &localError)) { - secerror("item: %@ insert during upgrade: %@", item, localError); - ok = false; - } - } - - out: - if (localError) { - OSStatus status = SecErrorGetOSStatus(localError); - - switch (status) { - // continue to upgrade and don't propagate errors for insert failures - // that are typical of a single item failure - case errSecDecode: - case errSecDuplicateItem: - ok = true; - break; - case errSecInteractionNotAllowed: - case errSecAuthNeeded: - ok = true; - break; - // This does not mean the keychain is hosed, we just can't use it right now -#if USE_KEYSTORE - case kAKSReturnNotReady: - case kAKSReturnTimeout: -#endif - case errSecNotAvailable: - secnotice("upgr", "Bailing in phase 1 because AKS is unavailable: %@", localError); - // FALLTHROUGH - default: - ok &= CFErrorPropagate(CFRetainSafe(localError), error); - break; - } - CFReleaseSafe(localError); - } - - *stop = !ok; - - }); - - require_action_quiet(ok, out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1Items, error ? *error : NULL)); - } else { - // This table does not contain secdb items, and must be transferred without using SecDbItemSelect. - // For now, this code does not support removing or renaming any columns, or adding any new non-null columns. - CFReleaseNull(sql); - sql = CFStringCreateMutable(NULL, 0); - bool comma = false; - - CFMutableStringRef columns = CFStringCreateMutable(NULL, 0); - - SecDbForEachAttr(renamedOldClass, attr) { - if(comma) { - CFStringAppendFormat(columns, NULL, CFSTR(",")); - } - CFStringAppendFormat(columns, NULL, CFSTR("%@"), attr->name); - comma = true; - } - - CFStringAppendFormat(sql, NULL, CFSTR("INSERT OR REPLACE INTO %@ (%@) SELECT %@ FROM %@;"), (*newClass)->name, columns, columns, renamedOldClass->name); - - CFReleaseNull(columns); - require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1NonItems, error ? *error : NULL)); - } - } - - // Remove old tables from the DB. - CFReleaseNull(sql); - sql = CFStringCreateMutable(NULL, 0); - for (oldClass = oldSchema->classes, newClass = newSchema->classes; - *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { - if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { - continue; - } - - CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE %@_old;"), (*oldClass)->name); - } - - if(CFStringGetLength(sql) > 0) { - require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, - LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1DropOld, error ? *error : NULL)); - } -out: -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - measureUpgradePhase1(&start, ok, SecBucket2Significant(itemsMigrated)); -#endif - - if (query != NULL) { - query_destroy(query, NULL); - } - CFReleaseSafe(sql); - CFReleaseNull(classIndexesForNewTables); - if(renamedOldClass) { - CFReleaseNull(renamedOldClass->name); - free(renamedOldClass); - } - return ok; -} - -__thread SecDbConnectionRef threadDbt = NULL; - -// Goes through all tables represented by old_schema and tries to migrate all items from them into new (current version) tables. -static bool UpgradeItemPhase2(SecDbConnectionRef inDbt, bool *inProgress, int oldVersion, CFErrorRef *error) { - SecDbConnectionRef oldDbt = threadDbt; - threadDbt = inDbt; - __block bool ok = true; - SecDbQueryRef query = NULL; -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - __block int64_t itemsMigrated = 0; - struct timeval start; - - gettimeofday(&start, NULL); -#endif - -#if SECDB_BACKUPS_ENABLED - CFErrorRef backuperror = NULL; - if (!SecDbBackupCreateOrLoadBackupInfrastructure(&backuperror)) { - secerror("upgr: failed to create backup infrastructure: %@", backuperror); - } else { - secnotice("upgr", "setup backup infrastructure"); - } -#else - secnotice("upgr", "skipping backup setup for this platform"); -#endif - - // Go through all classes in new schema - const SecDbSchema *newSchema = current_schema(); - int newVersion = SCHEMA_VERSION(newSchema); - for (const SecDbClass *const *class = newSchema->classes; *class != NULL && !*inProgress; class++) { - if(!((*class)->itemclass)) { - //Don't try to decrypt non-item 'classes' - continue; - } - - const SecDbAttr *pdmn = SecDbClassAttrWithKind(*class, kSecDbAccessAttr, error); - if (pdmn == nil) { - continue; - } - - // Prepare query to go through all non-DK|DKU items - if (query != NULL) { - query_destroy(query, NULL); - } - require_action_quiet(query = query_create(*class, SecMUSRGetAllViews(), NULL, error), out, ok = false); - ok &= SecDbItemSelect(query, threadDbt, error, NULL, ^bool(const SecDbAttr *attr) { - // No simple per-attribute filtering. - return false; - }, ^bool(CFMutableStringRef sql, bool *needWhere) { - // Select only non-D-class items - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppendFormat(sql, NULL, CFSTR("NOT %@ IN (?,?)"), pdmn->name); - return true; - }, ^bool(sqlite3_stmt *stmt, int col) { - return SecDbBindObject(stmt, col++, kSecAttrAccessibleAlwaysPrivate, error) && - SecDbBindObject(stmt, col++, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, error); - }, ^(SecDbItemRef item, bool *stop) { - CFErrorRef localError = NULL; - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - itemsMigrated++; -#endif - - // Decrypt the item. - if (SecDbItemEnsureDecrypted(item, true, &localError)) { - - // Delete SHA1 field from the item, so that it is newly recalculated before storing - // the item into the new table. - require_quiet(ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), - kCFNull, &localError), out); - // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute - // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. - // - if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) && - SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) { - secnotice("upgr", "dropping item during item upgrade due to agrp=com.apple.token: %@", item); - ok = SecDbItemDelete(item, threadDbt, kCFBooleanFalse, &localError); - } else { - // Replace item with the new value in the table; this will cause the item to be decoded and recoded back, - // incl. recalculation of item's hash. - ok = SecDbItemUpdate(item, item, threadDbt, false, query->q_uuid_from_primary_key, &localError); - } - } - - if (localError) { - CFIndex status = CFErrorGetCode(localError); - - switch (status) { - case errSecDecode: { - // Items producing errSecDecode are silently dropped - they are not decodable and lost forever. - // make sure we use a local error so that this error is not proppaged upward and cause a - // migration failure. - CFErrorRef deleteError = NULL; - (void)SecDbItemDelete(item, threadDbt, false, &deleteError); - CFReleaseNull(deleteError); - ok = true; - break; - } - case errSecInteractionNotAllowed: - // If we are still not able to decrypt the item because the class key is not released yet, - // remember that DB still needs phase2 migration to be run next time a connection is made. Also - // stop iterating next items, it would be just waste of time because the whole iteration will be run - // next time when this phase2 will be rerun. - LKAReportKeychainUpgradeOutcome(oldVersion, newVersion, LKAKeychainUpgradeOutcomeLocked); - *inProgress = true; - *stop = true; - ok = true; - break; - case errSecAuthNeeded: - // errSecAuthNeeded means that it is an ACL-based item which requires authentication (or at least - // ACM context, which we do not have). - ok = true; - break; - case SQLITE_CONSTRAINT: // yeah... - if (!CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { - secerror("Received SQLITE_CONSTRAINT with wrong error domain. Huh? Item: %@, error: %@", item, localError); - break; - } - case errSecDuplicateItem: - // continue to upgrade and don't propagate errors for insert failures - // that are typical of a single item failure - secnotice("upgr", "Ignoring duplicate item: %@", item); - secdebug("upgr", "Duplicate item error: %@", localError); - ok = true; - break; -#if USE_KEYSTORE - case kAKSReturnNotReady: - case kAKSReturnTimeout: -#endif - case errSecNotAvailable: - *inProgress = true; // We're not done, call me again later! - secnotice("upgr", "Bailing in phase 2 because AKS is unavailable: %@", localError); - // FALLTHROUGH - default: - // Other errors should abort the migration completely. - ok = CFErrorPropagate(CFRetainSafe(localError), error); - break; - } - } - - out: - CFReleaseSafe(localError); - *stop = *stop || !ok; - - }); - require_action(ok, out, LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase2, error ? *error : NULL)); - } - -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - measureUpgradePhase2(&start, SecBucket2Significant(itemsMigrated)); -#endif - -out: - if (query != NULL) - query_destroy(query, NULL); - - threadDbt = oldDbt; - return ok; -} - -static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, bool *inProgress, CFErrorRef *error) { - __block bool didPhase2 = false; - __block bool ok = true; - __block CFErrorRef localError = NULL; - - if (error) - *error = NULL; - - const SecDbSchema *newSchema = current_schema(); - int newVersion = SCHEMA_VERSION(newSchema); - bool skipped_upgrade = false; - - // If DB schema is the one we want, we are done. - require_action_quiet(SCHEMA_VERSION(newSchema) != version, out, skipped_upgrade = true); - - // Check if the schema of the database on disk is the same major, but newer version then what we have - // in code, lets just skip this since a newer version of the OS have upgrade it. Since its the same - // major, its a promise that it will be compatible. - if (newSchema->majorVersion == VERSION_MAJOR(version) && newSchema->minorVersion < VERSION_MINOR(version)) { - secnotice("upgr", "skipping upgrade since minor is newer"); - goto out; - } - - ok &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - CFStringRef sql = NULL; - bool didPhase1 = false; - - // Get version again once we start a transaction, someone else might change the migration state. - int version2 = 0; - require_quiet(ok = SecKeychainDbGetVersion(dbt, &version2, &localError), out); - // Check if someone has raced us to the migration of the database - require_action(version == version2, out, CFReleaseNull(localError); ok = true); - - require_quiet(SCHEMA_VERSION(newSchema) != version2, out); - - // If this is empty database, just create table according to schema and be done with it. - require_action_quiet(version2 != 0, out, ok = SecItemDbCreateSchema(dbt, newSchema, NULL, true, &localError); - LKAReportKeychainUpgradeOutcomeWithError(version2, newVersion, LKAKeychainUpgradeOutcomeNewDb, localError)); - - int oldVersion = VERSION_OLD(version2); - version2 = VERSION_NEW(version2); - - require_action_quiet(version2 == SCHEMA_VERSION(newSchema) || oldVersion == 0, out, - ok = SecDbError(SQLITE_CORRUPT, &localError, - CFSTR("Half migrated but obsolete DB found: found 0x%x(0x%x) but 0x%x is needed"), - version2, oldVersion, SCHEMA_VERSION(newSchema)); - LKAReportKeychainUpgradeOutcome(version2, newVersion, LKAKeychainUpgradeOutcomeObsoleteDb)); - - // Check whether we have both old and new tables in the DB. - if (oldVersion == 0) { - // Pure old-schema migration attempt, with full blown table renames etc (a.k.a. phase1) - oldVersion = version2; - version2 = SCHEMA_VERSION(newSchema); - - // Find schema for old database. - const SecDbSchema *oldSchema = NULL; - for (const SecDbSchema * const *pschema = all_schemas(); *pschema; ++pschema) { - if (SCHEMA_VERSION((*pschema)) == oldVersion) { - oldSchema = *pschema; - break; - } - } - - // If we are attempting to upgrade from a version for which we have no schema, fail. - require_action_quiet(oldSchema != NULL, out, - ok = SecDbError(SQLITE_CORRUPT, &localError, CFSTR("no schema for version: 0x%x"), oldVersion); - secerror("no schema for version 0x%x", oldVersion); - LKAReportKeychainUpgradeOutcome(version2, newVersion, LKAKeychainUpgradeOutcomeNoSchema)); - - secnotice("upgr", "Upgrading from version 0x%x to 0x%x", oldVersion, SCHEMA_VERSION(newSchema)); - SecSignpostStart(SecSignpostUpgradePhase1); - require_action(ok = UpgradeSchemaPhase1(dbt, oldSchema, &localError), out, secerror("upgrade: Upgrade phase1 failed: %@", localError)); - SecSignpostStop(SecSignpostUpgradePhase1); - - didPhase1 = true; - } - - { - CFErrorRef phase2Error = NULL; - - SecSignpostStart(SecSignpostUpgradePhase2); - - // Lets try to go through non-D-class items in new tables and apply decode/encode on them - // If this fails the error will be ignored after doing a phase1 since but not in the second - // time when we are doing phase2. - ok = UpgradeItemPhase2(dbt, inProgress, version2, &phase2Error); - if (!ok) { - if (didPhase1) { - *inProgress = true; - ok = true; - CFReleaseNull(phase2Error); - } else { - SecErrorPropagate(phase2Error, &localError); - } - } - require_action(ok, out, secerror("upgrade: Upgrade phase2 (%d) failed: %@", didPhase1, localError)); - - if (!*inProgress) { - // If either migration path we did reported that the migration was complete, signalize that - // in the version database by cleaning oldVersion (which is stored in upper halfword of the version) - secnotice("upgr", "Done upgrading from version 0x%x to 0x%x", oldVersion, SCHEMA_VERSION(newSchema)); - oldVersion = 0; - - didPhase2 = true; - SecSignpostStop(SecSignpostUpgradePhase2); - } - } - - // Update database version table. - uint32_t major = (VERSION_MAJOR(version2)) | (VERSION_MAJOR(oldVersion) << 16); - uint32_t minor = (VERSION_MINOR(version2)) | (VERSION_MINOR(oldVersion) << 16); - secnotice("upgr", "Upgrading saving version major 0x%x minor 0x%x", major, minor); - sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("UPDATE tversion SET version='%d', minor='%d'"), - major, minor); - require_action_quiet(ok = SecDbExec(dbt, sql, &localError), out, secerror("upgrade: Setting version failed: %@", localError)); - - out: - if (!ok) { - secerror("upgrade: SecDB upgrade failed: %@", localError); - } - CFReleaseSafe(sql); - *commit = ok; - }); - - if (ok && didPhase2) { -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-success"), 1); -#endif - } - -out: - if (!ok || localError) { - // TODO: This logic should be inverted to a do-not-corrupt-unless default, - /* - * We assume that database is corrupt at this point, but we need to - * check if the error we got isn't severe enough to mark the database as corrupt. - * In those cases we opt out of corrupting the database. - */ - bool markedCorrupt = true; - - if (ok) { - secwarning("upgrade: error has been set but status is true"); - ok = false; - } - secerror("upgrade: error occurred, considering marking database as corrupt: %@", localError); - if (localError) { - CFStringRef domain = CFErrorGetDomain(localError); - CFIndex code = CFErrorGetCode(localError); - - if ((CFEqualSafe(domain, kSecDbErrorDomain) && - ((code & 0xff) == SQLITE_LOCKED || (code & 0xff) == SQLITE_BUSY || (code & 0xff) == SQLITE_FULL)) || -#if USE_KEYSTORE - code == kAKSReturnNotReady || code == kAKSReturnTimeout || -#endif - code == errSecNotAvailable) - { - secerror("upgrade: not marking keychain database corrupt for error: %@", localError); - markedCorrupt = false; - CFReleaseNull(localError); - } else { - secerror("upgrade: unable to complete upgrade, marking DB as corrupt: %@", localError); - } - } else { - secerror("upgrade: unable to complete upgrade and no error object returned, marking DB as corrupt"); - } - if (markedCorrupt) { - secerror("upgrade: marking database as corrupt"); - SecDbCorrupt(dbt, localError); -#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-failure"), 1); -#endif - } - } else { - // Things seemed to go okay! - if (didPhase2) { - LKAReportKeychainUpgradeOutcome(version, newVersion, LKAKeychainUpgradeOutcomeSuccess); - } - - //If we're done here, we should opportunistically re-add all indices (just in case) - if(skipped_upgrade || didPhase2) { - // Create indices, ignoring all errors - for (SecDbClass const* const* newClass = newSchema->classes; *newClass; ++newClass) { - SecDbForEachAttrWithMask((*newClass), desc, kSecDbIndexFlag | kSecDbInFlag) { - CFStringRef sql = NULL; - CFErrorRef classLocalError = NULL; - bool localOk = true; - - if (desc->kind == kSecDbSyncAttr) { - // Replace the complete sync index with a partial index for sync=0. Most items are sync=1, so the complete index isn't helpful for sync=1 queries. - sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("DROP INDEX IF EXISTS %@%@; CREATE INDEX IF NOT EXISTS %@%@0 on %@(%@) WHERE %@=0;"), - (*newClass)->name, desc->name, (*newClass)->name, desc->name, (*newClass)->name, desc->name, desc->name); - } else { - sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("CREATE INDEX IF NOT EXISTS %@%@ ON %@(%@);"), (*newClass)->name, desc->name, (*newClass)->name, desc->name); - } - localOk &= SecDbExec(dbt, sql, &classLocalError); - CFReleaseNull(sql); - - if(!localOk) { - secerror("upgrade: unable to opportunistically create index (%@,%@): %@", (*newClass)->name, desc->name, classLocalError); - } - CFReleaseNull(classLocalError); - } - } - } - } - if (localError) { - if (error) { - *error = (CFErrorRef)CFRetain(localError); - } - CFReleaseNull(localError); - } - - return ok; -} - -static bool accessGroupIsNetworkExtensionAndClientIsEntitled(CFStringRef accessGroup, SecurityClient* client) -{ - return client && client->canAccessNetworkExtensionAccessGroups && accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix); -} - -/* AUDIT[securityd](done): - accessGroup (ok) is a caller provided, non NULL CFTypeRef. - - Return true iff accessGroup is allowable according to accessGroups. - */ -bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client) { - /* NULL accessGroups is wildcard. */ - if (!accessGroups) - return true; - /* Make sure we have a string. */ - if (!isString(accessGroup)) - return false; - - /* Having the special accessGroup "*" allows access to all accessGroups. */ - CFRange range = { 0, CFArrayGetCount(accessGroups) }; - if (range.length && - (CFArrayContainsValue(accessGroups, range, accessGroup) || - CFArrayContainsValue(accessGroups, range, CFSTR("*")) || - accessGroupIsNetworkExtensionAndClientIsEntitled(accessGroup, client))) - return true; - - return false; -} - -bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) { - return accessGroupsAllows(accessGroups, - CFDictionaryGetValue(item, kSecAttrAccessGroup), NULL); -} - - -static CF_RETURNS_RETAINED CFDataRef SecServerExportBackupableKeychain(SecDbConnectionRef dbt, - SecurityClient *client, - keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFErrorRef *error) { - CFDataRef data_out = NULL; - - SecSignpostStart(SecSignpostBackupKeychainBackupable); - - /* Export everything except the items for which SecItemIsSystemBound() - returns true. */ - CFDictionaryRef keychain = SecServerCopyKeychainPlist(dbt, client, - src_keybag, dest_keybag, kSecBackupableItemFilter, - error); - if (keychain) { - data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain, - kCFPropertyListBinaryFormat_v1_0, - 0, error); - CFRelease(keychain); - } - SecSignpostStop(SecSignpostBackupKeychainBackupable); - - return data_out; -} - -static bool SecServerImportBackupableKeychain(SecDbConnectionRef dbt, - SecurityClient *client, - keybag_handle_t src_keybag, - keybag_handle_t dest_keybag, - CFDataRef data, - CFErrorRef *error) -{ - return kc_transaction(dbt, error, ^{ - bool ok = false; - CFDictionaryRef keychain; - - SecSignpostStart(SecSignpostRestoreKeychainBackupable); - - keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data, - kCFPropertyListImmutable, NULL, - error); - if (keychain) { - if (isDictionary(keychain)) { - ok = SecServerImportKeychainInPlist(dbt, - client, - src_keybag, - dest_keybag, - keychain, - kSecBackupableItemFilter, - false, // Restoring backup should not remove stuff that got into the keychain before us - error); - } else { - ok = SecError(errSecParam, error, CFSTR("import: keychain is not a dictionary")); - } - CFRelease(keychain); - } - - SecSignpostStop(SecSignpostRestoreKeychainBackupable); - - return ok; - }); -} - -#if USE_KEYSTORE -/* - * Similar to ks_open_keybag, but goes through MKB interface - */ -static bool mkb_open_keybag(CFDataRef keybag, CFDataRef password, MKBKeyBagHandleRef *handle, bool emcs, CFErrorRef *error) { - kern_return_t rc; - MKBKeyBagHandleRef mkbhandle = NULL; - - rc = MKBKeyBagCreateWithData(keybag, &mkbhandle); - if (rc != kMobileKeyBagSuccess) { - return SecKernError(rc, error, CFSTR("MKBKeyBagCreateWithData failed: %d"), rc); - } - - if (!emcs) { - rc = MKBKeyBagUnlock(mkbhandle, password); - if (rc != kMobileKeyBagSuccess) { - CFRelease(mkbhandle); - return SecKernError(rc, error, CFSTR("failed to unlock bag: %d"), rc); - } - } else { - secnotice("keychainbackup", "skipping keybag unlock for EMCS"); - } - - *handle = mkbhandle; - - return true; -} -#endif - - -static CFDataRef SecServerKeychainCreateBackup(SecDbConnectionRef dbt, SecurityClient *client, CFDataRef keybag, - CFDataRef password, bool emcs, CFErrorRef *error) { - CFDataRef backup = NULL; - keybag_handle_t backup_keybag; - - SecSignpostStart(SecSignpostBackupOpenKeybag); - -#if USE_KEYSTORE - MKBKeyBagHandleRef mkbhandle = NULL; - require(mkb_open_keybag(keybag, password, &mkbhandle, emcs, error), out); - - require_noerr(MKBKeyBagGetAKSHandle(mkbhandle, &backup_keybag), out); - -#else - backup_keybag = KEYBAG_NONE; -#endif - SecSignpostStop(SecSignpostBackupOpenKeybag); - SecSignpostStart(SecSignpostBackupKeychain); - - /* Export from system keybag to backup keybag. */ - backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag, error); - -#if USE_KEYSTORE -out: - SecSignpostStop(SecSignpostBackupOpenKeybag); - - if (mkbhandle) - CFRelease(mkbhandle); -#endif - return backup; -} - -static bool SecServerKeychainRestore(SecDbConnectionRef dbt, - SecurityClient *client, - CFDataRef backup, - CFDataRef keybag, - CFDataRef password, - CFErrorRef *error) -{ - bool ok = false; - keybag_handle_t backup_keybag; - - secnotice("SecServerKeychainRestore", "Restoring keychain backup"); - - SecSignpostStart(SecSignpostRestoreOpenKeybag); -#if USE_KEYSTORE - MKBKeyBagHandleRef mkbhandle = NULL; - require(mkb_open_keybag(keybag, password, &mkbhandle, false, error), out); - - require_noerr(MKBKeyBagGetAKSHandle(mkbhandle, &backup_keybag), out); -#else - backup_keybag = KEYBAG_NONE; -#endif - SecSignpostStop(SecSignpostRestoreOpenKeybag); - SecSignpostStart(SecSignpostRestoreKeychain); - - /* Import from backup keybag to system keybag. */ - require(SecServerImportBackupableKeychain(dbt, client, backup_keybag, KEYBAG_DEVICE, backup, error), out); - - ok = true; -out: - SecSignpostStop(SecSignpostRestoreKeychain); -#if USE_KEYSTORE - if (mkbhandle) - CFRelease(mkbhandle); -#endif - - if (ok) { - secnotice("SecServerKeychainRestore", "Restore completed successfully"); - } else { - secwarning("SecServerKeychainRestore: Restore failed with: %@", error ? *error : NULL); - } - - return ok; -} - -// MARK - External SPI support code. - -CFStringRef __SecKeychainCopyPath(void) { - CFStringRef kcRelPath = NULL; - - if (os_variant_is_recovery("securityd")) { - kcRelPath = CFSTR("keychain-recovery-2.db"); - } else if (use_hwaes()) { - kcRelPath = CFSTR("keychain-2.db"); - } else { - kcRelPath = CFSTR("keychain-2-debug.db"); - } - - CFStringRef kcPath = NULL; - CFURLRef kcURL = SecCopyURLForFileInKeychainDirectory(kcRelPath); - if (kcURL) { - kcPath = CFURLCopyFileSystemPath(kcURL, kCFURLPOSIXPathStyle); - CFRelease(kcURL); - } - return kcPath; -} - -// MARK; - -// MARK: kc_dbhandle init and reset - -SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error) { - __block CFErrorRef localerror = NULL; - - SecDbRef kc = SecDbCreate(path, 0600, true, true, true, true, kSecDbMaxIdleHandles, - ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *createError) - { - // Upgrade from version 0 means create the schema in empty db. - int version = 0; - bool ok = true; - if (!didCreate) - ok = SecKeychainDbGetVersion(dbconn, &version, createError); - - ok = ok && SecKeychainDbUpgradeFromVersion(dbconn, version, callMeAgainForNextConnection, createError); - if (!ok) - secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", createError ? *createError : NULL); - - localerror = createError ? *createError : NULL; - - if(ok) { - // This block might get called many, many times due to callMeAgainForNextConnection. - // When we no longer want to be called, we believe we're done. Begin the rest of initialization. - if( !callMeAgainForNextConnection || !(*callMeAgainForNextConnection)) { - SecKeychainDbInitialize(db); - } - } - - return ok; - }); - - if (kc) { - SecDbSetCorruptionReset(kc, ^{ - SecDbResetMetadataKeys(); - }); - } - - if(error) { - *error = localerror; - } - - return kc; -} - -SecDbRef SecKeychainDbInitialize(SecDbRef db) { - -#if OCTAGON - if(SecCKKSIsEnabled()) { - // This needs to be async, otherwise we get hangs between securityd, cloudd, and apsd - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - SecCKKSInitialize(db); - - }); - } - - if(OctagonIsEnabled() && OctagonShouldPerformInitialization()) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - OctagonInitialize(); - }); - } - - if(EscrowRequestServerIsEnabled()) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - EscrowRequestServerInitialize(); - }); - } -#endif - - return db; -} - -static SecDbRef _kc_dbhandle = NULL; -static dispatch_queue_t _kc_dbhandle_dispatch = NULL; -static dispatch_once_t _kc_dbhandle_dispatch_onceToken = 0; -static dispatch_queue_t get_kc_dbhandle_dispatch() { - dispatch_once(&_kc_dbhandle_dispatch_onceToken, ^{ - _kc_dbhandle_dispatch = dispatch_queue_create("sec_kc_dbhandle", DISPATCH_QUEUE_SERIAL); - }); - - return _kc_dbhandle_dispatch; -} - -static bool kc_dbhandle_init(CFErrorRef* error) { - SecDbRef oldHandle = _kc_dbhandle; - _kc_dbhandle = NULL; - CFStringRef dbPath = __SecKeychainCopyPath(); - if (dbPath) { - _kc_dbhandle = SecKeychainDbCreate(dbPath, error); - CFRelease(dbPath); - } else { - secerror("no keychain path available"); - } - if (oldHandle) { - secerror("replaced %@ with %@", oldHandle, _kc_dbhandle); - CFRelease(oldHandle); - } - // Having a dbhandle means we succeeded. - return !!_kc_dbhandle; -} - -static SecDbRef kc_dbhandle(CFErrorRef* error) -{ - dispatch_sync(get_kc_dbhandle_dispatch(), ^{ - if(_kc_dbhandle == NULL) { - _SecDbServerSetup(); - kc_dbhandle_init(error); - } - }); - return _kc_dbhandle; -} - -/* For whitebox testing only */ -void SecKeychainDbReset(dispatch_block_t inbetween) -{ - dispatch_sync(get_kc_dbhandle_dispatch(), ^{ - CFReleaseNull(_kc_dbhandle); - SecDbResetMetadataKeys(); - - if (inbetween) - inbetween(); - }); -} - -static bool kc_acquire_dbt(bool writeAndRead, SecDbConnectionRef* dbconn, CFErrorRef *error) { - SecDbRef db = kc_dbhandle(error); - if (db == NULL) { - if(error && !(*error)) { - SecError(errSecDataNotAvailable, error, CFSTR("failed to get a db handle")); - } - return NULL; - } - - return SecDbConnectionAcquireRefMigrationSafe(db, !writeAndRead, dbconn, error); -} - -/* Return a per thread dbt handle for the keychain. If create is true create - the database if it does not yet exist. If it is false, just return an - error if it fails to auto-create. */ -bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) -{ - return kc_with_custom_db(writeAndRead, true, NULL, error, perform); -} - -bool kc_with_dbt_non_item_tables(bool writeAndRead, CFErrorRef* error, bool (^perform)(SecDbConnectionRef dbt)) -{ - return kc_with_custom_db(writeAndRead, false, NULL, error, perform); -} - -bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) -{ - if (db && db != kc_dbhandle(error)) { - __block bool result = false; - if (writeAndRead) { - SecDbPerformWrite(db, error, ^(SecDbConnectionRef dbconn) { - result = perform(dbconn); - }); - } - else { - SecDbPerformRead(db, error, ^(SecDbConnectionRef dbconn) { - result = perform(dbconn); - }); - } - return result; - } - - if(threadDbt) { - // The kc_with_dbt upthread will clean this up when it's done. - return perform(threadDbt); - } - - if (writeAndRead && usesItemTables) { -#if SECUREOBJECTSYNC - SecItemDataSourceFactoryGetDefault(); -#endif - } - - bool ok = false; - if (kc_acquire_dbt(writeAndRead, &threadDbt, error)) { - ok = perform(threadDbt); - SecDbConnectionRelease(threadDbt); - threadDbt = NULL; - } - return ok; -} - -static bool -items_matching_issuer_parent(SecDbConnectionRef dbt, CFArrayRef accessGroups, CFDataRef musrView, - CFDataRef issuer, CFArrayRef issuers, int recurse) -{ - Query *q; - CFArrayRef results = NULL; - CFIndex i, count; - bool found = false; - - if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer)) - return true; - - /* XXX make musr supported */ - const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrSubject }; - const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, issuer }; - CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL); - - if (!query) - return false; - - CFErrorRef localError = NULL; - q = query_create_with_limit(query, musrView, kSecMatchUnlimited, &localError); - CFRelease(query); - if (q) { - s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError); - query_destroy(q, &localError); - } - if (localError) { - secerror("items matching issuer parent: %@", localError); - CFReleaseNull(localError); - return false; - } - - count = CFArrayGetCount(results); - for (i = 0; (i < count) && !found; i++) { - CFDictionaryRef cert_dict = (CFDictionaryRef)CFArrayGetValueAtIndex(results, i); - CFDataRef cert_issuer = CFDictionaryGetValue(cert_dict, kSecAttrIssuer); - if (CFEqual(cert_issuer, issuer)) - continue; - if (recurse-- > 0) - found = items_matching_issuer_parent(dbt, accessGroups, musrView, cert_issuer, issuers, recurse); - } - CFReleaseSafe(results); - - return found; -} - -static bool -_FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert) -{ - CFDictionaryRef props = NULL; - CFArrayRef keychains = NULL; - CFArrayRef anchors = NULL; - CFArrayRef certs = NULL; - CFArrayRef chain = NULL; - SecTrustRef trust = NULL; - - SecTrustResultType trustResult; - Boolean needChain = false; - __block bool ok = false; - - if (!policy || !cert) return false; - - certs = CFArrayCreate(NULL, (const void **)&cert, (CFIndex)1, &kCFTypeArrayCallBacks); - require_noerr_quiet(SecTrustCreateWithCertificates(certs, policy, &trust), cleanup); - - /* Set evaluation date, if specified (otherwise current date is implied) */ - if (date && (CFGetTypeID(date) == CFDateGetTypeID())) { - require_noerr_quiet(SecTrustSetVerifyDate(trust, date), cleanup); - } - - /* Check whether this is the X509 Basic policy, which means chain building */ - props = SecPolicyCopyProperties(policy); - if (props) { - CFTypeRef oid = (CFTypeRef) CFDictionaryGetValue(props, kSecPolicyOid); - if (oid && (CFEqual(oid, kSecPolicyAppleX509Basic) || - CFEqual(oid, kSecPolicyAppleRevocation))) { - needChain = true; - } - } - - if (!needChain) { - require_noerr_quiet(SecTrustEvaluateLeafOnly(trust, &trustResult), cleanup); - } else { - require_noerr_quiet(SecTrustEvaluate(trust, &trustResult), cleanup); - } - - require_quiet((trustResult == kSecTrustResultProceed || - trustResult == kSecTrustResultUnspecified || - trustResult == kSecTrustResultRecoverableTrustFailure), cleanup); - - ok = true; -#if TARGET_OS_IPHONE - CFArrayRef properties = SecTrustCopyProperties(trust); -#else - CFArrayRef properties = SecTrustCopyProperties_ios(trust); -#endif - if (properties) { - CFArrayForEach(properties, ^(const void *property) { - CFDictionaryForEach((CFDictionaryRef)property, ^(const void *key, const void *value) { - if (CFEqual((CFTypeRef)key, kSecPropertyKeyType) && CFEqual((CFTypeRef)value, kSecPropertyTypeError)) - ok = false; - }); - }); - CFRelease(properties); - } - -cleanup: - if(props) CFRelease(props); - if(chain) CFRelease(chain); - if(anchors) CFRelease(anchors); - if(keychains) CFRelease(keychains); - if(certs) CFRelease(certs); - if(trust) CFRelease(trust); - - return ok; -} - -static bool -_FilterWithDate(CFDateRef validOnDate, SecCertificateRef cert) -{ - if (!validOnDate || !cert) return false; - - CFAbsoluteTime at, nb, na; - at = CFDateGetAbsoluteTime((CFDateRef)validOnDate); - - bool ok = true; - nb = SecCertificateNotValidBefore(cert); - na = SecCertificateNotValidAfter(cert); - - if (nb == 0 || na == 0 || nb == na) { - ok = false; - secnotice("FilterWithDate", "certificate cannot operate"); - } - else if (at < nb) { - ok = false; - secnotice("FilterWithDate", "certificate is not valid yet"); - } - else if (at > na) { - ok = false; - secnotice("FilterWithDate", "certificate expired"); - } - - return ok; -} - -static bool -_FilterWithTrust(Boolean trustedOnly, SecCertificateRef cert) -{ - if (!cert) return false; - if (!trustedOnly) return true; - - bool ok = false; - CFArrayRef certArray = CFArrayCreate(NULL, (const void**)&cert, 1, &kCFTypeArrayCallBacks); - SecTrustRef trust = NULL; - SecPolicyRef policy = SecPolicyCreateBasicX509(); - require_quiet(policy, out); - - require_noerr_quiet(SecTrustCreateWithCertificates(certArray, policy, &trust), out); - SecTrustResultType trustResult; - require_noerr_quiet(SecTrustEvaluate(trust, &trustResult), out); - - require_quiet((trustResult == kSecTrustResultProceed || - trustResult == kSecTrustResultUnspecified), out); - ok = true; -out: - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certArray); - return ok; -} - -static SecCertificateRef -CopyCertificateFromItem(Query *q, CFDictionaryRef item) { - SecCertificateRef certRef = NULL; - CFDictionaryRef itemValue = NULL; - - CFTypeRef tokenID = NULL; - CFDataRef certData = NULL; - if (q->q_class == identity_class()) { - certData = CFDictionaryGetValue(item, kSecAttrIdentityCertificateData); - tokenID = CFDictionaryGetValue(item, kSecAttrIdentityCertificateTokenID); - } else if (q->q_class == cert_class()) { - certData = CFDictionaryGetValue(item, kSecValueData); - tokenID = CFDictionaryGetValue(item, kSecAttrTokenID); - } - - require_quiet(certData, out); - if (tokenID != NULL) { - CFErrorRef error = NULL; - itemValue = SecTokenItemValueCopy(certData, &error); - require_action_quiet(itemValue, out, { secerror("function SecTokenItemValueCopy failed with: %@", error); CFReleaseSafe(error); }); - CFDataRef tokenCertData = CFDictionaryGetValue(itemValue, kSecTokenValueDataKey); - require_action_quiet(tokenCertData, out, { secerror("token item doesn't contain token value data");}); - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, tokenCertData); - } - else - certRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData); - -out: - CFReleaseNull(itemValue); - return certRef; -} - -bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item) -{ - bool ok = false; - SecCertificateRef certRef = NULL; - if (q->q_match_issuer) { - CFDataRef issuer = CFDictionaryGetValue(item, kSecAttrIssuer); - if (!items_matching_issuer_parent(dbt, accessGroups, q->q_musrView, issuer, q->q_match_issuer, 10 /*max depth*/)) - return ok; - } - - if (q->q_match_policy && (q->q_class == identity_class() || q->q_class == cert_class())) { - if (!certRef) - certRef = CopyCertificateFromItem(q, item); - require_quiet(certRef, out); - require_quiet(_FilterWithPolicy(q->q_match_policy, q->q_match_valid_on_date, certRef), out); - } - - if (q->q_match_valid_on_date && (q->q_class == identity_class() || q->q_class == cert_class())) { - if (!certRef) - certRef = CopyCertificateFromItem(q, item); - require_quiet(certRef, out); - require_quiet(_FilterWithDate(q->q_match_valid_on_date, certRef), out); - } - - if (q->q_match_trusted_only && (q->q_class == identity_class() || q->q_class == cert_class())) { - if (!certRef) - certRef = CopyCertificateFromItem(q, item); - require_quiet(certRef, out); - require_quiet(_FilterWithTrust(CFBooleanGetValue(q->q_match_trusted_only), certRef), out); - } - - /* Add future match checks here. */ - ok = true; -out: - CFReleaseSafe(certRef); - return ok; -} - -/**************************************************************************** - **************** Beginning of Externally Callable Interface **************** - ****************************************************************************/ - -static bool SecEntitlementError(CFErrorRef *error) -{ -#if TARGET_OS_OSX -#define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.application-identifier nor com.apple.security.application-groups nor keychain-access-groups") -#elif TARGET_OS_IOSMAC -#define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.developer.associated-application-identifier nor application-identifier nor com.apple.security.application-groups nor keychain-access-groups") -#else -#define SEC_ENTITLEMENT_WARNING CFSTR("application-identifier nor keychain-access-groups") -#endif - - return SecError(errSecMissingEntitlement, error, CFSTR("Client has neither %@ entitlements"), SEC_ENTITLEMENT_WARNING); -} - -static bool SecEntitlementErrorForExplicitAccessGroup(CFStringRef agrp, CFArrayRef clientGroups, CFErrorRef* error) -{ - return SecError(errSecMissingEntitlement, error, CFSTR("Client explicitly specifies access group %@ but is only entitled for %@"), agrp, clientGroups); -} - -static CFStringRef CopyAccessGroupForRowID(sqlite_int64 rowID, CFStringRef itemClass) -{ - __block CFStringRef accessGroup = NULL; - - __block CFErrorRef error = NULL; - bool ok = kc_with_dbt(false, &error, ^bool(SecDbConnectionRef dbt) { - CFStringRef table = CFEqual(itemClass, kSecClassIdentity) ? kSecClassCertificate : itemClass; - CFStringRef sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("SELECT agrp FROM %@ WHERE rowid == %u"), table, (unsigned int)rowID); - bool dbOk = SecDbWithSQL(dbt, sql, &error, ^bool(sqlite3_stmt *stmt) { - bool rowOk = SecDbForEach(dbt, stmt, &error, ^bool(int row_index) { - accessGroup = CFStringCreateWithBytes(NULL, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0), kCFStringEncodingUTF8, false); - return accessGroup != NULL; - }); - - return (bool)(rowOk && accessGroup != NULL); - }); - - CFReleaseNull(sql); - return (bool)(dbOk && accessGroup); - }); - - if (ok) { - return accessGroup; - } - else { - CFReleaseNull(accessGroup); - return NULL; - } -} - -/* AUDIT[securityd](done): - query (ok) is a caller provided dictionary, only its cf type has been checked. - */ -static bool -SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, - SecurityClient *client, CFErrorRef *error) -{ - CFArrayRef accessGroups = CFRetainSafe(client->accessGroups); - - CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - CFReleaseNull(accessGroups); - return SecEntitlementError(error); - } - - SecSignpostStart(SecSignpostSecItemCopyMatching); - - if (client->canAccessNetworkExtensionAccessGroups) { - CFDataRef persistentRef = CFDictionaryGetValue(query, kSecValuePersistentRef); - CFStringRef itemClass = NULL; - sqlite_int64 itemRowID = 0; - if (persistentRef && _SecItemParsePersistentRef(persistentRef, &itemClass, &itemRowID, NULL)) { - CFStringRef accessGroup = CopyAccessGroupForRowID(itemRowID, itemClass); - if (accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix) && !CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), accessGroup)) { - CFMutableArrayRef mutableAccessGroups = CFArrayCreateMutableCopy(NULL, 0, accessGroups); - CFArrayAppendValue(mutableAccessGroups, accessGroup); - CFReleaseNull(accessGroups); - accessGroups = mutableAccessGroups; - } - CFReleaseNull(accessGroup); - } - } - - if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { - /* Having the special accessGroup "*" allows access to all accessGroups. */ - CFReleaseNull(accessGroups); - } - - bool ok = false; - Query *q = query_create_with_limit(query, client->musr, 1, error); - if (q) { - CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup); - if (agrp) { - if (accessGroupsAllows(accessGroups, agrp, client)) { - const void *val = agrp; - CFReleaseNull(accessGroups); - accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks); - } else { - (void)SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); - CFReleaseNull(accessGroups); - query_destroy(q, NULL); - return false; - } - } else { -#if !TARGET_OS_OSX - if (accessGroups != NULL) { - // On iOS, drop 'com.apple.token' AG from allowed accessGroups, to avoid inserting token elements into - // unsuspecting application's keychain. If the application on iOS wants to access token items, it needs - // explicitly specify kSecAttrAccessGroup=kSecAttrAccessGroupToken in its query. - CFMutableArrayRef mutableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, accessGroups); - CFArrayRemoveAllValue(mutableGroups, kSecAttrAccessGroupToken); - CFReleaseNull(accessGroups); - accessGroups = mutableGroups; - } -#endif - } - -#if TARGET_OS_IPHONE - if (q->q_sync_bubble && client->inMultiUser) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCreateSyncBubbleUserUUID(q->q_sync_bubble); - } else if (client->inMultiUser && client->isNetworkExtension) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCreateBothUserAndSystemUUID(client->uid); - } else if (q->q_system_keychain && client->inMultiUser) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCopySystemKeychainUUID(); - } else { - q->q_system_keychain = false; - } -#endif - - query_set_caller_access_groups(q, accessGroups); - - /* Sanity check the query. */ - if (q->q_system_keychain && !client->allowSystemKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); - } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); - } else if (q->q_system_keychain && q->q_sync_bubble) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("can't do both system and syncbubble keychain")); - } else if (q->q_use_item_list) { - ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported")); - } else if (q->q_match_issuer && ((q->q_class != cert_class()) && - (q->q_class != identity_class()))) { - ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute")); - } else if (q->q_match_policy && ((q->q_class != cert_class()) && - (q->q_class != identity_class()))) { - ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported kSecMatchPolicy attribute")); - } else if (q->q_return_type != 0 && result == NULL) { - ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer")); - } else if (!q->q_error) { - ok = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { - return s3dl_copy_matching(dbt, q, result, accessGroups, error); - }); - } - - if (!query_destroy(q, error)) - ok = false; - } - CFReleaseNull(accessGroups); - - SecSignpostStop(SecSignpostSecItemCopyMatching); - - return ok; -} - -bool -_SecItemCopyMatching(CFDictionaryRef query, SecurityClient *client, CFTypeRef *result, CFErrorRef *error) { - return SecItemServerCopyMatching(query, result, client, error); -} - -#if TARGET_OS_IPHONE -static bool -SecItemSynchronizable(CFDictionaryRef query) -{ - bool result = false; - CFTypeRef value = CFDictionaryGetValue(query, kSecAttrSynchronizable); - if (isBoolean(value)) - return CFBooleanGetValue(value); - else if (isNumber(value)) { - SInt32 number = 0; - (void)CFNumberGetValue(value, kCFNumberSInt32Type, &number); - result = !!number; - } - - return result; -} -#endif - -static CFArrayRef -SecurityClientCopyWritableAccessGroups(SecurityClient *client) { - if (client == NULL || client->accessGroups == NULL) { - return NULL; - } - CFIndex count = CFArrayGetCount(client->accessGroups); - if (CFArrayContainsValue(client->accessGroups, CFRangeMake(0, count), kSecAttrAccessGroupToken)) { - CFMutableArrayRef writableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, client->accessGroups); - CFArrayRemoveAllValue(writableGroups, kSecAttrAccessGroupToken); - return writableGroups; - } else { - return CFRetainSafe(client->accessGroups); - } -} - - -/* AUDIT[securityd](done): - attributes (ok) is a caller provided dictionary, only its cf type has - been checked. - */ -bool -_SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *result, CFErrorRef *error) -{ - CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); - - bool ok = true; - CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - CFReleaseNull(accessGroups); - return SecEntitlementError(error); - } - - SecSignpostStart(SecSignpostSecItemAdd); - - Query *q = query_create_with_limit(attributes, client->musr, 0, error); - if (q) { - /* Access group sanity checking. */ - CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes, - kSecAttrAccessGroup); - - /* Having the special accessGroup "*" allows access to all accessGroups. */ - if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) - CFReleaseNull(accessGroups); - - if (agrp) { - /* The user specified an explicit access group, validate it. */ - if (!accessGroupsAllows(accessGroups, agrp, client)) - ok = SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); - } else { - agrp = (CFStringRef)CFArrayGetValueAtIndex(client->accessGroups, 0); - - /* We are using an implicit access group, add it as if the user - specified it as an attribute. */ - query_add_attribute(kSecAttrAccessGroup, agrp, q); - } - - if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { - CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("add"), CFSTR("AccessGroup"), agrp, NULL); - if (dict) { - SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); - CFRelease(dict); - } - } -#if TARGET_OS_IPHONE - if (q->q_system_keychain && client->inMultiUser) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCopySystemKeychainUUID(); - } else { - q->q_system_keychain = false; - } - query_add_attribute_with_desc(&v8musr, q->q_musrView, q); -#endif - - if (ok) { - query_ensure_access_control(q, agrp); - -#if OCTAGON - void (^add_sync_callback)(bool, CFErrorRef) = CFDictionaryGetValue(attributes, CFSTR("f_ckkscallback")); - if(add_sync_callback) { - // The existence of this callback indicates that we need a predictable UUID for this item. - q->q_uuid_from_primary_key = true; - q->q_add_sync_callback = add_sync_callback; - } -#endif - - if (q->q_system_keychain && !client->allowSystemKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); - } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); -#if TARGET_OS_IPHONE - } else if (q->q_system_keychain && SecItemSynchronizable(attributes) && !client->inMultiUser) { - ok = SecError(errSecInvalidKey, error, CFSTR("Can't store system keychain and synchronizable")); -#endif - } else if (q->q_row_id || q->q_token_object_id) { - ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id")); // TODO: better error string - } else if (!q->q_error) { - ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){ - return kc_transaction(dbt, error, ^{ - query_pre_add(q, true); - return s3dl_query_add(dbt, q, result, error); - }); - }); - } - } - ok = query_notify_and_destroy(q, ok, error); - } else { - ok = false; - } - CFReleaseNull(accessGroups); - - SecSignpostStop(SecSignpostSecItemAdd); - - return ok; -} - -/* AUDIT[securityd](done): - query (ok) and attributesToUpdate (ok) are a caller provided dictionaries, - only their cf types have been checked. - */ -bool -_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, - SecurityClient *client, CFErrorRef *error) -{ - CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); - - CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - CFReleaseNull(accessGroups); - return SecEntitlementError(error); - } - - // Queries using implicit access groups which only find items that're inaccessible yield errSecItemNotFound, - // but we can pre-emptively shut down queries which are clearly illegal - CFTypeRef q_agrp = CFDictionaryGetValue(query, kSecAttrAccessGroup); - if (q_agrp && !accessGroupsAllows(accessGroups, q_agrp, client)) { - SecEntitlementErrorForExplicitAccessGroup(q_agrp, accessGroups, error); - CFReleaseSafe(accessGroups); - return false; - } - - SecSignpostStart(SecSignpostSecItemUpdate); - - if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { - CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); - CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("update"), CFSTR("AccessGroup"), agrp, NULL); - if (dict) { - SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); - CFRelease(dict); - } - } - - if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { - /* Having the special accessGroup "*" allows access to all accessGroups. */ - CFReleaseNull(accessGroups); - } - - bool ok = true; - Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); - if (!q) { - ok = false; - } - if (ok) { -#if TARGET_OS_IPHONE - if (q->q_system_keychain && client->inMultiUser) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCopySystemKeychainUUID(); - } else { - q->q_system_keychain = false; - } -#endif - - /* Sanity check the query. */ - query_set_caller_access_groups(q, accessGroups); - if (q->q_system_keychain && !client->allowSystemKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); - } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); -#if TARGET_OS_IPHONE - } else if (q->q_system_keychain && SecItemSynchronizable(attributesToUpdate) && !client->inMultiUser) { - ok = SecError(errSecInvalidKey, error, CFSTR("Can't update an system keychain item with synchronizable")); -#endif - } else if (q->q_use_item_list) { - ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list not supported")); - } else if (q->q_return_type & kSecReturnDataMask) { - /* Update doesn't return anything so don't ask for it. */ - ok = SecError(errSecReturnDataUnsupported, error, CFSTR("return data not supported by update")); - } else if (q->q_return_type & kSecReturnAttributesMask) { - ok = SecError(errSecReturnAttributesUnsupported, error, CFSTR("return attributes not supported by update")); - } else if (q->q_return_type & kSecReturnRefMask) { - ok = SecError(errSecReturnRefUnsupported, error, CFSTR("return ref not supported by update")); - } else if (q->q_return_type & kSecReturnPersistentRefMask) { - ok = SecError(errSecReturnPersistentRefUnsupported, error, CFSTR("return persistent ref not supported by update")); - } else { - /* Access group sanity checking. */ - CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate, - kSecAttrAccessGroup); - if (agrp) { - /* The user is attempting to modify the access group column, - validate it to make sure the new value is allowable. */ - if (!accessGroupsAllows(accessGroups, agrp, client)) { - secerror("Cannot update keychain item to access group %@", agrp); - ok = SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); - } - } - } - } - if (ok) { - ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - return s3dl_query_update(dbt, q, attributesToUpdate, accessGroups, error); - }); - }); - } - if (q) { - ok = query_notify_and_destroy(q, ok, error); - } - CFReleaseNull(accessGroups); - - SecSignpostStop(SecSignpostSecItemUpdate); - - return ok; -} - - -/* AUDIT[securityd](done): - query (ok) is a caller provided dictionary, only its cf type has been checked. - */ -bool -_SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error) -{ - CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); - - CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - CFReleaseNull(accessGroups); - return SecEntitlementError(error); - } - - CFTypeRef q_agrp = CFDictionaryGetValue(query, kSecAttrAccessGroup); - if (q_agrp && !accessGroupsAllows(accessGroups, q_agrp, client)) { - SecEntitlementErrorForExplicitAccessGroup(q_agrp, accessGroups, error); - CFReleaseSafe(accessGroups); - return false; - } - - SecSignpostStart(SecSignpostSecItemDelete); - - if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { - CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); - CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("delete"), CFSTR("AccessGroup"), agrp, NULL); - if (dict) { - SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); - CFRelease(dict); - } - } - - if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { - /* Having the special accessGroup "*" allows access to all accessGroups. */ - CFReleaseNull(accessGroups); - } - - Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); - bool ok; - if (q) { -#if TARGET_OS_IPHONE - if (q->q_system_keychain && client->inMultiUser) { - CFReleaseNull(q->q_musrView); - q->q_musrView = SecMUSRCopySystemKeychainUUID(); - } else { - q->q_system_keychain = false; - } -#endif - - query_set_caller_access_groups(q, accessGroups); - /* Sanity check the query. */ - if (q->q_system_keychain && !client->allowSystemKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); - } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); - } else if (q->q_limit != kSecMatchUnlimited) { - ok = SecError(errSecMatchLimitUnsupported, error, CFSTR("match limit not supported by delete")); - } else if (query_match_count(q) != 0) { - ok = SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported by delete")); - } else if (q->q_ref) { - ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete")); - } else if (q->q_row_id && query_attr_count(q)) { - ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive")); - } else if (q->q_token_object_id && query_attr_count(q) != 1) { - ok = SecError(errSecItemIllegalQuery, error, CFSTR("token persistent ref and other attributes are mutually exclusive")); - } else { - ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - return s3dl_query_delete(dbt, q, accessGroups, error); - }); - }); - } - ok = query_notify_and_destroy(q, ok, error); - } else { - ok = false; - } - CFReleaseNull(accessGroups); - - SecSignpostStop(SecSignpostSecItemDelete); - - return ok; -} - -static bool SecItemDeleteTokenItems(SecDbConnectionRef dbt, CFTypeRef classToDelete, CFTypeRef tokenID, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) { - CFTypeRef keys[] = { kSecClass, kSecAttrTokenID }; - CFTypeRef values[] = { classToDelete, tokenID }; - - CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); - CFRelease(query); - bool ok; - if (q) { - query_set_caller_access_groups(q, accessGroups); - ok = s3dl_query_delete(dbt, q, accessGroups, error); - ok = query_notify_and_destroy(q, ok, error); - } else { - ok = false; - } - - return ok; -} - -static bool SecItemAddTokenItem(SecDbConnectionRef dbt, CFDictionaryRef attributes, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) { - bool ok = true; - Query *q = query_create_with_limit(attributes, client->musr, 0, error); - if (q) { - CFStringRef agrp = kSecAttrAccessGroupToken; - query_add_attribute(kSecAttrAccessGroup, agrp, q); - - if (ok) { - query_ensure_access_control(q, agrp); - if (q->q_system_keychain && !client->allowSystemKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); - } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { - ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); - } else if (q->q_row_id || q->q_token_object_id) { - ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id")); // TODO: better error string - } else if (!q->q_error) { - query_pre_add(q, true); - ok = s3dl_query_add(dbt, q, NULL, error); - } - } - ok = query_notify_and_destroy(q, ok, error); - } else { - return false; - } - return ok; -} - -bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error) { - bool ok = true; - CFArrayRef accessGroups = client->accessGroups; - CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { - return SecEntitlementError(error); - } - - ok = kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^bool { - if (items) { - const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey }; - for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) { - SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, NULL); - } - - for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { - if (!SecItemAddTokenItem(dbt, CFArrayGetValueAtIndex(items, i), accessGroups, client, error)) - return false; - } - return true; - } - else { - const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey }; - bool deleted = true; - for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) { - if (!SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, error) && error && CFErrorGetCode(*error) != errSecItemNotFound) { - deleted = false; - break; - } - else if (error && *error) { - CFReleaseNull(*error); - } - } - return deleted; - } - }); - }); - - return ok; -} - -static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClass const* class, CFErrorRef* error) { - CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); - - __block CFErrorRef localError = NULL; - SecDbQueryRef q = query_create(class, NULL, query, &localError); - if (q == NULL) { // illegal query or out of memory - secerror("SecItemServerDeleteAll: aborting because failed to initialize Query: %@", localError); - abort(); - } - SecDbItemSelect(q, dbt, &localError, ^bool(const SecDbAttr *attr) { - return (attr->flags & kSecDbInFlag) && !CFEqual(attr->name, CFSTR("data")); - }, NULL, NULL, NULL, - ^(SecDbItemRef item, bool *stop) { - if (!SecItemIsSystemBound(item->attributes, class, false) && - !CFEqual(CFDictionaryGetValue(item->attributes, kSecAttrAccessGroup), CFSTR("com.apple.bluetooth"))) - { - SecDbItemDelete(item, dbt, kCFBooleanFalse, &localError); - } - }); - query_destroy(q, &localError); - - if (localError) { - if (error) { - CFReleaseNull(*error); - *error = localError; - } else { - CFReleaseNull(localError); - } - return false; - } - return true; -} - -// Delete all the items except sysbound ones because horrible things happen if you do, like bluetooth devices unpairing -static bool -SecItemServerDeleteAll(CFErrorRef *error) { - secerror("SecItemServerDeleteAll"); - return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) { - return (kc_transaction(dbt, error, ^bool { - bool ok = true; - ok &= SecDbExec(dbt, CFSTR("DELETE FROM genp WHERE sync=1;"), error); - ok &= SecDbExec(dbt, CFSTR("DELETE FROM inet WHERE sync=1;"), error); - ok &= SecDbExec(dbt, CFSTR("DELETE FROM cert WHERE sync=1;"), error); - ok &= SecDbExec(dbt, CFSTR("DELETE FROM keys WHERE sync=1;"), error); - - ok &= deleteNonSysboundItemsForItemClass(dbt, genp_class(), error); - ok &= deleteNonSysboundItemsForItemClass(dbt, inet_class(), error); - ok &= deleteNonSysboundItemsForItemClass(dbt, cert_class(), error); - ok &= deleteNonSysboundItemsForItemClass(dbt, keys_class(), error); - - return ok; - }) && SecDbExec(dbt, CFSTR("VACUUM;"), error)); - }); -} - -bool -_SecItemDeleteAll(CFErrorRef *error) { - return SecItemServerDeleteAll(error); -} - -bool -_SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) -{ - __block bool ok = true; - static dispatch_once_t onceToken; - static CFSetRef illegalAccessGroups = NULL; - - dispatch_once(&onceToken, ^{ - const CFStringRef values[] = { - CFSTR("*"), - CFSTR("apple"), - CFSTR("com.apple.security.sos"), - CFSTR("lockdown-identities"), - }; - illegalAccessGroups = CFSetCreate(NULL, (const void **)values, sizeof(values)/sizeof(values[0]), &kCFTypeSetCallBacks); - }); - - static CFTypeRef qclasses[] = { - NULL, - NULL, - NULL, - NULL - }; - // strange construction needed for schema indirection - static dispatch_once_t qclassesOnceToken; - dispatch_once(&qclassesOnceToken, ^{ - qclasses[0] = inet_class(); - qclasses[1] = genp_class(); - qclasses[2] = keys_class(); - qclasses[3] = cert_class(); - }); - - require_action_quiet(isArray(accessGroups), fail, - ok = false; - SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("accessGroups not CFArray, got %@"), accessGroups)); - - // TODO: whitelist instead? look for dev IDs like 7123498YQX.com.somedev.app - - require_action(CFArrayGetCount(accessGroups) != 0, fail, - ok = false; - SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("accessGroups e empty"))); - - - // Pre-check accessGroups for prohibited values - CFArrayForEach(accessGroups, ^(const void *value) { - CFStringRef agrp = (CFStringRef)value; - - if (!isString(agrp)) { - SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, - CFSTR("access not a string: %@"), agrp); - ok &= false; - } else if (CFSetContainsValue(illegalAccessGroups, agrp)) { - SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, - CFSTR("illegal access group: %@"), accessGroups); - ok &= false; - } - }); - require(ok,fail); - - ok = kc_with_dbt(true, error, ^bool(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^bool { - CFErrorRef localError = NULL; - bool ok1 = true; - size_t n; - - for (n = 0; n < sizeof(qclasses)/sizeof(qclasses[0]) && ok1; n++) { - Query *q; - - q = query_create(qclasses[n], client->musr, NULL, error); - require(q, fail2); - - (void)s3dl_query_delete(dbt, q, accessGroups, &localError); - fail2: - query_destroy(q, error); - CFReleaseNull(localError); - } - return ok1; - }) && SecDbExec(dbt, CFSTR("VACUUM"), error); - }); - -fail: - return ok; -} - - -// MARK: - -// MARK: Shared web credentials - -#if SHAREDWEBCREDENTIALS - -/* constants */ -#define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); - -SEC_CONST_DECL (kSecSafariAccessGroup, "com.apple.cfnetwork"); -SEC_CONST_DECL (kSecSafariDefaultComment, "default"); -SEC_CONST_DECL (kSecSafariPasswordsNotSaved, "Passwords not saved"); -SEC_CONST_DECL (kSecSharedCredentialUrlScheme, "https://"); -SEC_CONST_DECL (kSecSharedWebCredentialsService, "webcredentials"); - -#if !TARGET_OS_SIMULATOR -static SWCFlags -_SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error) -{ - __block SWCFlags flags = kSWCFlags_None; - OSStatus status; - - secnotice("swc", "Application %@ is requesting approval for %@", appID, fqdn); - - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - if (semaphore == NULL) - return 0; - - status = SWCCheckService(kSecSharedWebCredentialsService, appID, fqdn, ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails) - { - if (inStatus == 0) { - flags = inFlags; - } else { - secerror("SWCCheckService failed with %d", (int)inStatus); - } - dispatch_semaphore_signal(semaphore); - }); - - if (status == 0) { - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); - } else { - secerror("SWCCheckService: failed to queue"); - } - dispatch_release(semaphore); - - if (error) { - if (!(flags & kSWCFlag_SiteApproved)) { - SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID); - } else if (flags & kSWCFlag_UserDenied) { - SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID); - } - } - return flags; -} - -static bool -_SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, CFStringRef service) -{ - bool result = false; - CFIndex idx, count = (domains) ? CFArrayGetCount(domains) : (CFIndex) 0; - if (!count || !domain || !service) { - return result; - } - for (idx=0; idx < count; idx++) { - CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx); - if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) { - CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1; - CFIndex substr_len = CFStringGetLength(str) - prefix_len; - CFRange range = { prefix_len, substr_len }; - CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range); - if (substr && CFEqual(substr, domain)) { - result = true; - } - CFReleaseSafe(substr); - if (result) { - break; - } - } - } - return result; -} -#endif /* !TARGET_OS_SIMULATOR */ - -static bool -_SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringRef appID, bool forSafari) -{ -#if !TARGET_OS_SIMULATOR - bool result = false; - if (!fqdn) { return result; } - - // update our database - CFRetainSafe(appID); - CFRetainSafe(fqdn); - if (0 == SWCSetServiceFlags(kSecSharedWebCredentialsService, appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied, - ^void(OSStatus inStatus, SWCFlags inNewFlags){ - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - })) - { - result = true; - } - else // didn't queue the block - { - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - } - - if (!forSafari) { return result; } - - // below this point: create a negative Safari web credential item - - CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!attrs) { return result; } - - CFErrorRef error = NULL; - CFStringRef accessGroup = CFSTR("*"); - SecurityClient swcclient = { - .task = NULL, - .accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks), - .allowSystemKeychain = false, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - .musr = client->musr, - }; - - CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup); - CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); - CFDictionaryAddValue(attrs, kSecAttrProtocol, kSecAttrProtocolHTTPS); - CFDictionaryAddValue(attrs, kSecAttrServer, fqdn); - CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue); - - (void)_SecItemDelete(attrs, &swcclient, &error); - CFReleaseNull(error); - - CFDictionaryAddValue(attrs, kSecAttrAccount, kSecSafariPasswordsNotSaved); - CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment); - - CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault, - NULL, CFSTR("%@ (%@)"), fqdn, kSecSafariPasswordsNotSaved); - if (label) { - CFDictionaryAddValue(attrs, kSecAttrLabel, label); - CFReleaseSafe(label); - } - - UInt8 space = ' '; - CFDataRef data = CFDataCreate(kCFAllocatorDefault, &space, 1); - if (data) { - CFDictionarySetValue(attrs, kSecValueData, data); - CFReleaseSafe(data); - } - - CFTypeRef addResult = NULL; - result = _SecItemAdd(attrs, &swcclient, &addResult, &error); - - CFReleaseSafe(addResult); - CFReleaseSafe(error); - CFReleaseSafe(attrs); - CFReleaseSafe(swcclient.accessGroups); - - return result; -#else - return true; -#endif -} - -/* Specialized version of SecItemAdd for shared web credentials */ -bool -_SecAddSharedWebCredential(CFDictionaryRef attributes, - SecurityClient *client, - const audit_token_t *clientAuditToken, - CFStringRef appID, - CFArrayRef domains, - CFTypeRef *result, - CFErrorRef *error) -{ - - SecurityClient swcclient = {}; - - CFStringRef fqdn = CFRetainSafe(CFDictionaryGetValue(attributes, kSecAttrServer)); - CFStringRef account = CFDictionaryGetValue(attributes, kSecAttrAccount); -#if TARGET_OS_IOS && !TARGET_OS_BRIDGE - CFStringRef password = CFDictionaryGetValue(attributes, kSecSharedPassword); -#else - CFStringRef password = CFDictionaryGetValue(attributes, CFSTR("spwd")); -#endif - CFStringRef accessGroup = CFSTR("*"); - CFMutableDictionaryRef query = NULL, attrs = NULL; - SInt32 port = -1; - bool ok = false; - - // check autofill enabled status - if (!swca_autofill_enabled(clientAuditToken)) { - SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings")); - goto cleanup; - } - - // parse fqdn with CFURL here, since it could be specified as domain:port - if (fqdn) { - CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn); - if (urlStr) { - CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil); - if (url) { - CFStringRef hostname = CFURLCopyHostName(url); - if (hostname) { - CFReleaseSafe(fqdn); - fqdn = hostname; - port = CFURLGetPortNumber(url); - } - CFReleaseSafe(url); - } - CFReleaseSafe(urlStr); - } - } - - if (!account) { - SecError(errSecParam, error, CFSTR("No account provided")); - goto cleanup; - } - if (!fqdn) { - SecError(errSecParam, error, CFSTR("No domain provided")); - goto cleanup; - } - -#if TARGET_OS_SIMULATOR - secerror("app/site association entitlements not checked in Simulator"); -#else - OSStatus status = errSecMissingEntitlement; - // validate that fqdn is part of caller's shared credential domains entitlement - if (!appID) { - SecError(status, error, CFSTR("Missing application-identifier entitlement")); - goto cleanup; - } - if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) { - status = errSecSuccess; - } - if (errSecSuccess != status) { - CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains); - if (!msg) { - msg = CFRetain(CFSTR("Requested domain not found in entitlement")); - } - SecError(status, error, CFSTR("%@"), msg); - CFReleaseSafe(msg); - goto cleanup; - } -#endif - -#if TARGET_OS_SIMULATOR - secerror("Ignoring app/site approval state in the Simulator."); -#else - // get approval status for this app/domain pair - SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error); - if (!(flags & kSWCFlag_SiteApproved)) { - goto cleanup; - } -#endif - - // give ourselves access to see matching items for kSecSafariAccessGroup - swcclient.task = NULL; - swcclient.accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks); - swcclient.allowSystemKeychain = false; - swcclient.musr = client->musr; - swcclient.allowSystemKeychain = false; - swcclient.allowSyncBubbleKeychain = false; - swcclient.isNetworkExtension = false; - - - // create lookup query - query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!query) { - SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary")); - goto cleanup; - } - CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(query, kSecAttrAccessGroup, kSecSafariAccessGroup); - CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); - CFDictionaryAddValue(query, kSecAttrServer, fqdn); - CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue); - - // check for presence of Safari's negative entry ('passwords not saved') - CFDictionarySetValue(query, kSecAttrAccount, kSecSafariPasswordsNotSaved); - ok = _SecItemCopyMatching(query, &swcclient, result, error); - if(result) CFReleaseNull(*result); - if (error) CFReleaseNull(*error); - if (ok) { - SecError(errSecDuplicateItem, error, CFSTR("Item already exists for this server")); - goto cleanup; - } - - // now use the provided account (and optional port number, if one was present) - CFDictionarySetValue(query, kSecAttrAccount, account); - if (port < -1 || port > 0) { - SInt16 portValueShort = (port & 0xFFFF); - CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort); - CFDictionaryAddValue(query, kSecAttrPort, portNumber); - CFReleaseSafe(portNumber); - } - - // look up existing password - CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue); - bool matched = _SecItemCopyMatching(query, &swcclient, result, error); - CFDictionaryRemoveValue(query, kSecReturnData); - if (matched) { - // found it, so this becomes either an "update password" or "delete password" operation - bool update = (password != NULL); - if (update) { - attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0); - CFDictionaryAddValue(attrs, kSecValueData, credential); - bool samePassword = result && *result && CFEqual(*result, credential); - CFReleaseSafe(credential); - CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment); - - ok = samePassword || swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error, - ^void (CFStringRef confirm_fqdn) { - _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); - }); - if (ok) { - ok = _SecItemUpdate(query, attrs, &swcclient, error); - } - } - else { - // confirm the delete - // (per rdar://16676288 we always prompt, even if there was prior user approval) - ok = /*approved ||*/ swca_confirm_operation(swca_delete_request_id, clientAuditToken, query, error, - ^void (CFStringRef confirm_fqdn) { - _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); - }); - if (ok) { - ok = _SecItemDelete(query, &swcclient, error); - } - } - - if(result) CFReleaseNull(*result); - if(error) CFReleaseNull(*error); - - goto cleanup; - } - if (result) CFReleaseNull(*result); - if (error) CFReleaseNull(*error); - - // password does not exist, so prepare to add it - if (!password) { - // a NULL password value removes the existing credential. Since we didn't find it, this is a no-op. - ok = true; - goto cleanup; - } - else { - CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ (%@)"), fqdn, account); - if (label) { - CFDictionaryAddValue(query, kSecAttrLabel, label); - CFReleaseSafe(label); - } - // NOTE: we always expect to use HTTPS for web forms. - CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTPS); - - CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0); - CFDictionarySetValue(query, kSecValueData, credential); - CFReleaseSafe(credential); - CFDictionarySetValue(query, kSecAttrComment, kSecSafariDefaultComment); - - CFReleaseSafe(swcclient.accessGroups); - swcclient.accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&kSecSafariAccessGroup, 1, &kCFTypeArrayCallBacks); - - // mark the item as created by this function - const int32_t creator_value = 'swca'; - CFNumberRef creator = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &creator_value); - if (creator) { - CFDictionarySetValue(query, kSecAttrCreator, creator); - CFReleaseSafe(creator); - } - - // confirm the add - ok = swca_confirm_operation(swca_add_request_id, clientAuditToken, query, error, ^void (CFStringRef confirm_fqdn) { - _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); - }); - } - if (ok) { - ok = _SecItemAdd(query, &swcclient, result, error); - } - -cleanup: - CFReleaseSafe(attrs); - CFReleaseSafe(query); - CFReleaseSafe(swcclient.accessGroups); - CFReleaseSafe(fqdn); - return ok; -} - -/* Specialized version of SecItemCopyMatching for shared web credentials */ -bool -_SecCopySharedWebCredential(CFDictionaryRef query, - SecurityClient *client, - const audit_token_t *clientAuditToken, - CFStringRef appID, - CFArrayRef domains, - CFTypeRef *result, - CFErrorRef *error) -{ - CFMutableArrayRef credentials = NULL; - CFMutableArrayRef foundItems = NULL; - CFMutableArrayRef fqdns = NULL; - CFStringRef fqdn = NULL; - CFStringRef account = NULL; - SInt32 port = -1; - bool ok = false; - - require_quiet(result, cleanup); - credentials = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - foundItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - fqdns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - - // give ourselves access to see matching items for kSecSafariAccessGroup - CFStringRef accessGroup = CFSTR("*"); - SecurityClient swcclient = { - .task = NULL, - .accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks), - .allowSystemKeychain = false, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - .musr = client->musr, - }; - - // On input, the query dictionary contains optional fqdn and account entries. - fqdn = CFDictionaryGetValue(query, kSecAttrServer); - account = CFDictionaryGetValue(query, kSecAttrAccount); - - // Check autofill enabled status - if (!swca_autofill_enabled(clientAuditToken)) { - SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings")); - goto cleanup; - } - - // Check fqdn; if NULL, add domains from caller's entitlement. - if (fqdn) { - CFArrayAppendValue(fqdns, fqdn); - } - else if (domains) { - CFIndex idx, count = CFArrayGetCount(domains); - for (idx=0; idx < count; idx++) { - CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx); - // Parse the entry for our service label prefix - if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) { - CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1; - CFIndex substr_len = CFStringGetLength(str) - prefix_len; - CFRange range = { prefix_len, substr_len }; - fqdn = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range); - if (fqdn) { - CFArrayAppendValue(fqdns, fqdn); - CFRelease(fqdn); - } - } - } - } - CFIndex count, idx; - - count = CFArrayGetCount(fqdns); - if (count < 1) { - SecError(errSecParam, error, CFSTR("No domain provided")); - goto cleanup; - } - - // Aggregate search results for each domain - for (idx = 0; idx < count; idx++) { - CFMutableArrayRef items = NULL; - CFMutableDictionaryRef attrs = NULL; - fqdn = (CFStringRef) CFArrayGetValueAtIndex(fqdns, idx); - CFRetainSafe(fqdn); - port = -1; - - // Parse the fqdn for a possible port specifier. - if (fqdn) { - CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn); - if (urlStr) { - CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil); - if (url) { - CFStringRef hostname = CFURLCopyHostName(url); - if (hostname) { - CFReleaseSafe(fqdn); - fqdn = hostname; - port = CFURLGetPortNumber(url); - } - CFReleaseSafe(url); - } - CFReleaseSafe(urlStr); - } - } - -#if TARGET_OS_SIMULATOR - secerror("app/site association entitlements not checked in Simulator"); -#else - OSStatus status = errSecMissingEntitlement; - if (!appID) { - SecError(status, error, CFSTR("Missing application-identifier entitlement")); - CFReleaseSafe(fqdn); - goto cleanup; - } - // validate that fqdn is part of caller's entitlement - if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) { - status = errSecSuccess; - } - if (errSecSuccess != status) { - CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains); - if (!msg) { - msg = CFRetain(CFSTR("Requested domain not found in entitlement")); - } - SecError(status, error, CFSTR("%@"), msg); - CFReleaseSafe(msg); - CFReleaseSafe(fqdn); - goto cleanup; - } -#endif - - attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!attrs) { - SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary")); - CFReleaseSafe(fqdn); - goto cleanup; - } - CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword); - CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup); - CFDictionaryAddValue(attrs, kSecAttrProtocol, kSecAttrProtocolHTTPS); - CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); - CFDictionaryAddValue(attrs, kSecAttrServer, fqdn); - if (account) { - CFDictionaryAddValue(attrs, kSecAttrAccount, account); - } - if (port < -1 || port > 0) { - SInt16 portValueShort = (port & 0xFFFF); - CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort); - CFDictionaryAddValue(attrs, kSecAttrPort, portNumber); - CFReleaseSafe(portNumber); - } - CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue); - CFDictionaryAddValue(attrs, kSecMatchLimit, kSecMatchLimitAll); - CFDictionaryAddValue(attrs, kSecReturnAttributes, kCFBooleanTrue); - CFDictionaryAddValue(attrs, kSecReturnData, kCFBooleanTrue); - - ok = _SecItemCopyMatching(attrs, &swcclient, (CFTypeRef*)&items, error); - if (count > 1) { - // ignore interim error since we have multiple domains to search - CFReleaseNull(*error); - } - if (ok && items && CFGetTypeID(items) == CFArrayGetTypeID()) { -#if TARGET_OS_SIMULATOR - secerror("Ignoring app/site approval state in the Simulator."); - bool approved = true; -#else - // get approval status for this app/domain pair - SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error); - if (count > 1) { - // ignore interim error since we have multiple domains to check - CFReleaseNull(*error); - } - bool approved = (flags & kSWCFlag_SiteApproved); -#endif - if (approved) { - CFArrayAppendArray(foundItems, items, CFRangeMake(0, CFArrayGetCount(items))); - } - } - CFReleaseSafe(items); - CFReleaseSafe(attrs); - CFReleaseSafe(fqdn); - } - -// If matching credentials are found, the credentials provided to the completionHandler -// will be a CFArrayRef containing CFDictionaryRef entries. Each dictionary entry will -// contain the following pairs (see Security/SecItem.h): -// key: kSecAttrServer value: CFStringRef (the website) -// key: kSecAttrAccount value: CFStringRef (the account) -// key: kSecSharedPassword value: CFStringRef (the password) -// Optional keys: -// key: kSecAttrPort value: CFNumberRef (the port number, if non-standard for https) - - count = CFArrayGetCount(foundItems); - for (idx = 0; idx < count; idx++) { - CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(foundItems, idx); - CFMutableDictionaryRef newdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (newdict && dict && CFGetTypeID(dict) == CFDictionaryGetTypeID()) { - CFStringRef srvr = CFDictionaryGetValue(dict, kSecAttrServer); - CFStringRef acct = CFDictionaryGetValue(dict, kSecAttrAccount); - CFNumberRef pnum = CFDictionaryGetValue(dict, kSecAttrPort); - CFStringRef icmt = CFDictionaryGetValue(dict, kSecAttrComment); - CFDataRef data = CFDictionaryGetValue(dict, kSecValueData); - if (srvr) { - CFDictionaryAddValue(newdict, kSecAttrServer, srvr); - } - if (acct) { - CFDictionaryAddValue(newdict, kSecAttrAccount, acct); - } - if (pnum) { - SInt16 pval = -1; - if (CFNumberGetValue(pnum, kCFNumberSInt16Type, &pval) && - (pval < -1 || pval > 0)) { - CFDictionaryAddValue(newdict, kSecAttrPort, pnum); - } - } - if (data) { - CFStringRef password = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, kCFStringEncodingUTF8); - if (password) { - #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV - CFDictionaryAddValue(newdict, kSecSharedPassword, password); - #else - CFDictionaryAddValue(newdict, CFSTR("spwd"), password); - #endif - CFReleaseSafe(password); - } - } - - if (acct && CFEqual(acct, kSecSafariPasswordsNotSaved)) { - // Do not add to credentials list! - secwarning("copySWC: Skipping \"%@\" item", kSecSafariPasswordsNotSaved); - } else if (icmt && CFEqual(icmt, kSecSafariDefaultComment)) { - CFArrayInsertValueAtIndex(credentials, 0, newdict); - } else { - CFArrayAppendValue(credentials, newdict); - } - } - CFReleaseSafe(newdict); - } - - count = CFArrayGetCount(credentials); - if (count) { - ok = false; - // create a new array of dictionaries (without the actual password) for picker UI - CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - for (idx = 0; idx < count; idx++) { - CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx); - CFMutableDictionaryRef newdict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); - #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV - CFDictionaryRemoveValue(newdict, kSecSharedPassword); - #else - CFDictionaryRemoveValue(newdict, CFSTR("spwd")); - #endif - CFArrayAppendValue(items, newdict); - CFReleaseSafe(newdict); - } - - // prompt user to select one of the dictionary items - CFDictionaryRef selected = swca_copy_selected_dictionary(swca_select_request_id, - clientAuditToken, items, error); - if (selected) { - // find the matching item in our credentials array - CFStringRef srvr = CFDictionaryGetValue(selected, kSecAttrServer); - CFStringRef acct = CFDictionaryGetValue(selected, kSecAttrAccount); - CFNumberRef pnum = CFDictionaryGetValue(selected, kSecAttrPort); - for (idx = 0; idx < count; idx++) { - CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx); - CFStringRef srvr1 = CFDictionaryGetValue(dict, kSecAttrServer); - CFStringRef acct1 = CFDictionaryGetValue(dict, kSecAttrAccount); - CFNumberRef pnum1 = CFDictionaryGetValue(dict, kSecAttrPort); - - if (!srvr || !srvr1 || !CFEqual(srvr, srvr1)) continue; - if (!acct || !acct1 || !CFEqual(acct, acct1)) continue; - if ((pnum && pnum1) && !CFEqual(pnum, pnum1)) continue; - - // we have a match! - CFReleaseSafe(selected); - CFRetainSafe(dict); - selected = dict; - ok = true; - break; - } - } - CFReleaseSafe(items); - CFArrayRemoveAllValues(credentials); - if (selected && ok) { -#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR - fqdn = CFDictionaryGetValue(selected, kSecAttrServer); -#endif - CFArrayAppendValue(credentials, selected); - } - - if (ok) { -#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR - // register confirmation with database - CFRetainSafe(appID); - CFRetainSafe(fqdn); - if (0 != SWCSetServiceFlags(kSecSharedWebCredentialsService, - appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserApproved, - ^void(OSStatus inStatus, SWCFlags inNewFlags){ - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - })) - { - // we didn't queue the block - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - } -#endif - } - CFReleaseSafe(selected); - } - else if (NULL == *error) { - // found no items, and we haven't already filled in the error - SecError(errSecItemNotFound, error, CFSTR("no matching items found")); - } - -cleanup: - if (!ok) { - CFArrayRemoveAllValues(credentials); - CFReleaseNull(credentials); - } - CFReleaseSafe(foundItems); - *result = credentials; - CFReleaseSafe(swcclient.accessGroups); - CFReleaseSafe(fqdns); - - return ok; -} - -#endif /* SHAREDWEBCREDENTIALS */ - - -// MARK: - -// MARK: Keychain backup - -CF_RETURNS_RETAINED CFDataRef -_SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error) { - __block CFDataRef backup; - kc_with_dbt(false, error, ^bool (SecDbConnectionRef dbt) { - - LKABackupReportStart(!!keybag, !!passcode, emcs); - - return kc_transaction_type(dbt, kSecDbNormalTransactionType, error, ^bool{ - secnotice("SecServerKeychainCreateBackup", "Performing backup from %s keybag%s", keybag ? "provided" : "device", emcs ? ", EMCS mode" : ""); - - if (keybag == NULL && passcode == NULL) { -#if USE_KEYSTORE - backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag_handle, error); -#else /* !USE_KEYSTORE */ - (void)client; - SecError(errSecParam, error, CFSTR("Why are you doing this?")); - backup = NULL; -#endif /* USE_KEYSTORE */ - } else { - backup = SecServerKeychainCreateBackup(dbt, client, keybag, passcode, emcs, error); - } - return (backup != NULL); - }); - }); - - secnotice("SecServerKeychainCreateBackup", "Backup result: %s (%@)", backup ? "success" : "fail", error ? *error : NULL); - LKABackupReportEnd(!!backup, error ? *error : NULL); - - return backup; -} - -bool -_SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - if (backup == NULL || keybag == NULL) - return SecError(errSecParam, error, CFSTR("backup or keybag missing")); - - __block bool ok = true; - ok &= kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbconn) { - return SecServerKeychainRestore(dbconn, client, backup, keybag, passcode, error); - }); - - if (ok) { - SecKeychainChanged(); - } - - return ok; -} - -CFStringRef -_SecServerBackupCopyUUID(CFDataRef data, CFErrorRef *error) -{ - CFStringRef uuid = NULL; - CFDictionaryRef backup; - - backup = CFPropertyListCreateWithData(kCFAllocatorDefault, data, - kCFPropertyListImmutable, NULL, - error); - if (isDictionary(backup)) { - uuid = SecServerBackupGetKeybagUUID(backup, error); - if (uuid) - CFRetain(uuid); - } - CFReleaseNull(backup); - - return uuid; -} - - - -// MARK: - -// MARK: SecItemDataSource - -#if SECUREOBJECTSYNC - -// Make sure to call this before any writes to the keychain, so that we fire -// up the engines to monitor manifest changes. -SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void) { - return SecItemDataSourceFactoryGetShared(kc_dbhandle(NULL)); -} - -/* AUDIT[securityd]: - args_in (ok) is a caller provided, CFDictionaryRef. - */ - -CF_RETURNS_RETAINED CFArrayRef -_SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) { - // This never fails, trust us! - return SOSCCHandleUpdateMessage(updates); -} - -// -// Truthiness in the cloud backup/restore support. -// - -static CFDictionaryRef -_SecServerCopyTruthInTheCloud(CFDataRef keybag, CFDataRef password, - CFDictionaryRef backup, CFErrorRef *error) -{ - SOSManifestRef mold = NULL, mnow = NULL, mdelete = NULL, madd = NULL; - __block CFMutableDictionaryRef backup_new = NULL; - keybag_handle_t bag_handle; - if (!ks_open_keybag(keybag, password, &bag_handle, error)) - return backup_new; - - // We need to have a datasource singleton for protection domain - // kSecAttrAccessibleWhenUnlocked and keep a single shared engine - // instance around which we create in the datasource constructor as well. - SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); - if (ds) { - backup_new = backup ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - mold = SOSCreateManifestWithBackup(backup, error); - SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); - mnow = SOSEngineCopyManifest(engine, NULL); - if (!mnow) { - mnow = SOSDataSourceCopyManifestWithViewNameSet(ds, SOSViewsGetV0ViewSet(), error); - } - if (!mnow) { - CFReleaseNull(backup_new); - secerror("failed to obtain manifest for keychain: %@", error ? *error : NULL); - } else { - SOSManifestDiff(mold, mnow, &mdelete, &madd, error); - } - - // Delete everything from the new_backup that is no longer in the datasource according to the datasources manifest. - SOSManifestForEach(mdelete, ^(CFDataRef digest_data, bool *stop) { - CFStringRef deleted_item_key = CFDataCopyHexString(digest_data); - CFDictionaryRemoveValue(backup_new, deleted_item_key); - CFRelease(deleted_item_key); - }); - - CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - SOSDataSourceForEachObject(ds, NULL, madd, error, ^void(CFDataRef digest, SOSObjectRef object, bool *stop) { - CFErrorRef localError = NULL; - CFDataRef digest_data = NULL; - CFTypeRef value = NULL; - if (!object) { - // Key in our manifest can't be found in db, remove it from our manifest - SOSChangesAppendDelete(changes, digest); - } else if (!(digest_data = SOSObjectCopyDigest(ds, object, &localError)) - || !(value = SOSObjectCopyBackup(ds, object, bag_handle, &localError))) { - if (SecErrorGetOSStatus(localError) == errSecDecode) { - // Ignore decode errors, pretend the objects aren't there - CFRelease(localError); - // Object undecodable, remove it from our manifest - SOSChangesAppendDelete(changes, digest); - } else { - // Stop iterating and propagate out all other errors. - *stop = true; - *error = localError; - CFReleaseNull(backup_new); - } - } else { - // TODO: Should we skip tombstones here? - CFStringRef key = CFDataCopyHexString(digest_data); - CFDictionarySetValue(backup_new, key, value); - CFReleaseSafe(key); - } - CFReleaseSafe(digest_data); - CFReleaseSafe(value); - }) || CFReleaseNull(backup_new); - - if (CFArrayGetCount(changes)) { - if (!SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, error)) { - CFReleaseNull(backup_new); - } - } - CFReleaseSafe(changes); - - SOSDataSourceRelease(ds, error) || CFReleaseNull(backup_new); - } - - CFReleaseSafe(mold); - CFReleaseSafe(mnow); - CFReleaseSafe(madd); - CFReleaseSafe(mdelete); - ks_close_keybag(bag_handle, error) || CFReleaseNull(backup_new); - - return backup_new; -} - -static bool -_SecServerRestoreTruthInTheCloud(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) { - __block bool ok = true; - keybag_handle_t bag_handle; - if (!ks_open_keybag(keybag, password, &bag_handle, error)) - return false; - - SOSManifestRef mbackup = SOSCreateManifestWithBackup(backup_in, error); - if (mbackup) { - SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); - ok &= ds && SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) { - SOSManifestRef mnow = SOSDataSourceCopyManifestWithViewNameSet(ds, SOSViewsGetV0BackupViewSet(), error); - SOSManifestRef mdelete = NULL, madd = NULL; - SOSManifestDiff(mnow, mbackup, &mdelete, &madd, error); - - // Don't delete everything in datasource not in backup. - - // Add items from the backup - SOSManifestForEach(madd, ^void(CFDataRef e, bool *stop) { - CFDictionaryRef item = NULL; - CFStringRef sha1 = CFDataCopyHexString(e); - if (sha1) { - item = CFDictionaryGetValue(backup_in, sha1); - CFRelease(sha1); - } - if (item) { - CFErrorRef localError = NULL; - - if (!SOSObjectRestoreObject(ds, txn, bag_handle, item, &localError)) { - OSStatus status = SecErrorGetOSStatus(localError); - if (status == errSecDuplicateItem) { - // Log and ignore duplicate item errors during restore - secnotice("titc", "restore %@ not replacing existing item", item); - } else if (status == errSecDecode) { - // Log and ignore corrupted item errors during restore - secnotice("titc", "restore %@ skipping corrupted item %@", item, localError); - } else { - if (status == errSecInteractionNotAllowed) - *stop = true; - // Propagate the first other error upwards (causing the restore to fail). - secerror("restore %@ failed %@", item, localError); - ok = false; - if (error && !*error) { - *error = localError; - localError = NULL; - } - } - CFReleaseSafe(localError); - } - } - }); - ok &= SOSDataSourceRelease(ds, error); - CFReleaseNull(mdelete); - CFReleaseNull(madd); - CFReleaseNull(mnow); - }); - CFRelease(mbackup); - } - - ok &= ks_close_keybag(bag_handle, error); - - return ok; -} - - -CF_RETURNS_RETAINED CFDictionaryRef -_SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) { - require_action_quiet(isData(keybag), errOut, SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag)); - require_action_quiet(!backup || isDictionary(backup), errOut, SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup)); - require_action_quiet(!password || isData(password), errOut, SecError(errSecParam, error, CFSTR("password %@ not a data"), password)); - - return _SecServerCopyTruthInTheCloud(keybag, password, backup, error); - -errOut: - return NULL; -} - -bool -_SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) { - bool ok; - require_action_quiet(isData(keybag), errOut, ok = SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag)); - require_action_quiet(isDictionary(backup), errOut, ok = SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup)); - if (password) { - - require_action_quiet(isData(password), errOut, ok = SecError(errSecParam, error, CFSTR("password not a data"))); - } - - ok = _SecServerRestoreTruthInTheCloud(keybag, password, backup, error); - -errOut: - return ok; -} -#endif /* SECUREOBJECTSYNC */ - -bool _SecServerRollKeysGlue(bool force, CFErrorRef *error) { - return _SecServerRollKeys(force, NULL, error); -} - - -bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error) { -#if USE_KEYSTORE - uint32_t keystore_generation_status = 0; - if (aks_generation(KEYBAG_DEVICE, generation_noop, &keystore_generation_status)) - return false; - uint32_t current_generation = keystore_generation_status & generation_current; - - return kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - bool up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL); - - if (force && !up_to_date) { - up_to_date = s3dl_dbt_update_keys(dbt, client, error); - if (up_to_date) { - secerror("Completed roll keys."); - up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL); - } - if (!up_to_date) - secerror("Failed to roll keys."); - } - return up_to_date; - }); -#else - return true; -#endif -} - -static bool -InitialSyncItems(CFMutableArrayRef items, bool limitToCurrent, CFStringRef agrp, CFStringRef svce, const SecDbClass *qclass, CFErrorRef *error) -{ - bool result = false; - Query *q = NULL; - - q = query_create(qclass, NULL, NULL, error); - require(q, fail); - - q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; - q->q_limit = kSecMatchUnlimited; - q->q_keybag = KEYBAG_DEVICE; - - query_add_attribute(kSecAttrAccessGroup, agrp, q); - query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q); - query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); - if (svce) - query_add_attribute(kSecAttrService, svce, q); - - result = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - CFErrorRef error2 = NULL; - - SecDbItemSelect(q, dbt, &error2, NULL, ^bool(const SecDbAttr *attr) { - return CFDictionaryGetValue(q->q_item, attr->name); - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - CFErrorRef error3 = NULL; - secinfo("InitialSyncItems", "Copy item"); - - CFMutableDictionaryRef attrs = SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &error3); - if (attrs) { - int match = true; - CFStringRef itemvwht = CFDictionaryGetValue(attrs, kSecAttrSyncViewHint); - /* - * Saying its a SOS viewhint is really not the right answer post Triangle - */ - if (isString(itemvwht) && !SOSViewInSOSSystem(itemvwht)) { - match = false; - } - /* - * Here we encode how PCS stores identities so that we only copy the - * current identites for performance reasons. - */ - if (limitToCurrent) { - enum { PCS_CURRENT_IDENTITY_OFFSET = 0x10000 }; - int32_t s32; - - CFNumberRef type = CFDictionaryGetValue(attrs, kSecAttrType); - if (!isNumber(type)) { - // still allow this case since its not a service identity ?? - } else if (!CFNumberGetValue(type, kCFNumberSInt32Type, &s32)) { - match = false; - } else if ((s32 & PCS_CURRENT_IDENTITY_OFFSET) == 0) { - match = false; - } - } - if (match) { - CFDictionaryAddValue(attrs, kSecClass, SecDbItemGetClass(item)->name); - CFArrayAppendValue(items, attrs); - } - - CFReleaseNull(attrs); - } - CFReleaseNull(error3); - }); - CFReleaseNull(error2); - - return (bool)true; - }); - }); - -fail: - if (q) - query_destroy(q, NULL); - return result; -} - -CFArrayRef -_SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error) -{ - CFMutableArrayRef items = CFArrayCreateMutableForCFTypes(NULL); - - if (flags & SecServerInitialSyncCredentialFlagTLK) { - require_action(InitialSyncItems(items, false, CFSTR("com.apple.security.ckks"), NULL, inet_class(), error), fail, - secerror("failed to collect CKKS-inet keys: %@", error ? *error : NULL)); - } - if (flags & SecServerInitialSyncCredentialFlagPCS) { - bool onlyCurrent = !(flags & SecServerInitialSyncCredentialFlagPCSNonCurrent); - - require_action(InitialSyncItems(items, false, CFSTR("com.apple.ProtectedCloudStorage"), NULL, genp_class(), error), fail, - secerror("failed to collect PCS-genp keys: %@", error ? *error : NULL)); - require_action(InitialSyncItems(items, onlyCurrent, CFSTR("com.apple.ProtectedCloudStorage"), NULL, inet_class(), error), fail, - secerror("failed to collect PCS-inet keys: %@", error ? *error : NULL)); - } - if (flags & SecServerInitialSyncCredentialFlagBluetoothMigration) { - require_action(InitialSyncItems(items, false, CFSTR("com.apple.nanoregistry.migration"), NULL, genp_class(), error), fail, - secerror("failed to collect com.apple.nanoregistry.migration-genp item: %@", error ? *error : NULL)); - require_action(InitialSyncItems(items, false, CFSTR("com.apple.nanoregistry.migration2"), NULL, genp_class(), error), fail, - secerror("failed to collect com.apple.nanoregistry.migration2-genp item: %@", error ? *error : NULL)); - require_action(InitialSyncItems(items, false, CFSTR("com.apple.bluetooth"), CFSTR("BluetoothLESync"), genp_class(), error), fail, - secerror("failed to collect com.apple.bluetooth-genp item: %@", error ? *error : NULL)); - - } - -fail: - return items; -} - -bool -_SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error) -{ - return kc_with_dbt(true, error, ^bool(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^bool(void){ - CFIndex n, count = CFArrayGetCount(array); - - secinfo("ImportInitialSyncItems", "Importing %d items", (int)count); - - for (n = 0; n < count; n++) { - CFErrorRef cferror = NULL; - - CFDictionaryRef item = CFArrayGetValueAtIndex(array, n); - if (!isDictionary(item)) - continue; - - CFStringRef className = CFDictionaryGetValue(item, kSecClass); - if (className == NULL) { - secinfo("ImportInitialSyncItems", "Item w/o class"); - continue; - } - - const SecDbClass *cls = kc_class_with_name(className); - if (cls == NULL) { - secinfo("ImportInitialSyncItems", "Item with unknown class: %@", className); - continue; - } - - SecDbItemRef dbi = SecDbItemCreateWithAttributes(NULL, cls, item, KEYBAG_DEVICE, &cferror); - if (dbi == NULL) { - secinfo("ImportInitialSyncItems", "Item creation failed with: %@", cferror); - CFReleaseNull(cferror); - continue; - } - - if (!SecDbItemSetSyncable(dbi, true, &cferror)) { - secinfo("ImportInitialSyncItems", "Failed to set sync=1: %@ for item %@", cferror, dbi); - CFReleaseNull(cferror); - CFReleaseNull(dbi); - continue; - } - - if (!SecDbItemInsert(dbi, dbt, &cferror)) { - secinfo("ImportInitialSyncItems", "Item store failed with: %@: %@", cferror, dbi); - CFReleaseNull(cferror); - } - CFReleaseNull(dbi); - } - return true; - }); - }); -} - - - -#if TARGET_OS_IOS - -/* - * Sync bubble migration code - */ - -struct SyncBubbleRule { - CFStringRef attribute; - CFTypeRef value; -}; - -static bool -TransmogrifyItemsToSyncBubble(SecurityClient *client, uid_t uid, - bool onlyDelete, - bool copyToo, - const SecDbClass *qclass, - struct SyncBubbleRule *items, CFIndex nItems, - CFErrorRef *error) -{ - CFMutableDictionaryRef updateAttributes = NULL; - CFDataRef syncBubbleView = NULL; - CFDataRef activeUserView = NULL; - bool res = false; - Query *q = NULL; - CFIndex n; - - syncBubbleView = SecMUSRCreateSyncBubbleUserUUID(uid); - require(syncBubbleView, fail); - - activeUserView = SecMUSRCreateActiveUserUUID(uid); - require(activeUserView, fail); - - - if ((onlyDelete && !copyToo) || !onlyDelete) { - - /* - * Clean out items first - */ - - secnotice("syncbubble", "cleaning out old items"); - - q = query_create(qclass, NULL, NULL, error); - require(q, fail); - - q->q_limit = kSecMatchUnlimited; - q->q_keybag = device_keybag_handle; - - for (n = 0; n < nItems; n++) { - query_add_attribute(items[n].attribute, items[n].value, q); - } - q->q_musrView = CFRetain(syncBubbleView); - require(q->q_musrView, fail); - - kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - return s3dl_query_delete(dbt, q, NULL, error); - }); - }); - - query_destroy(q, NULL); - q = NULL; - } - - - if (onlyDelete || !copyToo) { - secnotice("syncbubble", "skip migration of items"); - } else { - /* - * Copy over items from EMCS to sync bubble - */ - - secnotice("syncbubble", "migrating sync bubble items"); - - q = query_create(qclass, NULL, NULL, error); - require(q, fail); - - q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; - q->q_limit = kSecMatchUnlimited; - q->q_keybag = device_keybag_handle; /* XXX change to session key bag when it exists */ - - for (n = 0; n < nItems; n++) { - query_add_or_attribute(items[n].attribute, items[n].value, q); - } - query_add_or_attribute(CFSTR("musr"), activeUserView, q); - q->q_musrView = CFRetain(activeUserView); - - updateAttributes = CFDictionaryCreateMutableForCFTypes(NULL); - require(updateAttributes, fail); - - CFDictionarySetValue(updateAttributes, CFSTR("musr"), syncBubbleView); /* XXX should use kSecAttrMultiUser */ - - - kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - CFErrorRef error2 = NULL; - - SecDbItemSelect(q, dbt, &error2, NULL, ^bool(const SecDbAttr *attr) { - return CFDictionaryGetValue(q->q_item, attr->name); - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - CFErrorRef error3 = NULL; - secinfo("syncbubble", "migrating item"); - - SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, updateAttributes, NULL); - if (new_item == NULL) - return; - - SecDbItemClearRowId(new_item, NULL); - - if (!SecDbItemSetKeybag(new_item, device_keybag_handle, NULL)) { - CFRelease(new_item); - return; - } - - if (!SecDbItemInsert(new_item, dbt, &error3)) { - secnotice("syncbubble", "migration failed with %@ for item %@", error3, new_item); - } - CFRelease(new_item); - CFReleaseNull(error3); - }); - CFReleaseNull(error2); - - return (bool)true; - }); - }); - } - res = true; - -fail: - CFReleaseNull(syncBubbleView); - CFReleaseNull(activeUserView); - CFReleaseNull(updateAttributes); - if (q) - query_destroy(q, NULL); - - return res; -} - -static struct SyncBubbleRule PCSItems[] = { - { - .attribute = CFSTR("agrp"), - .value = CFSTR("com.apple.ProtectedCloudStorage"), - } -}; -static struct SyncBubbleRule NSURLSesssiond[] = { - { - .attribute = CFSTR("agrp"), - .value = CFSTR("com.apple.nsurlsessiond"), - } -}; -static struct SyncBubbleRule AccountsdItems[] = { - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.AppleAccount.token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.AppleAccount.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.AppleAccount.rpassword"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.idms.token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.idms.continuation-key"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.CloudKit.token"), - }, -}; - -static struct SyncBubbleRule MobileMailItems[] = { - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.IMAP.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.SMTP.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Exchange.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Hotmail.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Google.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Google.oauth-token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Google.oath-refresh-token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Yahoo.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Yahoo.oauth-token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Yahoo.oauth-token-nosync"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.Yahoo.oath-refresh-token"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.IMAPNotes.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.IMAPMail.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.126.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.163.password"), - }, - { - .attribute = CFSTR("svce"), - .value = CFSTR("com.apple.account.aol.password"), - }, -}; - -static bool -ArrayContains(CFArrayRef array, CFStringRef service) -{ - return CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), service); -} - -bool -_SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClient *client, CFErrorRef *error) -{ - bool copyCloudAuthToken = false; - bool copyMobileMail = false; - bool res = true; - bool copyPCS = false; - bool onlyDelete = false; - bool copyNSURLSesssion = false; - - if (!client->inMultiUser) - return false; - - secnotice("syncbubble", "migration for uid %d uid for services %@", (int)uid, services); - -#if TARGET_OS_SIMULATOR - // no delete in sim -#elif TARGET_OS_IOS - if (uid != (uid_t)client->activeUser) - onlyDelete = true; -#else -#error "no sync bubble on other platforms" -#endif - - /* - * First select that services to copy/delete - */ - - if (ArrayContains(services, CFSTR("com.apple.bird.usermanager.sync")) - || ArrayContains(services, CFSTR("com.apple.cloudphotod.sync")) - || ArrayContains(services, CFSTR("com.apple.cloudphotod.syncstakeholder")) - || ArrayContains(services, CFSTR("com.apple.cloudd.usermanager.sync"))) - { - copyCloudAuthToken = true; - copyPCS = true; - } - - if (ArrayContains(services, CFSTR("com.apple.nsurlsessiond.usermanager.sync"))) - { - copyCloudAuthToken = true; - copyNSURLSesssion = true; - } - - if (ArrayContains(services, CFSTR("com.apple.syncdefaultsd.usermanager.sync"))) { - copyCloudAuthToken = true; - } - if (ArrayContains(services, CFSTR("com.apple.mailq.sync")) || ArrayContains(services, CFSTR("com.apple.mailq.sync.xpc"))) { - copyCloudAuthToken = true; - copyMobileMail = true; - copyPCS = true; - } - - /* - * The actually copy/delete the items selected - */ - - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, inet_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); - require(res, fail); - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, genp_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); - require(res, fail); - - /* mail */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyMobileMail, genp_class(), MobileMailItems, sizeof(MobileMailItems)/sizeof(MobileMailItems[0]), error); - require(res, fail); - - /* accountsd */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyCloudAuthToken, genp_class(), AccountsdItems, sizeof(AccountsdItems)/sizeof(AccountsdItems[0]), error); - require(res, fail); - - /* nsurlsessiond */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyNSURLSesssion, inet_class(), NSURLSesssiond, sizeof(NSURLSesssiond)/sizeof(NSURLSesssiond[0]), error); - require(res, fail); - -fail: - return res; -} - -/* - * Migrate from user keychain to system keychain when switching to edu mode - */ - -bool -_SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error) -{ - __block bool ok = true; - - /* - * we are not in multi user yet, about to switch, otherwise we would - * check that for client->inMultiuser here - */ - - kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - return kc_transaction(dbt, error, ^{ - CFDataRef systemUUID = SecMUSRGetSystemKeychainUUID(); - - const SecDbSchema *newSchema = current_schema(); - SecDbClass const *const *kcClass; - - for (kcClass = newSchema->classes; *kcClass != NULL; kcClass++) { - CFErrorRef localError = NULL; - Query *q = NULL; - - if (!((*kcClass)->itemclass)) { - continue; - } - - q = query_create(*kcClass, SecMUSRGetSingleUserKeychainUUID(), NULL, error); - if (q == NULL) - continue; - - ok &= SecDbItemSelect(q, dbt, error, ^bool(const SecDbAttr *attr) { - return (attr->flags & kSecDbInFlag) != 0; - }, ^bool(const SecDbAttr *attr) { - // No filtering please. - return false; - }, ^bool(CFMutableStringRef sql, bool *needWhere) { - SecDbAppendWhereOrAnd(sql, needWhere); - CFStringAppendFormat(sql, NULL, CFSTR("musr = ?")); - return true; - }, ^bool(sqlite3_stmt *stmt, int col) { - return SecDbBindObject(stmt, col++, SecMUSRGetSingleUserKeychainUUID(), error); - }, ^(SecDbItemRef item, bool *stop) { - CFErrorRef itemError = NULL; - - if (!SecDbItemSetValueWithName(item, kSecAttrMultiUser, systemUUID, &itemError)) { - secerror("item: %@ update musr to system failed: %@", item, itemError); - ok = false; - goto out; - } - - if (!SecDbItemDoUpdate(item, item, dbt, &itemError, ^bool (const SecDbAttr *attr) { - return attr->kind == kSecDbRowIdAttr; - })) { - secerror("item: %@ insert during UPDATE: %@", item, itemError); - ok = false; - goto out; - } - - out: - SecErrorPropagate(itemError, error); - }); - - if (q) - query_destroy(q, &localError); - - } - return (bool)true; - }); - }); - - return ok; -} - -/* - * Delete account from local usage - */ - -bool -_SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error) -{ - return kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { - CFDataRef musrView = NULL, syncBubbleView = NULL; - bool ok = false; - - syncBubbleView = SecMUSRCreateSyncBubbleUserUUID(uid); - require(syncBubbleView, fail); - - musrView = SecMUSRCreateActiveUserUUID(uid); - require(musrView, fail); - - require(ok = SecServerDeleteAllForUser(dbt, syncBubbleView, false, error), fail); - require(ok = SecServerDeleteAllForUser(dbt, musrView, false, error), fail); - - fail: - CFReleaseNull(syncBubbleView); - CFReleaseNull(musrView); - return ok; - }); -} - - -#endif /* TARGET_OS_IOS */ - -CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) { - const void *keys[] = { - kSecClass, - kSecReturnData, - kSecMatchLimit, - kSecAttrSubject - }, - *values[] = { - kSecClassCertificate, - kCFBooleanTrue, - kSecMatchLimitAll, - normalizedIssuer - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, - NULL, NULL); - CFTypeRef results = NULL; - SecurityClient client = { - .task = NULL, - .accessGroups = accessGroups, - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - }; - - (void)_SecItemCopyMatching(query, &client, &results, error); - CFRelease(query); - return results; -} - -bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) { - const void *keys[] = { - kSecClass, - kSecMatchLimit, - kSecAttrIssuer, - kSecAttrSerialNumber - }, - *values[] = { - kSecClassCertificate, - kSecMatchLimitOne, - normalizedIssuer, - serialNumber - }; - SecurityClient client = { - .task = NULL, - .accessGroups = accessGroups, - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); - CFTypeRef results = NULL; - bool ok = _SecItemCopyMatching(query, &client, &results, error); - CFReleaseSafe(query); - CFReleaseSafe(results); - if (!ok) { - return false; - } - return true; -} diff --git a/OSX/sec/securityd/SecItemServer.h b/OSX/sec/securityd/SecItemServer.h deleted file mode 100644 index 7b550e49..00000000 --- a/OSX/sec/securityd/SecItemServer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemServer - The functions provided in SecItemServer.h provide an interface to - the backend for SecItem APIs in the server. -*/ - -#ifndef _SECURITYD_SECITEMSERVER_H_ -#define _SECURITYD_SECITEMSERVER_H_ - -#include -#include "keychain/SecureObjectSync/SOSCircle.h" -#include "securityd/SecDbQuery.h" -#include "utilities/SecDb.h" -#include -#include "sec/ipc/securityd_client.h" - - -__BEGIN_DECLS - -bool _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *result, CFErrorRef *error); -bool _SecItemCopyMatching(CFDictionaryRef query, SecurityClient *client, CFTypeRef *result, CFErrorRef *error); -bool _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, SecurityClient *client, CFErrorRef *error); -bool _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error); -bool _SecItemDeleteAll(CFErrorRef *error); -bool _SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error); - -bool _SecServerRestoreKeychain(CFErrorRef *error); -bool _SecServerMigrateKeychain(int32_t handle_in, CFDataRef data_in, int32_t *handle_out, CFDataRef *data_out, CFErrorRef *error); -CFDataRef _SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error); -bool _SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error); -CFStringRef _SecServerBackupCopyUUID(CFDataRef backup, CFErrorRef *error); - -bool _SecServerBackupKeybagAdd(SecurityClient *client, CFDataRef passcode, CFDataRef *identifier, CFDataRef *pathinfo, CFErrorRef *error); -bool _SecServerBackupKeybagDelete(CFDictionaryRef attributes, bool deleteAll, CFErrorRef *error); - -bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error); - -CF_RETURNS_RETAINED CFArrayRef _SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error); -CF_RETURNS_RETAINED CFDictionaryRef _SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error); - -int SecServerKeychainTakeOverBackupFD(CFStringRef backupName, CFErrorRef *error); - -bool _SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error); - -#if TARGET_OS_IOS -bool _SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error); -bool _SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClient *client, CFErrorRef *error); -bool _SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error); -#endif - -#if TARGET_OS_IOS && !TARGET_OS_BRIDGE -bool _SecAddSharedWebCredential(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error); -bool _SecCopySharedWebCredential(CFDictionaryRef query, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error); -#endif /* TARGET_OS_IOS */ - -// Hack to log objects from inside SOS code -void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object); - -SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error); -SecDbRef SecKeychainDbInitialize(SecDbRef db); - -bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)); -bool kc_with_dbt_non_item_tables(bool writeAndRead, CFErrorRef* error, bool (^perform)(SecDbConnectionRef dbt)); // can be used when only tables which don't store 'items' are accessed - avoids invoking SecItemDataSourceFactoryGetDefault() -bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)); - - -/* For whitebox testing only */ -void SecKeychainDbReset(dispatch_block_t inbetween); - - -SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void); - -/* FIXME: there is a specific type for keybag handle (keybag_handle_t) - but it's not defined for simulator so we just use an int32_t */ -void SecItemServerSetKeychainKeybag(int32_t keybag); -void SecItemServerResetKeychainKeybag(void); - -void SecItemServerSetKeychainChangedNotification(const char *notification_name); - -CFStringRef __SecKeychainCopyPath(void); - -bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error); -bool _SecServerRollKeysGlue(bool force, CFErrorRef *error); - - -/* initial sync */ -#define SecServerInitialSyncCredentialFlagTLK (1 << 0) -#define SecServerInitialSyncCredentialFlagPCS (1 << 1) -#define SecServerInitialSyncCredentialFlagPCSNonCurrent (1 << 2) -#define SecServerInitialSyncCredentialFlagBluetoothMigration (1 << 3) - -CFArrayRef _SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error); -bool _SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error); - -CF_RETURNS_RETAINED CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error); -bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error); - -bool SecKeychainDbGetVersion(SecDbConnectionRef dbt, int *version, CFErrorRef *error); - - -// Should all be blocks called from SecItemDb -bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item); -bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client); -bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); -void SecKeychainChanged(void); - -__END_DECLS - -#endif /* _SECURITYD_SECITEMSERVER_H_ */ diff --git a/OSX/sec/securityd/SecKeybagSupport.c b/OSX/sec/securityd/SecKeybagSupport.c deleted file mode 100644 index d9c80487..00000000 --- a/OSX/sec/securityd/SecKeybagSupport.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecKeybagSupport.c - CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) - */ - -#include -#include - -#include - -#if USE_KEYSTORE -#include -#include -#include -#include -#include -#else /* !USE_KEYSTORE */ -#include -#endif /* USE_KEYSTORE */ - -#include -#include - -#include "OSX/utilities/SecAKSWrappers.h" - -/* g_keychain_handle is the keybag handle used for encrypting item in the keychain. - For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */ -#if USE_KEYSTORE -#if TARGET_OS_OSX -keybag_handle_t g_keychain_keybag = session_keybag_handle; -#else -keybag_handle_t g_keychain_keybag = device_keybag_handle; -#endif -#else /* !USE_KEYSTORE */ -keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ -#endif /* USE_KEYSTORE */ - -const CFStringRef kSecKSKeyData1 = CFSTR("d1"); -const CFStringRef kSecKSKeyData2 = CFSTR("d2"); - -void SecItemServerSetKeychainKeybag(int32_t keybag) -{ - g_keychain_keybag=keybag; -} - -void SecItemServerResetKeychainKeybag(void) -{ -#if USE_KEYSTORE -#if TARGET_OS_OSX - g_keychain_keybag = session_keybag_handle; -#else - g_keychain_keybag = device_keybag_handle; -#endif -#else /* !USE_KEYSTORE */ - g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ -#endif /* USE_KEYSTORE */ -} - -/* Wrap takes a 128 - 256 bit key as input and returns output of - inputsize + 64 bits. - In bytes this means that a - 16 byte (128 bit) key returns a 24 byte wrapped key - 24 byte (192 bit) key returns a 32 byte wrapped key - 32 byte (256 bit) key returns a 40 byte wrapped key */ -bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, - keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) { -#if USE_KEYSTORE - kern_return_t kernResult = kAKSReturnBadArgument; - - int dest_len = (int)CFDataGetLength(dest); - if (CFEqual(operation, kAKSKeyOpEncrypt)) { - kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class); - } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { - kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len); - } - - if (kernResult != KERN_SUCCESS) { - if ((kernResult == kAKSReturnNoPermission) || (kernResult == kAKSReturnNotPrivileged)) { - const char *substatus = ""; - if (keyclass == key_class_ck || keyclass == key_class_cku) - substatus = " (hibernation?)"; - /* Access to item attempted while keychain is locked. */ - return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked%s."), - kernResult, operation, keyclass, keybag, substatus); - } else if (kernResult == kAKSReturnNotFound) { - return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), kernResult, operation, keyclass, keybag); - } else if (kernResult == kAKSReturnError || kernResult == kAKSReturnDecodeError) { - /* Item can't be decrypted on this device, ever, so drop the item. */ - return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), - kernResult, operation, keyclass, keybag); - } else { - return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"), - kernResult, operation, keyclass, keybag); - } - } - else - CFDataSetLength(dest, dest_len); - return true; -#else /* !USE_KEYSTORE */ - - uint32_t dest_len = (uint32_t)CFDataGetLength(dest); - if (CFEqual(operation, kAKSKeyOpEncrypt)) { - /* The no encryption case. */ - if (dest_len >= textLength + 8) { - memcpy(CFDataGetMutableBytePtr(dest), source, textLength); - memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8); - CFDataSetLength(dest, textLength + 8); - *actual_class = keyclass; - } else - return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass); - } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { - if (dest_len + 8 >= textLength) { - memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8); - CFDataSetLength(dest, textLength - 8); - } else - return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass); - } - return true; -#endif /* USE_KEYSTORE */ -} - -#if USE_KEYSTORE -bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) { - if (error == NULL) - return false; - - if (*error && CFErrorGetCode(*error) != errSecAuthNeeded) { - // If we already had an error there, just leave it, no access_control specific error is needed here. - return false; - } - - // Create new error instance which adds new access control data appended to existing - CFMutableDictionaryRef user_info; - if (*error) { - CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error); - user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info); - CFRelease(old_user_info); - CFReleaseNull(*error); - } else { - user_info = CFDictionaryCreateMutableForCFTypes(NULL); - } - - if (access_control_data) { - CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded); - CFMutableArrayRef acls; - CFArrayRef old_acls = CFDictionaryGetValue(user_info, key); - if (old_acls) - acls = CFArrayCreateMutableCopy(NULL, 0, old_acls); - else - acls = CFArrayCreateMutableForCFTypes(NULL); - - CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL); - CFArrayAppendValue(acls, pair); - CFRelease(pair); - - CFDictionarySetValue(user_info, key, acls); - CFRelease(key); - CFRelease(acls); - - *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info); - } - else - *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL); - - CFReleaseSafe(user_info); - return false; -} - -static bool merge_der_in_to_data(const void *ed_blob, size_t ed_blob_len, const void *key_blob, size_t key_blob_len, CFMutableDataRef mergedData) -{ - bool ok = false; - CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull); - CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull); - - if (ed_data && key_data) { - CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL); - - CFDataSetLength(mergedData, 0); - CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL); - if (der_data) { - CFDataAppend(mergedData, der_data); - CFRelease(der_data); - ok = CFDataGetLength(mergedData) > 0; - } - CFRelease(result_dict); - } - - CFReleaseSafe(ed_data); - CFReleaseSafe(key_data); - return ok; -} - -bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data) -{ - bool ok = false; - CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1); - CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2); - - if (tmp_ed_data && tmp_key_data && - CFDataGetTypeID() == CFGetTypeID(tmp_ed_data) && - CFDataGetTypeID() == CFGetTypeID(tmp_key_data)) { - *ed_data = CFRetain(tmp_ed_data); - *key_data = CFRetain(tmp_key_data); - ok = true; - } - - return ok; -} - -bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error) -{ - const char *operation_string = ""; - if (CFEqual(operation, kAKSKeyOpDecrypt)) { - operation_string = "decrypt"; - } else if (CFEqual(operation, kAKSKeyOpEncrypt)) { - operation_string = "encrypt"; - } if (CFEqual(operation, kAKSKeyOpDelete)) { - operation_string = "delete"; - } - - if (aks_return == kAKSReturnNoPermission) { - /* Keychain is locked. */ - SecError(errSecInteractionNotAllowed, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."), - aks_return, operation_string, keyclass, keybag); - } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) { - if (aks_return == kAKSReturnBadPassword) { - ACMContextRef acm_context_ref = NULL; - acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data)); - if (acm_context_ref) { - ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext); - ACMContextDelete(acm_context_ref, false); - } - } - - /* Item needed authentication. */ - ks_access_control_needed_error(error, access_control_data, operation); - } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid || aks_return == kAKSReturnDecodeError) { - /* Item can't be decrypted on this device, ever, so drop the item. */ - SecError(errSecDecode, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), - aks_return, operation_string, keyclass, keybag); - - } else if (aks_return == kAKSReturnNotFound) { - return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), aks_return, operation, keyclass, keybag); - } else { - SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"), - aks_return, operation_string, keyclass, keybag); - } - - return false; -} - -bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source, - CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, - SecAccessControlRef access_control, CFErrorRef *error) { - void *params = NULL, *der = NULL; - size_t params_len = 0, der_len = 0; - CFDataRef access_control_data = SecAccessControlCopyData(access_control); - int aks_return = kAKSReturnSuccess; - aks_ref_key_t key_handle = NULL; - - /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ - bool ok = false; - if (!acm_context || !SecAccessControlIsBound(access_control)) { - require_quiet(ok = ks_access_control_needed_error(error, access_control_data, SecAccessControlIsBound(access_control) ? kAKSKeyOpEncrypt : CFSTR("")), out); - } - - aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); - require_noerr_action_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out, - create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); - require_noerr_action_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out, - create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); - size_t key_blob_len; - const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len); - require_action_quiet(key_blob, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to invalid key data, so drop the item."), - aks_return, "encrypt", keyclass, keybag)); - - require_action_quiet(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out, - SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to merge failed, so drop the item."), - aks_return, "encrypt", keyclass, keybag)); - - ok = true; - -out: - if (key_handle) - aks_ref_key_free(&key_handle); - if(params) - free(params); - if(der) - free(der); - CFReleaseSafe(access_control_data); - return ok; -} - -bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest, - CFDataRef acm_context, CFDataRef caller_access_groups, - SecAccessControlRef access_control, CFErrorRef *error) { - void *params = NULL, *der = NULL; - const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; - size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; - CFDataRef access_control_data = SecAccessControlCopyData(access_control); - int aks_return = kAKSReturnSuccess; - - /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ - bool ok = false; - if (!acm_context) { - require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); - } - - aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); - require_noerr_action_quiet(aks_return = aks_ref_key_decrypt(ref_key, params, params_len, CFDataGetBytePtr(encrypted_data), CFDataGetLength(encrypted_data), &der, &der_len), out, - create_cferror_from_aks(aks_return, kAKSKeyOpDecrypt, 0, 0, access_control_data, acm_context, error)); - require_action_quiet(der, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to invalid der data, so drop the item."), - aks_return, "decrypt")); - - CFPropertyListRef decoded_data = NULL; - der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len); - require_action_quiet(decoded_data, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."), - aks_return, "decrypt")); - if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) { - CFDataSetLength(dest, 0); - CFDataAppend(dest, decoded_data); - CFRelease(decoded_data); - } - else { - CFRelease(decoded_data); - require_action_quiet(false, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to wrong data, so drop the item."), - aks_return, "decrypt")); - } - - ok = true; - -out: - if(params) - free(params); - if(der) - free(der); - CFReleaseSafe(access_control_data); - return ok; -} - -bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, - CFDataRef acm_context, CFDataRef caller_access_groups, - SecAccessControlRef access_control, CFErrorRef *error) { - void *params = NULL; - CFDataRef access_control_data = NULL; - int aks_return = kAKSReturnSuccess; - bool ok = false; - - nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true); - - /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ - if (!acm_context) { - require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); - } - - access_control_data = SecAccessControlCopyData(access_control); - const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; - size_t params_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; - aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); - require_noerr_action_quiet(aks_return = aks_ref_key_delete(ref_key, params, params_len), out, - create_cferror_from_aks(aks_return, kAKSKeyOpDelete, 0, 0, access_control_data, acm_context, error)); - - ok = true; - -out: - if(params) - free(params); - CFReleaseSafe(access_control_data); - return ok; -} - -const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error) { - const void* result = NULL; - int aks_return = kAKSReturnSuccess; - require_noerr_action_quiet(aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key), out, - SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (bag: %"PRId32")"), aks_return, "create ref key with blob", keybag)); - result = aks_ref_key_get_external_data(*ref_key, external_data_len); - -out: - return result; -} -#endif - -bool use_hwaes(void) { -#if !TARGET_OS_BRIDGE - static bool use_hwaes; - static dispatch_once_t check_once; - dispatch_once(&check_once, ^{ - use_hwaes = hwaes_key_available(); - if (use_hwaes) { - secinfo("aks", "using hwaes key"); - } else { - secerror("unable to access hwaes key"); - } - }); - return use_hwaes; -#else - return false; -#endif // TARGET_OS_BRIDGE -} - -bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) { -#if USE_KEYSTORE - kern_return_t kernResult; - if (!asData(keybag, error)) return false; - kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle); - if (kernResult) - return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag); - - if (password) { - kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password)); - if (kernResult) { - aks_unload_bag(*handle); - return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed")); - } - } - return true; -#else /* !USE_KEYSTORE */ - *handle = KEYBAG_NONE; - return true; -#endif /* USE_KEYSTORE */ -} - -bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) { -#if USE_KEYSTORE - IOReturn kernResult = aks_unload_bag(keybag); - if (kernResult) { - return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed")); - } -#endif /* USE_KEYSTORE */ - return true; -} - diff --git a/OSX/sec/securityd/SecKeybagSupport.h b/OSX/sec/securityd/SecKeybagSupport.h deleted file mode 100644 index b2b6aa28..00000000 --- a/OSX/sec/securityd/SecKeybagSupport.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecKeybagSupport.h - The thing that does the stuff with the gibli. - */ - -#ifndef _SECURITYD_SECKEYBAGSUPPORT_H_ -#define _SECURITYD_SECKEYBAGSUPPORT_H_ - -#include -#include "utilities/SecAKSWrappers.h" -#include -#include - -#ifndef USE_KEYSTORE -// Use keystore (real or mock) on all platforms, except bridge -#define USE_KEYSTORE !TARGET_OS_BRIDGE -#endif - -#if __has_include() -#include -#endif - -#if USE_KEYSTORE -#include -#endif /* USE_KEYSTORE */ - -__BEGIN_DECLS - - -/* KEYBAG_NONE is private to security and have special meaning. - They should not collide with AppleKeyStore constants, but are only referenced - in here. - */ -#define KEYBAG_NONE (-1) /* Set q_keybag to KEYBAG_NONE to obtain cleartext data. */ -#define KEYBAG_DEVICE (g_keychain_keybag) /* actual keybag used to encrypt items */ -extern keybag_handle_t g_keychain_keybag; - -bool use_hwaes(void); - -bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, - keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, - CFMutableDataRef dest, CFErrorRef *error); -#if USE_KEYSTORE -bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source, - CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, - SecAccessControlRef access_control, CFErrorRef *error); -bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest, - CFDataRef acm_context, CFDataRef caller_access_groups, - SecAccessControlRef access_control, CFErrorRef *error); -bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, - CFDataRef acm_context, CFDataRef caller_access_groups, - SecAccessControlRef access_control, CFErrorRef *error); -const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, - aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error); -bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data); - -bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation); -bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error); -#endif -bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error); -bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error); - -__END_DECLS - -#endif /* _SECURITYD_SECKEYBAGSUPPORT_H_ */ diff --git a/OSX/sec/securityd/SecLogSettingsServer.h b/OSX/sec/securityd/SecLogSettingsServer.h deleted file mode 100644 index 21e886c4..00000000 --- a/OSX/sec/securityd/SecLogSettingsServer.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// SecLogSettingsServer.h -// sec -// -// - -#ifndef _SECURITY_SECLOGSETTINGSSERVER_H_ -#define _SECURITY_SECLOGSETTINGSSERVER_H_ - -#include - -__BEGIN_DECLS - -CFPropertyListRef SecCopyLogSettings_Server(CFErrorRef* error); -bool SecSetXPCLogSettings_Server(CFTypeRef type, CFErrorRef* error); -bool SecSetCircleLogSettings_Server(CFTypeRef type, CFErrorRef* error); - -__END_DECLS - -#endif diff --git a/OSX/sec/securityd/SecLogSettingsServer.m b/OSX/sec/securityd/SecLogSettingsServer.m deleted file mode 100644 index fd15022f..00000000 --- a/OSX/sec/securityd/SecLogSettingsServer.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// SecLogSettingsServer.c -// sec -// -// - -#include -#include "keychain/SecureObjectSync/SOSAccountPriv.h" -#include -#include -#include "keychain/SecureObjectSync/SOSTransportCircle.h" -#include -#include -#include - -CFPropertyListRef -SecCopyLogSettings_Server(CFErrorRef* error) -{ - return CopyCurrentScopePlist(); -} - -bool -SecSetXPCLogSettings_Server(CFTypeRef type, CFErrorRef* error) -{ - bool success = false; - if (isString(type)) { - ApplyScopeListForID(type, kScopeIDXPC); - success = true; - } else if (isDictionary(type)) { - ApplyScopeDictionaryForID(type, kScopeIDXPC); - success = true; - } else { - success = SecError(errSecParam, error, CFSTR("Unsupported CFType")); - } - - return success; -} - -bool -SecSetCircleLogSettings_Server(CFTypeRef type, CFErrorRef* error) -{ - bool success = false; - SOSAccount* account = (__bridge SOSAccount*)SOSKeychainAccountGetSharedAccount(); - if (account) { - success = SOSAccountPostDebugScope(account, type, error); - } - return success; -} - diff --git a/OSX/sec/securityd/SecOCSPCache.c b/OSX/sec/securityd/SecOCSPCache.c deleted file mode 100644 index 5c221b71..00000000 --- a/OSX/sec/securityd/SecOCSPCache.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecOCSPCache.c - securityd - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utilities/SecCFWrappers.h" -#include "utilities/SecDb.h" -#include "utilities/SecFileLocations.h" -#include "utilities/iOSforOSX.h" - -/* Note that lastUsed is actually time of insert because we don't - refresh lastUsed on each SELECT. */ - -#define flushSQL CFSTR("DELETE FROM responses") -#define expireSQL CFSTR("DELETE FROM responses WHERE expires? AND responseId=(SELECT responseId FROM ocsp WHERE " \ - "issuerNameHash=? AND issuerPubKeyHash=? AND serialNum=? AND hashAlgorithm=?)" \ - " ORDER BY expires DESC") - -#define kSecOCSPCacheFileName CFSTR("ocspcache.sqlite3") - - -// MARK; - -// MARK: SecOCSPCacheDb - -static SecDbRef SecOCSPCacheDbCreate(CFStringRef path) { - return SecDbCreate(path, 0600, true, true, true, true, 1, - ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { - __block bool ok = true; - - CFErrorRef localError = NULL; - if (!SecDbWithSQL(dbconn, selectHashAlgorithmSQL /* expireSQL */, &localError, NULL) && CFErrorGetCode(localError) == SQLITE_ERROR) { - /* SecDbWithSQL returns SQLITE_ERROR if the table we are preparing the above statement for doesn't exist. */ - ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - ok &= SecDbExec(dbconn, - CFSTR("CREATE TABLE ocsp(" - "issuerNameHash BLOB NOT NULL," - "issuerPubKeyHash BLOB NOT NULL," - "serialNum BLOB NOT NULL," - "hashAlgorithm BLOB NOT NULL," - "responseId INTEGER NOT NULL" - ");" - "CREATE INDEX iResponseId ON ocsp(responseId);" - "CREATE INDEX iserialNum ON ocsp(serialNum);" - "CREATE INDEX iSNumDAlg ON ocsp(serialNum,hashAlgorithm);" - "CREATE TABLE responses(" - "responseId INTEGER PRIMARY KEY," - "ocspResponse BLOB NOT NULL," - "responderURI BLOB," - "expires DOUBLE NOT NULL," - "lastUsed DOUBLE NOT NULL" - ");" - "CREATE INDEX iexpires ON responses(expires);" - "CREATE TRIGGER tocspdel BEFORE DELETE ON responses FOR EACH ROW " - "BEGIN " - "DELETE FROM ocsp WHERE responseId=OLD.responseId;" - " END;"), error); - *commit = ok; - }); - } - CFReleaseSafe(localError); - if (!ok) { - secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); - CFIndex errCode = errSecInternalComponent; - if (error && *error) { - errCode = CFErrorGetCode(*error); - } - TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, - didCreate ? TAOperationCreate : TAOperationOpen, - TAFatalError, errCode); - } - return ok; - }); -} - -// MARK; - -// MARK: SecOCSPCache - -typedef struct __SecOCSPCache *SecOCSPCacheRef; -struct __SecOCSPCache { - SecDbRef db; -}; - -static dispatch_once_t kSecOCSPCacheOnce; -static SecOCSPCacheRef kSecOCSPCache = NULL; - -static SecOCSPCacheRef SecOCSPCacheCreate(CFStringRef db_name) { - SecOCSPCacheRef this; - - require(this = (SecOCSPCacheRef)malloc(sizeof(struct __SecOCSPCache)), errOut); - require(this->db = SecOCSPCacheDbCreate(db_name), errOut); - - return this; - -errOut: - if (this) { - CFReleaseSafe(this->db); - free(this); - } - - return NULL; -} - -static CFStringRef SecOCSPCacheCopyPath(void) { - CFStringRef ocspRelPath = kSecOCSPCacheFileName; -#if TARGET_OS_IPHONE - CFURLRef ocspURL = SecCopyURLForFileInKeychainDirectory(ocspRelPath); - if (!ocspURL) { - ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); - } -#else - /* macOS caches should be in user cache dir */ - CFURLRef ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); -#endif - CFStringRef ocspPath = NULL; - if (ocspURL) { - ocspPath = CFURLCopyFileSystemPath(ocspURL, kCFURLPOSIXPathStyle); - CFRelease(ocspURL); - } - return ocspPath; -} - -static void SecOCSPCacheWith(void(^cacheJob)(SecOCSPCacheRef cache)) { - dispatch_once(&kSecOCSPCacheOnce, ^{ - CFStringRef dbPath = SecOCSPCacheCopyPath(); - if (dbPath) { - kSecOCSPCache = SecOCSPCacheCreate(dbPath); - CFRelease(dbPath); - } - }); - // Do pre job run work here (cancel idle timers etc.) - cacheJob(kSecOCSPCache); - // Do post job run work here (gc timer, etc.) -} - -static bool _SecOCSPCacheExpireWithTransaction(SecDbConnectionRef dbconn, CFAbsoluteTime now, CFErrorRef *error) { - //if (now > nextExpireTime) - { - return SecDbWithSQL(dbconn, expireSQL, error, ^bool(sqlite3_stmt *expire) { - return SecDbBindDouble(expire, 1, now, error) && - SecDbStep(dbconn, expire, error, NULL); - }); - // TODO: Write now + expireDelay to nextExpireTime; - // currently we try to expire entries on each cache write - } -} - -/* Instance implementation. */ - -static void _SecOCSPCacheReplaceResponse(SecOCSPCacheRef this, - SecOCSPResponseRef oldResponse, SecOCSPResponseRef ocspResponse, - CFURLRef localResponderURI, CFAbsoluteTime verifyTime) { - secdebug("ocspcache", "adding response from %@", localResponderURI); - /* responses.ocspResponse */ - - // TODO: Update a latestProducedAt value using date in new entry, to ensure forward movement of time. - // Set "now" to the new producedAt we are receiving here if localTime is before this date. - // In addition whenever we run though here, check to see if "now" is more than past - // the nextCacheExpireDate and expire the cache if it is. - CFDataRef responseData = SecOCSPResponseGetData(ocspResponse); - __block CFErrorRef localError = NULL; - __block bool ok = true; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { - ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - __block sqlite3_int64 responseId; - if (oldResponse && (responseId = SecOCSPResponseGetID(oldResponse)) >= 0) { - ok &= SecDbWithSQL(dbconn, deleteResponseSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { - ok &= SecDbBindInt64(deleteResponse, 1, responseId, &localError); - /* Execute the delete statement. */ - ok &= SecDbStep(dbconn, deleteResponse, &localError, NULL); - return ok; - }); - } - - ok &= SecDbWithSQL(dbconn, insertResponseSQL, &localError, ^bool(sqlite3_stmt *insertResponse) { - ok &= SecDbBindBlob(insertResponse, 1, - CFDataGetBytePtr(responseData), - CFDataGetLength(responseData), - SQLITE_TRANSIENT, &localError); - - /* responses.responderURI */ - if (ok) { - CFDataRef uriData = NULL; - if (localResponderURI) { - uriData = CFURLCreateData(kCFAllocatorDefault, localResponderURI, - kCFStringEncodingUTF8, false); - } - if (uriData) { - ok = SecDbBindBlob(insertResponse, 2, - CFDataGetBytePtr(uriData), - CFDataGetLength(uriData), - SQLITE_TRANSIENT, &localError); - CFRelease(uriData); - } - } - /* responses.expires */ - ok &= SecDbBindDouble(insertResponse, 3, - SecOCSPResponseGetExpirationTime(ocspResponse), - &localError); - /* responses.lastUsed */ - ok &= SecDbBindDouble(insertResponse, 4, - verifyTime, - &localError); - - /* Execute the insert statement. */ - ok &= SecDbStep(dbconn, insertResponse, &localError, NULL); - - responseId = sqlite3_last_insert_rowid(SecDbHandle(dbconn)); - return ok; - }); - - /* Now add a link record for every singleResponse in the ocspResponse. */ - ok &= SecDbWithSQL(dbconn, insertLinkSQL, &localError, ^bool(sqlite3_stmt *insertLink) { - SecAsn1OCSPSingleResponse **responses; - for (responses = ocspResponse->responseData.responses; - *responses; ++responses) { - SecAsn1OCSPSingleResponse *resp = *responses; - SecAsn1OCSPCertID *certId = &resp->certID; - ok &= SecDbBindBlob(insertLink, 1, - certId->algId.algorithm.Data, - certId->algId.algorithm.Length, - SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(insertLink, 2, - certId->issuerNameHash.Data, - certId->issuerNameHash.Length, - SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(insertLink, 3, - certId->issuerPubKeyHash.Data, - certId->issuerPubKeyHash.Length, - SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(insertLink, 4, - certId->serialNumber.Data, - certId->serialNumber.Length, - SQLITE_TRANSIENT, &localError); - ok &= SecDbBindInt64(insertLink, 5, responseId, &localError); - - /* Execute the insert statement. */ - ok &= SecDbStep(dbconn, insertLink, &localError, NULL); - ok &= SecDbReset(insertLink, &localError); - } - return ok; - }); - - // Remove expired entries here. - // TODO: Consider only doing this once per 24 hours or something. - ok &= _SecOCSPCacheExpireWithTransaction(dbconn, verifyTime, &localError); - if (!ok) - *commit = false; - }); - }); - if (!ok) { - secerror("_SecOCSPCacheAddResponse failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - CFReleaseNull(localError); - } - CFReleaseSafe(localError); -} - -static SecOCSPResponseRef _SecOCSPCacheCopyMatching(SecOCSPCacheRef this, - SecOCSPRequestRef request, CFURLRef responderURI, CFAbsoluteTime minInsertTime) { - const DERItem *publicKey; - CFDataRef issuer = NULL; - CFDataRef serial = NULL; - __block SecOCSPResponseRef response = NULL; - __block CFErrorRef localError = NULL; - __block bool ok = true; - - require(publicKey = SecCertificateGetPublicKeyData(request->issuer), errOut); - require(issuer = SecCertificateCopyIssuerSequence(request->certificate), errOut); - require(serial = SecCertificateCopySerialNumberData(request->certificate, NULL), errOut); - - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { - ok &= SecDbWithSQL(dbconn, selectHashAlgorithmSQL, &localError, ^bool(sqlite3_stmt *selectHash) { - ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); - ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stopHash) { - SecAsn1Oid algorithm; - algorithm.Data = (uint8_t *)sqlite3_column_blob(selectHash, 0); - algorithm.Length = sqlite3_column_bytes(selectHash, 0); - - /* Calculate the issuerKey and issuerName digests using the returned - hashAlgorithm. */ - CFDataRef issuerNameHash = SecDigestCreate(kCFAllocatorDefault, - &algorithm, NULL, CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); - CFDataRef issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, - &algorithm, NULL, publicKey->data, publicKey->length); - - if (issuerNameHash && issuerPubKeyHash && ok) ok &= SecDbWithSQL(dbconn, selectResponseSQL, &localError, ^bool(sqlite3_stmt *selectResponse) { - /* Now we have the serial, algorithm, issuerNameHash and - issuerPubKeyHash so let's lookup the db entry. */ - ok &= SecDbBindDouble(selectResponse, 1, minInsertTime, &localError); - ok &= SecDbBindBlob(selectResponse, 2, CFDataGetBytePtr(issuerNameHash), - CFDataGetLength(issuerNameHash), SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(selectResponse, 3, CFDataGetBytePtr(issuerPubKeyHash), - CFDataGetLength(issuerPubKeyHash), SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(selectResponse, 4, CFDataGetBytePtr(serial), - CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); - ok &= SecDbBindBlob(selectResponse, 5, algorithm.Data, - algorithm.Length, SQLITE_TRANSIENT, &localError); - ok &= SecDbStep(dbconn, selectResponse, &localError, ^(bool *stopResponse) { - /* Found an entry! */ - secdebug("ocspcache", "found cached response"); - CFDataRef resp = CFDataCreate(kCFAllocatorDefault, - sqlite3_column_blob(selectResponse, 0), - sqlite3_column_bytes(selectResponse, 0)); - sqlite3_int64 responseID = sqlite3_column_int64(selectResponse, 1); - if (resp) { - SecOCSPResponseRef new_response = SecOCSPResponseCreateWithID(resp, responseID); - if (response) { - if (SecOCSPResponseProducedAt(response) < SecOCSPResponseProducedAt(new_response)) { - SecOCSPResponseFinalize(response); - response = new_response; - } else { - SecOCSPResponseFinalize(new_response); - } - } else { - response = new_response; - } - CFRelease(resp); - } - }); - return ok; - }); - - CFReleaseSafe(issuerNameHash); - CFReleaseSafe(issuerPubKeyHash); - }); - return ok; - }); - }); - -errOut: - CFReleaseSafe(serial); - CFReleaseSafe(issuer); - - if (!ok || localError) { - secerror("ocsp cache lookup failed: %@", localError); - if (response) { - SecOCSPResponseFinalize(response); - response = NULL; - } - TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - CFReleaseSafe(localError); - - secdebug("ocspcache", "returning %s", (response ? "cached response" : "NULL")); - - return response; -} - -static bool _SecOCSPCacheFlush(SecOCSPCacheRef cache, CFErrorRef *error) { - __block CFErrorRef localError = NULL; - __block bool ok = true; - - ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) { - ok &= SecDbExec(dbconn, flushSQL, &localError); - }); - if (!ok || localError) { - TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - - return ok; -} - - -/* Public API */ - -void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, SecOCSPResponseRef response, - CFURLRef localResponderURI, CFAbsoluteTime verifyTime) { - SecOCSPCacheWith(^(SecOCSPCacheRef cache) { - _SecOCSPCacheReplaceResponse(cache, old_response, response, localResponderURI, verifyTime); - }); -} - -SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request, - CFURLRef localResponderURI /* may be NULL */) { - __block SecOCSPResponseRef response = NULL; - SecOCSPCacheWith(^(SecOCSPCacheRef cache) { - response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, 0.0); - }); - return response; -} - -SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request, - CFURLRef localResponderURI, CFAbsoluteTime minInsertTime) { - __block SecOCSPResponseRef response = NULL; - SecOCSPCacheWith(^(SecOCSPCacheRef cache) { - response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, minInsertTime); - }); - return response; -} - -bool SecOCSPCacheFlush(CFErrorRef *error) { - __block bool result = false; - SecOCSPCacheWith(^(SecOCSPCacheRef cache) { - result = _SecOCSPCacheFlush(cache, error); - }); - return result; -} diff --git a/OSX/sec/securityd/SecOCSPCache.h b/OSX/sec/securityd/SecOCSPCache.h deleted file mode 100644 index 39a9744c..00000000 --- a/OSX/sec/securityd/SecOCSPCache.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/*! - @header SecOCSPCache - The functions provided in SecOCSPCache.h provide an interface to - an OCSP caching module. -*/ - -#ifndef _SECURITY_SECOCSPCACHE_H_ -#define _SECURITY_SECOCSPCACHE_H_ - -#include "securityd/SecOCSPRequest.h" -#include "securityd/SecOCSPResponse.h" -#include - -__BEGIN_DECLS - - -void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, - SecOCSPResponseRef response, CFURLRef localResponderURI, CFAbsoluteTime verifyTime); - -SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request, - CFURLRef localResponderURI /* may be NULL */); - -SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request, - CFURLRef localResponderURI, CFAbsoluteTime minInsertTime); - -bool SecOCSPCacheFlush(CFErrorRef *error); - -__END_DECLS - -#endif /* _SECURITY_SECOCSPCACHE_H_ */ - -#if 0 -/* -Experation policy assumptions: -- We never check revocation status of anchors, whether they be system anchors, - passed in anchors or anchors hardcoded in a policy. -- Revocation information is cached for positive reponses for a limited time. -- Revocation information can be cached for negative reponses for an unlimited time. -- Revocation information need never be kept around after the certificate has expired (unless we still check after the cert has expired like we were talking about for EERI). -- Revocation information records that are used and still valid should be kept longer. -- We can set an upper limit in number of records (or certificates) in the cache. -- We can set an upper limit on total space consumed by the cache. -Questions: -- Remember bad server responses too? some ocsp responders required signed requests which we don't support, so we could consider caching the 6 (Not Authorized or something) response. - -Data needed per type of revocation record to implement this policy. - -Caching policy: -- Deleting cache should not be user option. -- Cache should surrvive backups. -- Negative caching as long as possible. - -CRL certificate stati: -unspecified, keyCompromise, cACompromise, -affiliationChanged, superseded, cessationOfOperation, -certificateHold, removeFromCRL, privilegeWithdrawn, -aACompromise, the special value UNREVOKED, or the special -value UNDETERMINED. This variable is initialized to the -special value UNREVOKED. - -CRL Timestamp values: -- thisUpdate -- nextUpdate (optional but not really 5280 says CAs must provide it even though ASN.1 is optional) -(no producedAt in CRLs, that's what thisUpdate is by definition it seems). - - -OCSP Timestamp values: - thisUpdate = May 1, 2005 01:00:00 GMT - nextUpdate = May 3, 2005 01:00:00 GMT (optional abscence means update available any time) - productedAt = May 1, 2005 01:00:00 GMT - -PER CERTIFICATE RETURN in INFO - -Revocation object used: OCSP Response, mapping from -reasons-> (CRL + most current delta CRL), Error Object (with status code). - -- good - -- revoked - -- unknown - -other exceptions (unsigned responses): - -- malformedRequest - -- internalError - -- tryLater - -- sigRequired - -- unauthorized (5019 The response "unauthorized" is returned in cases where the client - is not authorized to make this query to this server or the server - is not capable of responding authoritatively. (Expired certs might get this answer too)) - - -CRL signer chain rules: -1) Must use same anchor as cert itself. -This implies that we can only cache the validity of a leaf or intermediate certificate for CRL checking based on the mapping: -(certificate, path anchor, use_deltas) -> Revocation_status (unspecified, keyCompromise, cACompromise, -affiliationChanged, superseded, cessationOfOperation,certificateHold, removeFromCRL, privilegeWithdrawn,aACompromise, UNREVOKED, UNDETERMINED). - -OCSP signer chain rules: -(Wikipedia confirmed in rfc): The key that signs a response need not be the same key that signed the certificate. The certificate's issuer may delegate another authority to be the OCSP responder. In this case, the responder's certificate (the one that is used to sign the response) must be issued by the issuer of the certificate in question, and must include a certain extension that marks it as an OCSP signing authority (more precisely, an extended key usage extension with the OID {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) keyPurpose(3) ocspSigning(9)}) - -rfc text of the wikipedia: Therefore, a certificate's issuer MUST either sign the OCSP - responses itself or it MUST explicitly designate this authority to - another entity. OCSP signing delegation SHALL be designated by the - inclusion of id-kp-OCSPSigning in an extendedKeyUsage certificate - extension included in the OCSP response signer's certificate. This - certificate MUST be issued directly by the CA that issued the - certificate in question. - -rfc: If ocsp signing cert has id-pkix-ocsp-nocheck extension we don't check it's revocation status. - -(certificate, direct issuer certificate) -> Revocation_status good (UNREVOKED) revoked revocationTime, CRLReason (unspecified, keyCompromise, cACompromise,affiliationChanged, superseded, cessationOfOperation,certificateHold, removeFromCRL, privilegeWithdrawn,aACompromise) unknown (UNDETERMINED). - -ocsp CertID ::= SEQUENCE { - hashAlgorithm AlgorithmIdentifier, - issuerNameHash OCTET STRING, -- Hash of Issuer's DN - issuerKeyHash OCTET STRING, -- Hash of Issuers public key - serialNumber CertificateSerialNumber } -) - -In order to accomadate the responder using a different hashAlgorithm than we used in the request we need to recalc these from the cert itself. - -If all we have is a list of ocspresponses without knowing where they came from, we have to calculate the hashes of our issuerName and issuerKey for each hashAlgorithm we have cached ocsp responses for (optionally after limiting our candidates to those with matching serialNumbers first). - -SELECT from ocsp_cache hashAlgorithm WHERE serialNumber = - -for hix = 0 hix < hashAlgorithms.count - ALG(hix).id = hashAlgorithms(hix) - -SELECT from ocsp_cache response WHERE serialNumber = hashAlgorithm = ALG(hix).id issuerNameHash = ALG(hix).hash(issuer) issuerKeyHash = ALG(hix).hash(key) - - - - - - -Notes for Matt: -- ttl in amfi cache (to force recheck when ocsp response is invalid)? -- Periodic check before launch to remove in band waiting for ocsp response? - -Notes on Nonces in ocsp request and responses. Only ask for nonce if we think server supports it (no way to know today). Fall back on time based validity checking if reponse has no nonce, even if we asked for one - -Note on CRL checking and experation and retries of OCSP checking. -Clients MAY attempt to retrieve the CRL if no - OCSPResponse is received from the responder after a locally - configured timeout and number of retries.. - - - -CRL/OCSP cache design idea: - -revocation status table: - -rowid certhash issuer-rowid lastUsed thisUpdate producedAt nextUpdate revocationTime revocationStatus - -cacheAddOCSP(path, index_of_cert_resp_is_for, ocspResp) -cacheAddCRLStatus(path, index_of_cert_in_path, nextUpdate, revocationTime, revocationStatus) -(revocationTime, revocationStatus) = cacheLookupStatus(path, ix) - -Return a list of parent certificate hashes for the current leaf. If a result is returned, we have a candiate path leading up to an anchor, for which we already trust the signature in the chain and revocation information has been checked. - -CFArrayRef cacheSuggestParentsHashesFor(cert) - -for crl based status root must match root of path. For ocsp status issuer must match issuer of leaf in path - -presence in the cache means cert chain leading to an anchor is valid, and signed properly and trusted by the ocsp or crl policy, revocation status for cert is valid until the time indicated by nextUpdate. Cert chain itself may or may not be valid but that's checked by the policy engine. - -If a chain isn't properly signed or fails to satisfy the crl policy, it should not be in the cache. - -ocsp cache - -rowid ocspResponse (responder) lastUsed nextUpdate - -hashAlgorithm->(issuerNameHash,issuerKeyHash,serialNumber)->response - - -crl cache () - -crlDistributionPoint (reasons) crl thisUpdate nextUpdate isDelta - - -crlEntry cache table -(certHash anchorHash) crlIssuer revocationStatus revocationTime expires lastUsed -crlTable -(crlIssuer anchorHash distributionPointURL?) crl sigVerified expires -ocspEntry cache table -(certHash parentHash ocspReponderID) hashAlg revocationStatus revocationTime expires lastUsed -ocspTable -((hashAlg, pubKeyHash, issuerHash, serialNum) anchorHash) ocspResponse sigVerified expires - -or -cert cache table -(certHash parentHash anchorHash) crlEntryID ocspID - -crlEntry cache table -(crlEntryID anchorHash) crlIssuer revocationStatus revocationTime - -crlIssuerTable -(crlIssuer anchorHash) crl sigVerified - -ocsp table -(ocspID) ocspResponse - - -but so does caching the raw response as a link to a blob table containing crls -and ocsp-responses -But also cache the revocationStatus for a (cert,parent) or (cert,anchor) via -a link to a cached ocspResponse or revocationStatus and revocationTime entry from crl -*/ - -#endif diff --git a/OSX/sec/securityd/SecOCSPRequest.c b/OSX/sec/securityd/SecOCSPRequest.c deleted file mode 100644 index d7081b83..00000000 --- a/OSX/sec/securityd/SecOCSPRequest.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2008-2009,2012,2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecOCSPRequest.c - Trust policies dealing with certificate revocation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecInternal.h" - -/* - OCSPRequest ::= SEQUENCE { - tbsRequest TBSRequest, - optionalSignature [0] EXPLICIT Signature OPTIONAL } - - TBSRequest ::= SEQUENCE { - version [0] EXPLICIT Version DEFAULT v1, - requestorName [1] EXPLICIT GeneralName OPTIONAL, - requestList SEQUENCE OF Request, - requestExtensions [2] EXPLICIT Extensions OPTIONAL } - - Signature ::= SEQUENCE { - signatureAlgorithm AlgorithmIdentifier, - signature BIT STRING, - certs [0] EXPLICIT SEQUENCE OF Certificate - OPTIONAL} - - Version ::= INTEGER { v1(0) } - - Request ::= SEQUENCE { - reqCert CertID, - singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } - - CertID ::= SEQUENCE { - hashAlgorithm AlgorithmIdentifier, - issuerNameHash OCTET STRING, -- Hash of Issuer's DN - issuerKeyHash OCTET STRING, -- Hash of Issuers public key - serialNumber CertificateSerialNumber } - */ -static CFDataRef _SecOCSPRequestCopyDEREncoding(SecOCSPRequestRef this) { - /* fields obtained from issuer */ - SecAsn1OCSPSignedRequest signedReq = {}; - SecAsn1OCSPTbsRequest *tbs = &signedReq.tbsRequest; - SecAsn1OCSPRequest singleReq = {}; - SecAsn1OCSPCertID *certId = &singleReq.reqCert; - SecAsn1OCSPRequest *reqArray[2] = { &singleReq, NULL }; - uint8_t version = 0; - SecAsn1Item vers = {1, &version}; - CFDataRef der = NULL; - SecAsn1CoderRef coder = NULL; - CFDataRef issuerNameDigest; - CFDataRef serial; - CFDataRef issuerPubKeyDigest; - - - /* algId refers to the hash we'll perform in issuer name and key */ - certId->algId.algorithm = CSSMOID_SHA1; - /* preencoded DER NULL */ - static uint8_t nullParam[2] = {5, 0}; - certId->algId.parameters.Data = nullParam; - certId->algId.parameters.Length = sizeof(nullParam); - - /* @@@ Change this from using SecCertificateCopyIssuerSHA1Digest() / - SecCertificateCopyPublicKeySHA1Digest() to - SecCertificateCopyIssuerSequence() / SecCertificateGetPublicKeyData() - and call SecDigestCreate here instead. */ - issuerNameDigest = SecCertificateCopyIssuerSHA1Digest(this->certificate); - issuerPubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(this->issuer); - serial = SecCertificateCopySerialNumberData(this->certificate, NULL); - - /* build the CertID from those components */ - certId->issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH; - certId->issuerNameHash.Data = (uint8_t *)CFDataGetBytePtr(issuerNameDigest); - certId->issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH; - certId->issuerPubKeyHash.Data = (uint8_t *)CFDataGetBytePtr(issuerPubKeyDigest); - certId->serialNumber.Length = CFDataGetLength(serial); - certId->serialNumber.Data = (uint8_t *)CFDataGetBytePtr(serial); - - /* Build top level request with one entry in requestList, no signature, - and no optional extensions. */ - tbs->version = &vers; - tbs->requestList = reqArray; - - /* Encode the request. */ - require_noerr(SecAsn1CoderCreate(&coder), errOut); - SecAsn1Item encoded; - require_noerr(SecAsn1EncodeItem(coder, &signedReq, - kSecAsn1OCSPSignedRequestTemplate, &encoded), errOut); - der = CFDataCreate(kCFAllocatorDefault, encoded.Data, - encoded.Length); - -errOut: - if (coder) - SecAsn1CoderRelease(coder); - CFReleaseSafe(issuerNameDigest); - CFReleaseSafe(serial); - CFReleaseSafe(issuerPubKeyDigest); - - return der; -} - -SecOCSPRequestRef SecOCSPRequestCreate(SecCertificateRef certificate, - SecCertificateRef issuer) { - SecOCSPRequestRef this; - require(this = (SecOCSPRequestRef)calloc(1, sizeof(struct __SecOCSPRequest)), - errOut); - this->certificate = certificate; - this->issuer = issuer; - - return this; -errOut: - if (this) { - SecOCSPRequestFinalize(this); - } - return NULL; -} - -CFDataRef SecOCSPRequestGetDER(SecOCSPRequestRef this) { - if (!this) { return NULL; } - CFDataRef der = this->der; - if (!der) { - this->der = der = _SecOCSPRequestCopyDEREncoding(this); - } - return der; -} - -void SecOCSPRequestFinalize(SecOCSPRequestRef this) { - CFReleaseSafe(this->der); - free(this); -} - diff --git a/OSX/sec/securityd/SecOCSPRequest.h b/OSX/sec/securityd/SecOCSPRequest.h deleted file mode 100644 index 8ab1e6b1..00000000 --- a/OSX/sec/securityd/SecOCSPRequest.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2009,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecOCSPRequest - The functions and data types in SecOCSPRequest implement ocsp request - creation. -*/ - -#ifndef _SECURITY_SECOCSPREQUEST_H_ -#define _SECURITY_SECOCSPREQUEST_H_ - -#include -#include - -__BEGIN_DECLS - -/*! - @typedef SecOCSPRequestRef - @abstract Object used for ocsp response decoding. -*/ -typedef struct __SecOCSPRequest *SecOCSPRequestRef; - -struct __SecOCSPRequest { - SecCertificateRef certificate; // Nonretained - SecCertificateRef issuer; // Nonretained - CFDataRef der; -}; - -/*! - @function SecOCSPRequestCreate - @abstract Returns a SecOCSPRequestRef from a BER encoded ocsp response. - @param certificate The certificate for which we want a OCSP request created. - @param issuer The parent of certificate. - @result A SecOCSPRequestRef. -*/ -SecOCSPRequestRef SecOCSPRequestCreate(SecCertificateRef certificate, - SecCertificateRef issuer); - -/*! - @function SecOCSPRequestCopyDER - @abstract Returns a DER encoded ocsp request. - @param ocspRequest A SecOCSPRequestRef. - @result DER encoded ocsp request. -*/ -CFDataRef SecOCSPRequestGetDER(SecOCSPRequestRef ocspRequest); - -/*! - @function SecOCSPRequestFinalize - @abstract Frees a SecOCSPRequestRef. - @param ocspRequest A SecOCSPRequestRef. - @note The passed in SecOCSPRequestRef is deallocated -*/ -void SecOCSPRequestFinalize(SecOCSPRequestRef ocspRequest); - -__END_DECLS - -#endif /* !_SECURITY_SECOCSPREQUEST_H_ */ diff --git a/OSX/sec/securityd/SecOCSPResponse.c b/OSX/sec/securityd/SecOCSPResponse.c deleted file mode 100644 index 2a38dfab..00000000 --- a/OSX/sec/securityd/SecOCSPResponse.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (c) 2008-2009,2012-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecOCSPResponse.c - Wrapper to decode ocsp responses. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecInternal.h" -#include -#include - - -#define ocspdErrorLog(args, ...) secerror(args, ## __VA_ARGS__) -#define ocspdHttpDebug(args...) secdebug("ocspdHttp", ## args) -#define ocspdDebug(args...) secdebug("ocsp", ## args) - - -/* - OCSPResponse ::= SEQUENCE { - responseStatus OCSPResponseStatus, - responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } - - OCSPResponseStatus ::= ENUMERATED { - successful (0), --Response has valid confirmations - malformedRequest (1), --Illegal confirmation request - internalError (2), --Internal error in issuer - tryLater (3), --Try again later - --(4) is not used - sigRequired (5), --Must sign the request - unauthorized (6) --Request unauthorized - } - - ResponseBytes ::= SEQUENCE { - responseType OBJECT IDENTIFIER, - response OCTET STRING } - - id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } - id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } - - The value for response SHALL be the DER encoding of - BasicOCSPResponse. - - BasicOCSPResponse ::= SEQUENCE { - tbsResponseData ResponseData, - signatureAlgorithm AlgorithmIdentifier, - signature BIT STRING, - certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } - - The value for signature SHALL be computed on the hash of the DER - encoding ResponseData. - - ResponseData ::= SEQUENCE { - version [0] EXPLICIT Version DEFAULT v1, - responderID ResponderID, - producedAt GeneralizedTime, - responses SEQUENCE OF SingleResponse, - responseExtensions [1] EXPLICIT Extensions OPTIONAL } - - ResponderID ::= CHOICE { - byName [1] Name, - byKey [2] KeyHash } - - KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key - (excluding the tag and length fields) - - SingleResponse ::= SEQUENCE { - certID CertID, - certStatus CertStatus, - thisUpdate GeneralizedTime, - nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, - singleExtensions [1] EXPLICIT Extensions OPTIONAL } - - CertStatus ::= CHOICE { - good [0] IMPLICIT NULL, - revoked [1] IMPLICIT RevokedInfo, - unknown [2] IMPLICIT UnknownInfo } - - RevokedInfo ::= SEQUENCE { - revocationTime GeneralizedTime, - revocationReason [0] EXPLICIT CRLReason OPTIONAL } - - UnknownInfo ::= NULL -- this can be replaced with an enumeration -*/ - -static CFAbsoluteTime genTimeToCFAbsTime(const SecAsn1Item *datetime) -{ - return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME, - datetime->Data, datetime->Length); -} - -void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this) { - CFReleaseSafe(this->scts); - free(this); -} - -static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate( - SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) { - assert(resp != NULL); - SecOCSPSingleResponseRef this; - require(this = (SecOCSPSingleResponseRef) - calloc(1, sizeof(struct __SecOCSPSingleResponse)), errOut); - this->certStatus = CS_NotParsed; - this->thisUpdate = NULL_TIME; - this->nextUpdate = NULL_TIME; - this->revokedTime = NULL_TIME; - this->crlReason = kSecRevocationReasonUndetermined; - this->scts = NULL; - - if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) { - ocspdErrorLog("OCSPSingleResponse: bad certStatus"); - goto errOut; - } - this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK); - if (this->certStatus == CS_Revoked) { - /* Decode further to get SecAsn1OCSPRevokedInfo */ - SecAsn1OCSPCertStatus certStatus; - memset(&certStatus, 0, sizeof(certStatus)); - if (SecAsn1DecodeData(coder, &resp->certStatus, - kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) { - ocspdErrorLog("OCSPSingleResponse: err decoding certStatus"); - goto errOut; - } - SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo; - if (revokedInfo != NULL) { - /* Treat this as optional even for CS_Revoked */ - this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime); - const SecAsn1Item *revReason = revokedInfo->revocationReason; - if((revReason != NULL) && - (revReason->Data != NULL) && - (revReason->Length != 0)) { - this->crlReason = revReason->Data[0]; - } - } - } - this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); - if (this->thisUpdate == NULL_TIME) { - ocspdErrorLog("OCSPResponse: bad thisUpdate DER"); - goto errOut; - } - - if (resp->nextUpdate != NULL) { - this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); - if (this->nextUpdate == NULL_TIME) { - ocspdErrorLog("OCSPResponse: bad nextUpdate DER"); - goto errOut; - } - } - - /* Lookup through extensions to find SCTs */ - if(resp->singleExtensions) { - ocspdErrorLog("OCSPResponse: single response has extension(s)."); - int i = 0; - NSS_CertExtension *extn; - while ((extn = resp->singleExtensions[i])) { - if(SecAsn1OidCompare(&extn->extnId, &OID_GOOGLE_OCSP_SCT )) { - ocspdErrorLog("OCSPResponse: single response has an SCT extension."); - SecAsn1Item sct_data = {0,}; - - // Note: if there are more that one valid SCT extension, we just use the first one that successfully decoded - if((this->scts == NULL) && (SecAsn1DecodeData(coder, &extn->value, kSecAsn1OctetStringTemplate, &sct_data) == 0)) { - this->scts = SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sct_data.Data, sct_data.Length); - ocspdErrorLog("OCSPResponse: single response has an SCT extension, parsed = %p.", this->scts); - } - } - i++; - } - } - - ocspdDebug("status %d reason %d", (int)this->certStatus, - (int)this->crlReason); - return this; -errOut: - if (this) - SecOCSPSingleResponseDestroy(this); - return NULL; -} - -#define LEEWAY (4500.0) - -/* Calculate temporal validity; set latestNextUpdate and expireTime. - Returns true if valid, else returns false. */ -bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, - CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) -{ - bool ok = false; - this->latestNextUpdate = NULL_TIME; - - if (this->producedAt > verifyTime + LEEWAY) { - secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now"); - goto exit; - } - - /* Make this->latestNextUpdate be the date farthest in the future - of any of the singleResponses nextUpdate fields. */ - SecAsn1OCSPSingleResponse **responses; - for (responses = this->responseData.responses; *responses; ++responses) { - SecAsn1OCSPSingleResponse *resp = *responses; - - /* thisUpdate later than 'now' invalidates the whole response. */ - CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); - if (thisUpdate > verifyTime + LEEWAY) { - secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now"); - goto exit; - } - - /* Keep track of latest nextUpdate. */ - if (resp->nextUpdate != NULL) { - CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); - if (nextUpdate > this->latestNextUpdate) { - this->latestNextUpdate = nextUpdate; - } - } - else { - /* RFC 5019 section 2.2.4 states on nextUpdate: - Responders MUST always include this value to aid in - response caching. See Section 6 for additional - information on caching. - */ - secnotice("ocsp", "OCSPResponse: nextUpdate not present"); -#ifdef STRICT_RFC5019 - goto exit; -#endif - } - } - - /* Now that we have this->latestNextUpdate, we figure out the latest - date at which we will expire this response from our cache. To comply - with rfc5019s: - -6.1. Caching at the Client - - To minimize bandwidth usage, clients MUST locally cache authoritative - OCSP responses (i.e., a response with a signature that has been - successfully validated and that indicate an OCSPResponseStatus of - 'successful'). - - Most OCSP clients will send OCSPRequests at or near the nextUpdate - time (when a cached response expires). To avoid large spikes in - responder load that might occur when many clients refresh cached - responses for a popular certificate, responders MAY indicate when the - client should fetch an updated OCSP response by using the cache- - control:max-age directive. Clients SHOULD fetch the updated OCSP - Response on or after the max-age time. To ensure that clients - receive an updated OCSP response, OCSP responders MUST refresh the - OCSP response before the max-age time. - -6.2 [...] - - we need to take the cache-control:max-age directive into account. - - The way the code below is written we ignore a max-age=0 in the - http header. Since a value of 0 (NULL_TIME) also means there - was no max-age in the header. This seems ok since that would imply - no-cache so we also ignore negative values for the same reason, - instead we'll expire whenever this->latestNextUpdate tells us to, - which is the signed value if max-age is too low, since we don't - want to refetch multilple times for a single page load in a browser. */ - if (this->latestNextUpdate == NULL_TIME) { - /* See comment above on RFC 5019 section 2.2.4. */ - /* Absolute expire time = current time plus defaultTTL */ - this->expireTime = verifyTime + defaultTTL; - } else if (this->latestNextUpdate < verifyTime - LEEWAY) { - secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago"); - goto exit; - } else if (maxAge > 0) { - /* Beware of double overflows such as: - - now + maxAge < this->latestNextUpdate - - in the math below since an attacker could create any positive - value for maxAge. */ - if (maxAge < this->latestNextUpdate - verifyTime) { - /* maxAge header wants us to expire the cache entry sooner than - nextUpdate would allow, to balance server load. */ - this->expireTime = verifyTime + maxAge; - } else { - /* maxAge http header attempting to make us cache the response - longer than it's valid for, bad http header! Ignoring you. */ -#ifdef DEBUG - CFStringRef hexResp = CFDataCopyHexString(this->data); - ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate," - " using latestNextUpdate %@", hexResp); - CFReleaseSafe(hexResp); -#endif - this->expireTime = this->latestNextUpdate; - } - } else { - /* No maxAge provided, just use latestNextUpdate. */ - this->expireTime = this->latestNextUpdate; - } - - ok = true; -exit: - return ok; -} - -SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID) { - SecAsn1OCSPResponse topResp = {}; - SecOCSPResponseRef this = NULL; - - require(ocspResponse, errOut); - require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)), - errOut); - require_noerr(SecAsn1CoderCreate(&this->coder), errOut); - - this->data = ocspResponse; - this->responseID = responseID; - CFRetain(ocspResponse); - - SecAsn1Item resp; - resp.Length = CFDataGetLength(ocspResponse); - resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse); - if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate, - &topResp)) { - ocspdErrorLog("OCSPResponse: decode failure at top level"); - } - /* remainder is valid only on RS_Success */ - if ((topResp.responseStatus.Data == NULL) || - (topResp.responseStatus.Length == 0)) { - ocspdErrorLog("OCSPResponse: no responseStatus"); - goto errOut; - } - this->responseStatus = topResp.responseStatus.Data[0]; - if (this->responseStatus != kSecOCSPSuccess) { -#ifdef DEBUG - CFStringRef hexResp = CFDataCopyHexString(this->data); - secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus, hexResp); - CFReleaseNull(hexResp); -#endif - /* not a failure of our constructor; this object is now useful, but - * only for this one byte of status info */ - goto fini; - } - if (topResp.responseBytes == NULL) { - /* I don't see how this can be legal on RS_Success */ - ocspdErrorLog("OCSPResponse: empty responseBytes"); - goto errOut; - } - if (!SecAsn1OidCompare(&topResp.responseBytes->responseType, - &OID_PKIX_OCSP_BASIC)) { - ocspdErrorLog("OCSPResponse: unknown responseType"); - goto errOut; - - } - - /* decode the SecAsn1OCSPBasicResponse */ - if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response, - kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse"); - goto errOut; - } - - /* signature and cert evaluation done externally */ - - /* decode the SecAsn1OCSPResponseData */ - if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData, - kSecAsn1OCSPResponseDataTemplate, &this->responseData)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData"); - goto errOut; - } - this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt); - if (this->producedAt == NULL_TIME) { - ocspdErrorLog("OCSPResponse: bad producedAt"); - goto errOut; - } - - if (this->responseData.responderID.Data == NULL) { - ocspdErrorLog("OCSPResponse: bad responderID"); - goto errOut; - } - - /* Choice processing for ResponderID */ - this->responderIdTag = (SecAsn1OCSPResponderIDTag) - (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK); - const SecAsn1Template *templ; - switch(this->responderIdTag) { - case RIT_Name: - /* @@@ Since we don't use the decoded byName value we could skip - decoding it but we do it anyway for validation. */ - templ = kSecAsn1OCSPResponderIDAsNameTemplate; - break; - case RIT_Key: - templ = kSecAsn1OCSPResponderIDAsKeyTemplate; - break; - default: - ocspdErrorLog("OCSPResponse: bad responderID tag"); - goto errOut; - } - if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ, - &this->responderID)) { - ocspdErrorLog("OCSPResponse: decode failure at responderID"); - goto errOut; - } - -fini: - return this; -errOut: -#ifdef DEBUG - { - CFStringRef hexResp = (this) ? CFDataCopyHexString(this->data) : NULL; - secdebug("ocsp", "bad ocsp response: %@", hexResp); - CFReleaseSafe(hexResp); - } -#endif - if (this) { - SecOCSPResponseFinalize(this); - } - return NULL; -} - -SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) { - return SecOCSPResponseCreateWithID(this, -1); -} - -int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) { - return this->responseID; -} - -CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) { - return this->data; -} - -SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) { - return this->responseStatus; -} - -CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) { - return this->expireTime; -} - -CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) { - return this->nonce; -} - -CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) { - return this->producedAt; -} - -CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) { - CFMutableArrayRef result = NULL; - result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (!result) { - return NULL; - } - SecAsn1Item **certs; - for (certs = this->basicResponse.certs; certs && *certs; ++certs) { - SecCertificateRef cert = NULL; - cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, (*certs)->Data, (*certs)->Length); - if (cert) { - CFArrayAppendValue(result, cert); - CFReleaseNull(cert); - } - } - - return result; -} - -void SecOCSPResponseFinalize(SecOCSPResponseRef this) { - CFReleaseSafe(this->data); - CFReleaseSafe(this->nonce); - SecAsn1CoderRelease(this->coder); - free(this); -} - -static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) { - /* rfc2560 section 2.4 states: "If nextUpdate is not set, the - responder is indicating that newer revocation information - is available all the time". - Let's ensure that thisUpdate isn't more than defaultTTL in - the past then. */ - return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate; -} - -bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) { - if (this->thisUpdate > verifyTime + LEEWAY) { - ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now"); - return false; - } - - CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL); - if (verifyTime - LEEWAY > cnu) { - ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400); - return false; - } - - return true; -} - -CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this) -{ - return CFRetainSafe(this->scts); -} - - -SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( - SecOCSPResponseRef this, SecOCSPRequestRef request) { - SecOCSPSingleResponseRef sr = NULL; - - if (!request) { return sr; } - CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate); - const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer); - CFDataRef serial = SecCertificateCopySerialNumberData(request->certificate, NULL); - CFDataRef issuerNameHash = NULL; - CFDataRef issuerPubKeyHash = NULL; - SecAsn1Oid *algorithm = NULL; - SecAsn1Item *parameters = NULL; - - SecAsn1OCSPSingleResponse **responses; - for (responses = this->responseData.responses; *responses; ++responses) { - SecAsn1OCSPSingleResponse *resp = *responses; - SecAsn1OCSPCertID *certId = &resp->certID; - /* First check the easy part, serial number should match. */ - if (!serial || certId->serialNumber.Length != (size_t)CFDataGetLength(serial) || - memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data, - certId->serialNumber.Length)) { - /* Serial # mismatch, skip this singleResponse. */ - continue; - } - - /* Calcluate the issuerKey and issuerName digests using the - hashAlgorithm and parameters specified in the certId, if - they differ from the ones we already computed. */ - if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) || - !SecAsn1OidCompare(parameters, &certId->algId.parameters)) { - algorithm = &certId->algId.algorithm; - parameters = &certId->algId.parameters; - CFReleaseSafe(issuerNameHash); - CFReleaseSafe(issuerPubKeyHash); - issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm, - parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); - issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm, - parameters, publicKey->data, publicKey->length); - } - - if (!issuerNameHash || !issuerPubKeyHash) { - /* This can happen when the hash algorithm is not supported, should be really rare */ - /* See also: CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */ - ocspdErrorLog("Unknown hash algorithm in singleResponse"); - algorithm = NULL; - parameters = NULL; - continue; - } - - if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash) - && !memcmp(CFDataGetBytePtr(issuerNameHash), - certId->issuerNameHash.Data, certId->issuerNameHash.Length) - && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash) - && !memcmp(CFDataGetBytePtr(issuerPubKeyHash), - certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) { - - /* resp matches the certificate in request, so let's use it. */ - sr = SecOCSPSingleResponseCreate(resp, this->coder); - if (sr) { - ocspdDebug("found matching singleResponse"); - break; - } - } - - } - - CFReleaseSafe(issuerPubKeyHash); - CFReleaseSafe(issuerNameHash); - CFReleaseSafe(serial); - CFReleaseSafe(issuer); - - if (!sr) { - ocspdDebug("certID not found"); - } - - return sr; -} - -static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this, - SecKeyRef key) { - /* Beware this->basicResponse.sig: on decode, length is in BITS */ - return SecKeyDigestAndVerify(key, &this->basicResponse.algId, - this->basicResponse.tbsResponseData.Data, - this->basicResponse.tbsResponseData.Length, - this->basicResponse.sig.Data, - this->basicResponse.sig.Length / 8) == errSecSuccess; -} - -static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this, - SecCertificateRef issuer) { - bool shouldBeSigner = false; - if (this->responderIdTag == RIT_Name) { - /* Name inside response must == signer's SubjectName. */ - CFDataRef subject = SecCertificateCopySubjectSequence(issuer); - if (!subject) { - ocspdDebug("error on SecCertificateCopySubjectSequence"); - return false; - } - if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length && - !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject), - this->responderID.byName.Length)) { - ocspdDebug("good ResponderID.byName"); - shouldBeSigner = true; - } else { - ocspdDebug("BAD ResponderID.byName"); - } - CFRelease(subject); - } else /* if (this->responderIdTag == RIT_Key) */ { - /* ResponderID.byKey must == SHA1(signer's public key) */ - CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(issuer); - if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length && - !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest), - this->responderID.byKey.Length)) { - ocspdDebug("good ResponderID.byKey"); - shouldBeSigner = true; - } else { - ocspdDebug("BAD ResponderID.byKey"); - } - CFRelease(pubKeyDigest); - } - - if (shouldBeSigner) { - SecKeyRef key = SecCertificateCopyKey(issuer); - if (key) { - shouldBeSigner = SecOCSPResponseVerifySignature(this, key); - ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not "); - CFRelease(key); - } else { - ocspdDebug("Failed to extract key from leaf certificate"); - shouldBeSigner = false; - } - } - - return shouldBeSigner; -} - -/* Returns the SecCertificateRef of the cert that signed this ocspResponse if - we can find one and NULL if we can't find a valid signer. */ -SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertificateRef issuer) { - /* Look though any certs that came with the response to find - * which one signed the response. */ - SecAsn1Item **certs; - for (certs = this->basicResponse.certs; certs && *certs; ++certs) { - SecCertificateRef cert = SecCertificateCreateWithBytes( - kCFAllocatorDefault, (*certs)->Data, (*certs)->Length); - if (cert) { - if (SecOCSPResponseIsIssuer(this, cert)) { - return cert; - } else { - CFRelease(cert); - } - } else { - ocspdErrorLog("ocsp response cert failed to parse"); - } - } - ocspdDebug("ocsp response did not contain a signer cert."); - - /* If none of the returned certs work, try the issuer of the certificate - being checked directly. */ - if (issuer && SecOCSPResponseIsIssuer(this, issuer)) { - CFRetain(issuer); - return issuer; - } - - /* We couldn't find who signed this ocspResponse, give up. */ - return NULL; -} diff --git a/OSX/sec/securityd/SecOCSPResponse.h b/OSX/sec/securityd/SecOCSPResponse.h deleted file mode 100644 index 0398c438..00000000 --- a/OSX/sec/securityd/SecOCSPResponse.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2009,2012-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecOCSPResponse - The functions and data types in SecOCSPResponse implement ocsp response - decoding and verification. -*/ - -#ifndef _SECURITY_SECOCSPRESPONSE_H_ -#define _SECURITY_SECOCSPRESPONSE_H_ - -#include -#include -#include -#include -#include "securityd/SecOCSPRequest.h" -#include - -__BEGIN_DECLS - -typedef enum { - kSecOCSPBad = -2, - kSecOCSPUnknown = -1, - kSecOCSPSuccess = 0, - kSecOCSPMalformedRequest = 1, - kSecOCSPInternalError = 2, - kSecOCSPTryLater = 3, - kSecOCSPUnused = 4, - kSecOCSPSigRequired = 5, - kSecOCSPUnauthorized = 6 -} SecOCSPResponseStatus; - -enum { - kSecRevocationReasonUnrevoked = -2, - kSecRevocationReasonUndetermined = -1, - kSecRevocationReasonUnspecified = 0, - kSecRevocationReasonKeyCompromise = 1, - kSecRevocationReasonCACompromise = 2, - kSecRevocationReasonAffiliationChanged = 3, - kSecRevocationReasonSuperseded = 4, - kSecRevocationReasonCessationOfOperation = 5, - kSecRevocationReasonCertificateHold = 6, - /* -- value 7 is not used */ - kSecRevocationReasonRemoveFromCRL = 8, - kSecRevocationReasonPrivilegeWithdrawn = 9, - kSecRevocationReasonAACompromise = 10 -}; -typedef int32_t SecRevocationReason; - - -/*! - @typedef SecOCSPResponseRef - @abstract Object used for ocsp response decoding. -*/ -typedef struct __SecOCSPResponse *SecOCSPResponseRef; - -struct __SecOCSPResponse { - CFDataRef data; - SecAsn1CoderRef coder; - SecOCSPResponseStatus responseStatus; - CFDataRef nonce; - CFAbsoluteTime producedAt; - CFAbsoluteTime latestNextUpdate; - CFAbsoluteTime expireTime; - SecAsn1OCSPBasicResponse basicResponse; - SecAsn1OCSPResponseData responseData; - SecAsn1OCSPResponderIDTag responderIdTag; - SecAsn1OCSPResponderID responderID; - int64_t responseID; -}; - -typedef struct __SecOCSPSingleResponse *SecOCSPSingleResponseRef; - -struct __SecOCSPSingleResponse { - SecAsn1OCSPCertStatusTag certStatus; - CFAbsoluteTime thisUpdate; - CFAbsoluteTime nextUpdate; /* may be NULL_TIME */ - CFAbsoluteTime revokedTime; /* != NULL_TIME for certStatus == CS_Revoked */ - SecRevocationReason crlReason; - CFArrayRef scts; /* This is parsed from an extension */ -}; - -/*! - @function SecOCSPResponseCreate - @abstract Returns a SecOCSPResponseRef from a BER encoded ocsp response. - @param ocspResponse The BER encoded ocsp response. - @result A SecOCSPResponseRef. -*/ -SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef ocspResponse); - -SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID); - -int64_t SecOCSPResponseGetID(SecOCSPResponseRef ocspResponse); - -/* Return true if response is still valid for the given age. */ -bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, - CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime); - -CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this); - -SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef ocspResponse); - -CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef ocspResponse); - -CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef ocspResponse); - -CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef ocspResponse); - -/*! - @function SecOCSPResponseCopySigners - @abstract Returns an array of signers. - @param ocspResponse A SecOCSPResponseRef. - @result The passed in SecOCSPResponseRef is deallocated -*/ -CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef ocspResponse); - -/*! - @function SecOCSPResponseFinalize - @abstract Frees a SecOCSPResponseRef. - @param ocspResponse The BER encoded ocsp response. -*/ -void SecOCSPResponseFinalize(SecOCSPResponseRef ocspResponse); - -SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( - SecOCSPResponseRef ocspResponse, SecOCSPRequestRef request); - -/* DefaultTTL is how long past the thisUpdate time we trust a response without a nextUpdate field. */ -bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFAbsoluteTime defaultTTL, CFAbsoluteTime verifyTime); - -/* Find the eventual SCTs from the single response extensions */ -CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this); - -void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this); - -/* Returns the SecCertificateRef whose leaf signed this ocspResponse if - we can find one and NULL if we can't find a valid signer. The issuerPath - contains the cert chain from the anchor to the certificate that issued the - leaf certificate for which this ocspResponse is supposed to be valid. */ -SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, - SecCertificateRef issuerPath); - -__END_DECLS - -#endif /* !_SECURITY_SECOCSPRESPONSE_H_ */ diff --git a/OSX/sec/securityd/SecOTRRemote.h b/OSX/sec/securityd/SecOTRRemote.h deleted file mode 100644 index 44775958..00000000 --- a/OSX/sec/securityd/SecOTRRemote.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef sec_SecOTRRemote_h -#define sec_SecOTRRemote_h - -#include - -CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error); -CFDataRef _SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error); -bool _SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error); - -#endif diff --git a/OSX/sec/securityd/SecOTRRemote.m b/OSX/sec/securityd/SecOTRRemote.m deleted file mode 100644 index 29c85ee7..00000000 --- a/OSX/sec/securityd/SecOTRRemote.m +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include "AssertMacros.h" -#include -#include "SecOTRRemote.h" -#include -#include -#include -#include - -#include "SOSAccountPriv.h" - -#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" - -CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error) { - SOSDataSourceFactoryRef ds = SecItemDataSourceFactoryGetDefault(); - - SOSAccount* privateAccount = NULL; - SOSAccount* publicAccount = NULL; - CFStringRef publicKeyString = NULL; - SecKeyRef privateKeyRef = NULL; - SecKeyRef publicKeyRef = NULL; - SecOTRFullIdentityRef privateIdentity = NULL; - SecOTRPublicIdentityRef publicIdentity = NULL; - CFDataRef result = NULL; - SecOTRSessionRef ourSession = NULL; - - require_quiet(ds, fail); - require_quiet(publicPeerId, fail); - - if (privateAccountData) { - NSError* ns_error = nil; - privateAccount = [SOSAccount accountFromData:(__bridge NSData*) privateAccountData factory:ds error:&ns_error]; - if (error && *error == NULL && !privateAccount) { - *error = (CFErrorRef) CFBridgingRetain(ns_error); - } - } else { - privateAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); - } - - require_quiet(privateAccount, fail); - - privateKeyRef = SOSAccountCopyDeviceKey(privateAccount, error); - require_quiet(privateKeyRef, fail); - - privateIdentity = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, privateKeyRef, error); - require_quiet(privateIdentity, fail); - CFReleaseNull(privateKeyRef); - - publicKeyString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, publicPeerId, kCFStringEncodingUTF8); - require_quiet(publicKeyString, fail); - - if (publicAccountData) { - NSError* ns_error = nil; - publicAccount = [SOSAccount accountFromData:(__bridge NSData*) publicAccountData factory:ds error:&ns_error]; - if (error && *error == NULL && !publicAccount) { - *error = (CFErrorRef) CFBridgingRetain(ns_error); - } - } else { - publicAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); - } - - require_quiet(publicAccount, fail); - - publicKeyRef = [publicAccount.trust copyPublicKeyForPeer:publicKeyString err:error]; - - if(!publicKeyRef){ - if(!ds){ - CFReleaseNull(ourSession); - CFReleaseNull(publicKeyString); - privateAccount= nil; - publicAccount = nil; - CFReleaseNull(privateKeyRef); - CFReleaseNull(publicKeyRef); - CFReleaseNull(publicIdentity); - CFReleaseNull(privateIdentity); - return result; - } - } - publicIdentity = SecOTRPublicIdentityCreateFromSecKeyRef(kCFAllocatorDefault, publicKeyRef, error); - require_quiet(publicIdentity, fail); - - CFReleaseNull(publicKeyRef); - - ourSession = SecOTRSessionCreateFromID(kCFAllocatorDefault, privateIdentity, publicIdentity); - - CFMutableDataRef exportSession = CFDataCreateMutable(kCFAllocatorDefault, 0); - SecOTRSAppendSerialization(ourSession, exportSession); - - result = exportSession; - exportSession = NULL; - -fail: - CFReleaseNull(ourSession); - CFReleaseNull(publicKeyString); - privateAccount= nil; - publicAccount = nil; - CFReleaseNull(privateKeyRef); - CFReleaseNull(publicKeyRef); - CFReleaseNull(publicIdentity); - CFReleaseNull(privateIdentity); - return result; -} - -CFDataRef _SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) { - return SecOTRSessionCreateRemote_internal(NULL, publicPeerId, NULL, error); -} - -bool _SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) { - - bool result = false; - SecOTRSessionRef session = SecOTRSessionCreateFromData(kCFAllocatorDefault, sessionData); - require_quiet(session, done); - - CFMutableDataRef negotiationResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); - - if (inputPacket) { - SecOTRSProcessPacket(session, inputPacket, negotiationResponse); - } else { - SecOTRSAppendStartPacket(session, negotiationResponse); - } - - CFMutableDataRef outputSession = CFDataCreateMutable(kCFAllocatorDefault, 0); - - SecOTRSAppendSerialization(session, outputSession); - *outputSessionData = outputSession; - - *outputPacket = negotiationResponse; - - *readyForMessages = SecOTRSGetIsReadyForMessages(session); - CFReleaseNull(session); - - result = true; - -done: - return result; -} - diff --git a/OSX/sec/securityd/SecPinningDb.h b/OSX/sec/securityd/SecPinningDb.h deleted file mode 100644 index fc5a21d6..00000000 --- a/OSX/sec/securityd/SecPinningDb.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/*! - @header SecPinningDb - The functions in SecPinningDb.h provide an interface to look up - pinning rules based on hostname. - */ - -#ifndef _SECURITY_SECPINNINGDB_H_ -#define _SECURITY_SECPINNINGDB_H_ - -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -extern const CFStringRef kSecPinningDbKeyHostname; -extern const CFStringRef kSecPinningDbKeyPolicyName; -extern const CFStringRef kSecPinningDbKeyRules; - -CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef _Nonnull query); -void SecPinningDbInitialize(void); - -#if !TARGET_OS_BRIDGE && __OBJC__ -/* Updating the pinning DB isn't supported on BridgeOS because we treat the disk as read-only. */ -bool SecPinningDbUpdateFromURL(NSURL *url, NSError **error); -#endif - -CFNumberRef SecPinningDbCopyContentVersion(void); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - - -#endif /* _SECURITY_SECPINNINGDB_H_ */ diff --git a/OSX/sec/securityd/SecPinningDb.m b/OSX/sec/securityd/SecPinningDb.m deleted file mode 100644 index b0308ccb..00000000 --- a/OSX/sec/securityd/SecPinningDb.m +++ /dev/null @@ -1,863 +0,0 @@ -/* - * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/* - * SecPinningDb.m - */ - -#include -#import -#import -#import -#import - -#if !TARGET_OS_BRIDGE -#import -#import -#endif - -#if TARGET_OS_OSX -#import -#include -#endif - -#import - -#import -#import -#import - -#include "utilities/debugging.h" -#include "utilities/sqlutils.h" -#include "utilities/iOSforOSX.h" -#include -#include -#include -#include -#include -#include "utilities/sec_action.h" - -#define kSecPinningDbFileName "pinningrules.sqlite3" - -const uint64_t PinningDbSchemaVersion = 2; -const NSString *PinningDbPolicyNameKey = @"policyName"; /* key for a string value */ -const NSString *PinningDbDomainsKey = @"domains"; /* key for an array of dictionaries */ -const NSString *PinningDbPoliciesKey = @"rules"; /* key for an array of dictionaries */ -const NSString *PinningDbDomainSuffixKey = @"suffix"; /* key for a string */ -const NSString *PinningDbLabelRegexKey = @"labelRegex"; /* key for a regex string */ - -const CFStringRef kSecPinningDbKeyHostname = CFSTR("PinningHostname"); -const CFStringRef kSecPinningDbKeyPolicyName = CFSTR("PinningPolicyName"); -const CFStringRef kSecPinningDbKeyRules = CFSTR("PinningRules"); - -@interface SecPinningDb : NSObject -@property (assign) SecDbRef db; -@property dispatch_queue_t queue; -@property NSURL *dbPath; -@property (assign) os_unfair_lock regexCacheLock; -@property NSMutableDictionary *regexCache; -- (instancetype) init; -- ( NSDictionary * _Nullable ) queryForDomain:(NSString *)domain; -- ( NSDictionary * _Nullable ) queryForPolicyName:(NSString *)policyName; -@end - -static inline bool isNSNumber(id nsType) { - return nsType && [nsType isKindOfClass:[NSNumber class]]; -} - -static inline bool isNSArray(id nsType) { - return nsType && [nsType isKindOfClass:[NSArray class]]; -} - -static inline bool isNSDictionary(id nsType) { - return nsType && [nsType isKindOfClass:[NSDictionary class]]; -} - -@implementation SecPinningDb -#define getSchemaVersionSQL CFSTR("PRAGMA user_version") -#define selectVersionSQL CFSTR("SELECT ival FROM admin WHERE key='version'") -#define insertAdminSQL CFSTR("INSERT OR REPLACE INTO admin (key,ival,value) VALUES (?,?,?)") -#define selectDomainSQL CFSTR("SELECT DISTINCT labelRegex,policyName,policies FROM rules WHERE domainSuffix=?") -#define selectPolicyNameSQL CFSTR("SELECT DISTINCT policies FROM rules WHERE policyName=?") -#define insertRuleSQL CFSTR("INSERT OR REPLACE INTO rules (policyName,domainSuffix,labelRegex,policies) VALUES (?,?,?,?) ") -#define removeAllRulesSQL CFSTR("DELETE FROM rules;") - -- (NSNumber *)getSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - __block bool ok = true; - __block NSNumber *version = nil; - ok &= SecDbWithSQL(dbconn, getSchemaVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { - ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { - int ival = sqlite3_column_int(selectVersion, 0); - version = [NSNumber numberWithInt:ival]; - }); - return ok; - }); - return version; -} - -- (BOOL)setSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - bool ok = true; - NSString *setVersion = [NSString stringWithFormat:@"PRAGMA user_version = %llu", PinningDbSchemaVersion]; - ok &= SecDbExec(dbconn, - (__bridge CFStringRef)setVersion, - error); - if (!ok) { - secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); - } - return ok; -} - -- (NSNumber *)getContentVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - __block bool ok = true; - __block NSNumber *version = nil; - ok &= SecDbWithSQL(dbconn, selectVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { - ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { - uint64_t ival = sqlite3_column_int64(selectVersion, 0); - version = [NSNumber numberWithUnsignedLongLong:ival]; - }); - return ok; - }); - return version; -} - -- (BOOL)setContentVersion:(NSNumber *)version dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - __block BOOL ok = true; - ok &= SecDbWithSQL(dbconn, insertAdminSQL, error, ^bool(sqlite3_stmt *insertAdmin) { - const char *versionKey = "version"; - ok &= SecDbBindText(insertAdmin, 1, versionKey, strlen(versionKey), SQLITE_TRANSIENT, error); - ok &= SecDbBindInt64(insertAdmin, 2, [version unsignedLongLongValue], error); - ok &= SecDbStep(dbconn, insertAdmin, error, NULL); - return ok; - }); - if (!ok) { - secerror("SecPinningDb: failed to set version %@ from pinning list: %@", version, error ? *error : nil); - } - return ok; -} - -- (BOOL) shouldUpdateContent:(NSNumber *)new_version error:(NSError **)nserror { - __block CFErrorRef error = NULL; - __block BOOL ok = YES; - __block BOOL newer = NO; - ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { - NSNumber *db_version = [self getContentVersion:dbconn error:&error]; - if (!db_version || [new_version compare:db_version] == NSOrderedDescending) { - newer = YES; - secnotice("pinningDb", "Pinning database should update from version %@ to version %@", db_version, new_version); - } - }); - - if (!ok || error) { - secerror("SecPinningDb: error reading content version from database %@", error); - } - if (nserror && error) { *nserror = CFBridgingRelease(error); } - return newer; -} - -- (BOOL) insertRuleWithName:(NSString *)policyName - domainSuffix:(NSString *)domainSuffix - labelRegex:(NSString *)labelRegex - policies:(NSArray *)policies - dbConnection:(SecDbConnectionRef)dbconn - error:(CFErrorRef *)error{ - /* @@@ This insertion mechanism assumes that the input is trusted -- namely, that the new rules - * are allowed to replace existing rules. For third-party inputs, this assumption isn't true. */ - - secdebug("pinningDb", "inserting new rule: %@ for %@.%@", policyName, labelRegex, domainSuffix); - - __block bool ok = true; - ok &= SecDbWithSQL(dbconn, insertRuleSQL, error, ^bool(sqlite3_stmt *insertRule) { - ok &= SecDbBindText(insertRule, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, error); - ok &= SecDbBindText(insertRule, 2, [domainSuffix UTF8String], [domainSuffix length], SQLITE_TRANSIENT, error); - ok &= SecDbBindText(insertRule, 3, [labelRegex UTF8String], [labelRegex length], SQLITE_TRANSIENT, error); - NSData *xmlPolicies = [NSPropertyListSerialization dataWithPropertyList:policies - format:NSPropertyListXMLFormat_v1_0 - options:0 - error:nil]; - if (!xmlPolicies) { - secerror("SecPinningDb: failed to serialize policies"); - ok = false; - } - ok &= SecDbBindBlob(insertRule, 4, [xmlPolicies bytes], [xmlPolicies length], SQLITE_TRANSIENT, error); - ok &= SecDbStep(dbconn, insertRule, error, NULL); - return ok; - }); - if (!ok) { - secerror("SecPinningDb: failed to insert rule %@ for %@.%@ with error %@", policyName, labelRegex, domainSuffix, error ? *error : nil); - } - return ok; -} - -- (BOOL) populateDbFromBundle:(NSArray *)pinningList dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - __block BOOL ok = true; - [pinningList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if (idx ==0) { return; } // Skip the first value which is the version - if (!isNSDictionary(obj)) { - secerror("SecPinningDb: rule entry in pinning plist is wrong class"); - ok = false; - return; - } - NSDictionary *rule = obj; - __block NSString *policyName = [rule objectForKey:PinningDbPolicyNameKey]; - NSArray *domains = [rule objectForKey:PinningDbDomainsKey]; - __block NSArray *policies = [rule objectForKey:PinningDbPoliciesKey]; - - if (!policyName || !domains || !policies) { - secerror("SecPinningDb: failed to get required fields from rule entry %lu", (unsigned long)idx); - ok = false; - return; - } - - [domains enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if (!isNSDictionary(obj)) { - secerror("SecPinningDb: domain entry %lu for %@ in pinning rule is wrong class", (unsigned long)idx, policyName); - ok = false; - return; - } - NSDictionary *domain = obj; - NSString *suffix = [domain objectForKey:PinningDbDomainSuffixKey]; - NSString *labelRegex = [domain objectForKey:PinningDbLabelRegexKey]; - - if (!suffix || !labelRegex) { - secerror("SecPinningDb: failed to get required fields for entry %lu for %@", (unsigned long)idx, policyName); - ok = false; - return; - } - ok &= [self insertRuleWithName:policyName domainSuffix:suffix labelRegex:labelRegex policies:policies - dbConnection:dbconn error:error]; - }]; - }]; - if (!ok) { - secerror("SecPinningDb: failed to populate DB from pinning list: %@", error ? *error : nil); - } - return ok; -} - -- (BOOL) removeAllRulesFromDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - __block BOOL ok = true; - ok &= SecDbWithSQL(dbconn, removeAllRulesSQL, error, ^bool(sqlite3_stmt *deleteRules) { - ok &= SecDbStep(dbconn, deleteRules, error, NULL); - return ok; - }); - if (!ok) { - secerror("SecPinningDb: failed to delete old values: %@", error ? *error :nil); - } - return ok; -} - - -- (BOOL) createOrAlterAdminTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - bool ok = true; - ok &= SecDbExec(dbconn, - CFSTR("CREATE TABLE IF NOT EXISTS admin(" - "key TEXT PRIMARY KEY NOT NULL," - "ival INTEGER NOT NULL," - "value BLOB" - ");"), - error); - if (!ok) { - secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); - } - return ok; -} - -- (BOOL) createOrAlterRulesTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { - bool ok = true; - ok &= SecDbExec(dbconn, - CFSTR("CREATE TABLE IF NOT EXISTS rules(" - "policyName TEXT NOT NULL," - "domainSuffix TEXT NOT NULL," - "labelRegex TEXT NOT NULL," - "policies BLOB NOT NULL," - "UNIQUE(policyName, domainSuffix, labelRegex)" - ");"), - error); - ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS idomain ON rules(domainSuffix);"), error); - ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS ipolicy ON rules(policyName);"), error); - if (!ok) { - secerror("SecPinningDb: failed to create rules table: %@", error ? *error : nil); - } - return ok; -} - -#if !TARGET_OS_BRIDGE -- (BOOL) installDbFromURL:(NSURL *)localURL error:(NSError **)nserror { - if (!localURL) { - secerror("SecPinningDb: missing url for downloaded asset"); - return NO; - } - NSURL *fileLoc = [NSURL URLWithString:@"CertificatePinning.plist" - relativeToURL:localURL]; - __block NSArray *pinningList = [NSArray arrayWithContentsOfURL:fileLoc error:nserror]; - if (!pinningList) { - secerror("SecPinningDb: unable to create pinning list from asset file: %@", fileLoc); - return NO; - } - - NSNumber *plist_version = [pinningList objectAtIndex:0]; - if (![self shouldUpdateContent:plist_version error:nserror]) { - /* Something went wrong reading the DB in order to determine whether this version is new. */ - if (nserror && *nserror) { - return NO; - } - /* We got a new plist but we already have that version installed. */ - return YES; - } - - /* Update Content */ - __block CFErrorRef error = NULL; - __block BOOL ok = YES; - dispatch_sync(self->_queue, ^{ - ok &= SecDbPerformWrite(self->_db, &error, ^(SecDbConnectionRef dbconn) { - ok &= [self updateDb:dbconn error:&error pinningList:pinningList updateSchema:NO updateContent:YES]; - }); -#if !TARGET_OS_WATCH - /* We changed the database, so clear the database cache */ - [self clearCache]; -#endif - }); - - if (!ok || error) { - secerror("SecPinningDb: error installing updated pinning list version %@: %@", [pinningList objectAtIndex:0], error); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error - withEventName:TrustdHealthAnalyticsEventDatabaseEvent - withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), - TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationWrite) }]; -#endif // ENABLE_TRUSTD_ANALYTICS - if (nserror && error) { *nserror = CFBridgingRelease(error); } - } - - return ok; -} -#endif /* !TARGET_OS_BRIDGE */ - -- (NSArray *) copySystemPinningList { - NSArray *pinningList = nil; - NSURL *pinningListURL = nil; - /* Get the pinning list shipped with the OS */ - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - if (otapkiref) { - pinningListURL = CFBridgingRelease(SecOTAPKICopyPinningList(otapkiref)); - CFReleaseNull(otapkiref); - if (!pinningListURL) { - secerror("SecPinningDb: failed to get pinning plist URL"); - } - NSError *error = nil; - pinningList = [NSArray arrayWithContentsOfURL:pinningListURL error:&error]; - if (!pinningList) { - secerror("SecPinningDb: failed to read pinning plist from bundle: %@", error); - } - } - - return pinningList; -} - -- (BOOL) updateDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error pinningList:(NSArray *)pinningList - updateSchema:(BOOL)updateSchema updateContent:(BOOL)updateContent -{ - if (!SecOTAPKIIsSystemTrustd()) { return false; } - secdebug("pinningDb", "updating or creating database"); - - __block bool ok = true; - ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - if (updateSchema) { - /* update the tables */ - ok &= [self createOrAlterAdminTable:dbconn error:error]; - ok &= [self createOrAlterRulesTable:dbconn error:error]; - ok &= [self setSchemaVersion:dbconn error:error]; - } - - if (updateContent) { - /* remove the old data */ - /* @@@ This behavior assumes that we have all the rules we want to populate - * elsewhere on disk and that the DB doesn't contain the sole copy of that data. */ - ok &= [self removeAllRulesFromDb:dbconn error:error]; - - /* read the new data */ - NSNumber *version = [pinningList objectAtIndex:0]; - - /* populate the tables */ - ok &= [self populateDbFromBundle:pinningList dbConnection:dbconn error:error]; - ok &= [self setContentVersion:version dbConnection:dbconn error:error]; - } - - *commit = ok; - }); - - return ok; -} - -- (SecDbRef) createAtPath { - bool readWrite = SecOTAPKIIsSystemTrustd(); -#if TARGET_OS_OSX - mode_t mode = 0644; // Root trustd can rw. All other trustds need to read. -#else - mode_t mode = 0600; // Only one trustd. -#endif - - CFStringRef path = CFStringCreateWithCString(NULL, [_dbPath fileSystemRepresentation], kCFStringEncodingUTF8); - SecDbRef result = SecDbCreate(path, mode, readWrite, readWrite, false, false, 1, - ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { - if (!SecOTAPKIIsSystemTrustd()) { - /* Non-owner process can't update the db, but it should get a db connection. - * @@@ Revisit if new schema version is needed by reader processes. */ - return true; - } - - dispatch_assert_queue_not(self->_queue); - - __block BOOL ok = true; - dispatch_sync(self->_queue, ^{ - bool updateSchema = false; - bool updateContent = false; - - /* Get the pinning plist */ - NSArray *pinningList = [self copySystemPinningList]; - if (!pinningList) { - secerror("SecPinningDb: failed to find pinning plist in bundle"); - ok = false; - return; - } - - /* Check latest data and schema versions against existing table. */ - if (!isNSNumber([pinningList objectAtIndex:0])) { - secerror("SecPinningDb: pinning plist in wrong format"); - return; // Don't change status. We can continue to use old DB. - } - NSNumber *plist_version = [pinningList objectAtIndex:0]; - NSNumber *db_version = [self getContentVersion:dbconn error:error]; - secnotice("pinningDb", "Opening db with version %@", db_version); - if (!db_version || [plist_version compare:db_version] == NSOrderedDescending) { - secnotice("pinningDb", "Updating pinning database content from version %@ to version %@", - db_version ? db_version : 0, plist_version); - updateContent = true; - } - NSNumber *schema_version = [self getSchemaVersion:dbconn error:error]; - NSNumber *current_version = [NSNumber numberWithUnsignedLongLong:PinningDbSchemaVersion]; - if (!schema_version || ![schema_version isEqualToNumber:current_version]) { - secnotice("pinningDb", "Updating pinning database schema from version %@ to version %@", - schema_version, current_version); - updateSchema = true; - } - - if (updateContent || updateSchema) { - ok &= [self updateDb:dbconn error:error pinningList:pinningList updateSchema:updateSchema updateContent:updateContent]; - /* Since we updated the DB to match the list that shipped with the system, - * reset the OTAPKI Asset version to the system asset version */ - (void)SecOTAPKIResetCurrentAssetVersion(NULL); - } - if (!ok) { - secerror("SecPinningDb: %s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logHardError:(error ? (__bridge NSError *)*error : nil) - withEventName:TrustdHealthAnalyticsEventDatabaseEvent - withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), - TrustdHealthAnalyticsAttributeDatabaseOperation : didCreate ? @(TAOperationCreate) : @(TAOperationOpen)}]; -#endif // ENABLE_TRUSTD_ANALYTICS - } - }); - return ok; - }); - - CFReleaseNull(path); - return result; -} - -static void verify_create_path(const char *path) -{ - int ret = mkpath_np(path, 0755); - if (!(ret == 0 || ret == EEXIST)) { - secerror("could not create path: %s (%s)", path, strerror(ret)); - } -} - -- (NSURL *)pinningDbPath { - /* Make sure the /Library/Keychains directory is there */ - NSURL *directory = CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(nil)); - verify_create_path([directory fileSystemRepresentation]); - - /* Get the full path of the pinning DB */ - return [directory URLByAppendingPathComponent:@kSecPinningDbFileName]; -} - -- (void) initializedDb { - dispatch_sync(_queue, ^{ - if (!self->_db) { - self->_dbPath = [self pinningDbPath]; - self->_db = [self createAtPath]; - } - }); -} - -- (instancetype) init { - if (self = [super init]) { - _queue = dispatch_queue_create("Pinning DB Queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); -#if !TARGET_OS_WATCH - _regexCache = [NSMutableDictionary dictionary]; - _regexCacheLock = OS_UNFAIR_LOCK_INIT; -#endif - [self initializedDb]; - } - return self; -} - -- (void) dealloc { - CFReleaseNull(_db); -} - -/* MARK: DB Cache - * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } } - * The cache is not used on watchOS to reduce memory overhead. */ -#if !TARGET_OS_WATCH -- (void) clearCache { - os_unfair_lock_lock(&_regexCacheLock); - self.regexCache = [NSMutableDictionary dictionary]; - os_unfair_lock_unlock(&_regexCacheLock); -} -#endif // !TARGET_OS_WATCH - -#if !TARGET_OS_WATCH -- (void) addSuffixToCache:(NSString *)suffix entry:(NSDictionary *)entry { - os_unfair_lock_lock(&_regexCacheLock); - secinfo("SecPinningDb", "adding %llu entries for %@ to cache", (unsigned long long)[entry count], suffix); - self.regexCache[suffix] = entry; - os_unfair_lock_unlock(&_regexCacheLock); -} -#endif // !TARGET_OS_WATCH - -#if !TARGET_OS_WATCH -/* Because we iterate over all DB entries for a suffix, even if we find a match, we guarantee - * that the cache, if the cache has an entry for a suffix, it has all the entries for that suffix */ -- (BOOL) queryCacheForSuffix:(NSString *)suffix firstLabel:(NSString *)firstLabel results:(NSDictionary * __autoreleasing *)results{ - __block BOOL foundSuffix = NO; - os_unfair_lock_lock(&_regexCacheLock); - NSDictionary *cacheEntry; - if (NULL != (cacheEntry = self.regexCache[suffix])) { - foundSuffix = YES; - for (NSRegularExpression *regex in cacheEntry) { - NSUInteger numMatches = [regex numberOfMatchesInString:firstLabel - options:0 - range:NSMakeRange(0, [firstLabel length])]; - if (numMatches == 0) { - continue; - } - secinfo("SecPinningDb", "found matching rule in cache for %@.%@", firstLabel, suffix); - NSDictionary *resultDictionary = [cacheEntry objectForKey:regex]; - - /* Check the policyName for no-pinning settings */ - if ([self isPinningDisabled:resultDictionary[(__bridge NSString *)kSecPinningDbKeyPolicyName]]) { - continue; - } - - /* Return the pinning rules */ - if (results) { - *results = resultDictionary; - } - } - } - os_unfair_lock_unlock(&_regexCacheLock); - - return foundSuffix; -} -#endif // !TARGET_OS_WATCH - -- (BOOL) isPinningDisabled:(NSString * _Nullable)policy { - static dispatch_once_t once; - static sec_action_t action; - - BOOL pinningDisabled = NO; - if (SecIsInternalRelease()) { - NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; - pinningDisabled = [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]; - if (!pinningDisabled && policy) { - NSMutableString *policySpecificKey = [NSMutableString stringWithString:@"AppleServerAuthenticationNoPinning"]; - [policySpecificKey appendString:policy]; - pinningDisabled = [defaults boolForKey:policySpecificKey]; - secinfo("pinningQA", "%@ disable pinning = %d", policy, pinningDisabled); - } - } - - - dispatch_once(&once, ^{ - /* Only log system-wide pinning status once every five minutes */ - action = sec_action_create("pinning logging charles", 5*60.0); - sec_action_set_handler(action, ^{ - if (!SecIsInternalRelease()) { - secnotice("pinningQA", "could not disable pinning: not an internal release"); - } else { - NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; - secnotice("pinningQA", "generic pinning disable = %d", [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]); - } - }); - }); - sec_action_perform(action); - - return pinningDisabled; -} - -- (NSDictionary * _Nullable) queryForDomain:(NSString *)domain { - if (!_queue) { (void)[self init]; } - if (!_db) { [self initializedDb]; } - - /* Check for general no-pinning setting */ - if ([self isPinningDisabled:nil]) { - return nil; - } - - /* parse the domain into suffix and 1st label */ - NSRange firstDot = [domain rangeOfString:@"."]; - if (firstDot.location == NSNotFound) { return nil; } // Probably not a legitimate domain name - __block NSString *firstLabel = [domain substringToIndex:firstDot.location]; - __block NSString *suffix = [domain substringFromIndex:(firstDot.location + 1)]; - -#if !TARGET_OS_WATCH - /* Search cache */ - NSDictionary *cacheResult = nil; - if ([self queryCacheForSuffix:suffix firstLabel:firstLabel results:&cacheResult]) { - return cacheResult; - } -#endif - - /* Cache miss. Perform SELECT */ - __block bool ok = true; - __block CFErrorRef error = NULL; - __block NSMutableArray *resultRules = [NSMutableArray array]; - __block NSString *resultName = nil; -#if !TARGET_OS_WATCH - __block NSMutableDictionary *newCacheEntry = [NSMutableDictionary dictionary]; -#endif - ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { - ok &= SecDbWithSQL(dbconn, selectDomainSQL, &error, ^bool(sqlite3_stmt *selectDomain) { - ok &= SecDbBindText(selectDomain, 1, [suffix UTF8String], [suffix length], SQLITE_TRANSIENT, &error); - ok &= SecDbStep(dbconn, selectDomain, &error, ^(bool *stop) { - @autoreleasepool { - /* Get the data from the entry */ - // First Label Regex - const uint8_t *regex = sqlite3_column_text(selectDomain, 0); - verify_action(regex, return); - NSString *regexStr = [NSString stringWithUTF8String:(const char *)regex]; - verify_action(regexStr, return); - NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regexStr - options:NSRegularExpressionCaseInsensitive - error:nil]; - verify_action(regularExpression, return); - // Policy name - const uint8_t *policyName = sqlite3_column_text(selectDomain, 1); - NSString *policyNameStr = [NSString stringWithUTF8String:(const char *)policyName]; - // Policies - NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectDomain, 2) length:sqlite3_column_bytes(selectDomain, 2)]; - verify_action(xmlPolicies, return); - id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; - verify_action(isNSArray(policies), return); - -#if !TARGET_OS_WATCH - /* Add to cache entry */ - [newCacheEntry setObject:@{(__bridge NSString*)kSecPinningDbKeyPolicyName:policyNameStr, - (__bridge NSString*)kSecPinningDbKeyRules:policies} - forKey:regularExpression]; -#endif - - /* Match the labelRegex */ - NSUInteger numMatches = [regularExpression numberOfMatchesInString:firstLabel - options:0 - range:NSMakeRange(0, [firstLabel length])]; - if (numMatches == 0) { - return; - } - secinfo("SecPinningDb", "found matching rule in DB for %@.%@", firstLabel, suffix); - - /* Check the policyName for no-pinning settings */ - if ([self isPinningDisabled:policyNameStr]) { - return; - } - - /* Add return data - * @@@ Assumes there is only one rule with matching suffix/label pairs. */ - [resultRules addObjectsFromArray:(NSArray *)policies]; - resultName = policyNameStr; - } - }); - return ok; - }); - }); - - if (!ok || error) { - secerror("SecPinningDb: error querying DB for hostname: %@", error); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error - withEventName:TrustdHealthAnalyticsEventDatabaseEvent - withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), - TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; -#endif // ENABLE_TRUSTD_ANALYTICS - CFReleaseNull(error); - } - -#if !TARGET_OS_WATCH - /* Add new cache entry to cache. */ - if ([newCacheEntry count] > 0) { - [self addSuffixToCache:suffix entry:newCacheEntry]; - } -#endif - - /* Return results if found */ - if ([resultRules count] > 0) { - NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, - (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; - return results; - } - return nil; -} - -- (NSDictionary * _Nullable) queryForPolicyName:(NSString *)policyName { - if (!_queue) { (void)[self init]; } - if (!_db) { [self initializedDb]; } - - /* Skip the "sslServer" policyName, which is not a pinning policy */ - if ([policyName isEqualToString:@"sslServer"]) { - return nil; - } - - /* Check for general no-pinning setting */ - if ([self isPinningDisabled:nil] || [self isPinningDisabled:policyName]) { - return nil; - } - - secinfo("SecPinningDb", "Fetching rules for policy named %@", policyName); - - /* Perform SELECT */ - __block bool ok = true; - __block CFErrorRef error = NULL; - __block NSMutableArray *resultRules = [NSMutableArray array]; - ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { - ok &= SecDbWithSQL(dbconn, selectPolicyNameSQL, &error, ^bool(sqlite3_stmt *selectPolicyName) { - ok &= SecDbBindText(selectPolicyName, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, &error); - ok &= SecDbStep(dbconn, selectPolicyName, &error, ^(bool *stop) { - @autoreleasepool { - secinfo("SecPinningDb", "found matching rule for %@ policy", policyName); - - /* Deserialize the policies and return */ - NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectPolicyName, 0) length:sqlite3_column_bytes(selectPolicyName, 0)]; - if (!xmlPolicies) { return; } - id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; - if (!isNSArray(policies)) { - return; - } - [resultRules addObjectsFromArray:(NSArray *)policies]; - } - }); - return ok; - }); - }); - - if (!ok || error) { - secerror("SecPinningDb: error querying DB for policyName: %@", error); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error - withEventName:TrustdHealthAnalyticsEventDatabaseEvent - withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), - TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; -#endif // ENABLE_TRUSTD_ANALYTICS - CFReleaseNull(error); - } - - if ([resultRules count] > 0) { - NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, - (__bridge NSString*)kSecPinningDbKeyPolicyName:policyName}; - return results; - } - return nil; -} - -@end - -/* C interfaces */ -static SecPinningDb *pinningDb = nil; -void SecPinningDbInitialize(void) { - /* Create the pinning object once per launch */ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - @autoreleasepool { - pinningDb = [[SecPinningDb alloc] init]; - __block CFErrorRef error = NULL; - BOOL ok = SecDbPerformRead([pinningDb db], &error, ^(SecDbConnectionRef dbconn) { - NSNumber *contentVersion = [pinningDb getContentVersion:dbconn error:&error]; - NSNumber *schemaVersion = [pinningDb getSchemaVersion:dbconn error:&error]; - secinfo("pinningDb", "Database Schema: %@ Content: %@", schemaVersion, contentVersion); - }); - if (!ok || error) { - secerror("SecPinningDb: unable to initialize db: %@", error); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error - withEventName:TrustdHealthAnalyticsEventDatabaseEvent - withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), - TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; -#endif // ENABLE_TRUSTD_ANALYTICS - } - CFReleaseNull(error); - } - }); -} - -CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef query) { - @autoreleasepool { - SecPinningDbInitialize(); - - NSDictionary *nsQuery = (__bridge NSDictionary*)query; - NSString *hostname = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyHostname]; - - NSDictionary *results = [pinningDb queryForDomain:hostname]; - if (results) { return CFBridgingRetain(results); } - NSString *policyName = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyPolicyName]; - results = [pinningDb queryForPolicyName:policyName]; - if (!results) { return nil; } - return CFBridgingRetain(results); - } -} - -#if !TARGET_OS_BRIDGE -bool SecPinningDbUpdateFromURL(NSURL *url, NSError **error) { - SecPinningDbInitialize(); - - return [pinningDb installDbFromURL:url error:error]; -} -#endif - -CFNumberRef SecPinningDbCopyContentVersion(void) { - @autoreleasepool { - __block CFErrorRef error = NULL; - __block NSNumber *contentVersion = nil; - BOOL ok = SecDbPerformRead([pinningDb db], &error, ^(SecDbConnectionRef dbconn) { - contentVersion = [pinningDb getContentVersion:dbconn error:&error]; - }); - if (!ok || error) { - secerror("SecPinningDb: unable to get content version: %@", error); - } - CFReleaseNull(error); - if (!contentVersion) { - contentVersion = [NSNumber numberWithInteger:0]; - } - return CFBridgingRetain(contentVersion); - } -} diff --git a/OSX/sec/securityd/SecPolicyServer.c b/OSX/sec/securityd/SecPolicyServer.c deleted file mode 100644 index 03775ed2..00000000 --- a/OSX/sec/securityd/SecPolicyServer.c +++ /dev/null @@ -1,3821 +0,0 @@ -/* - * Copyright (c) 2008-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "OTATrustUtilities.h" -#include "personalization.h" -#include - -#if !TARGET_OS_IPHONE -#include -#endif - -/* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */ -#ifndef DUMP_OCSPRESPONSES -#define DUMP_OCSPRESPONSES 0 -#endif - -#if DUMP_OCSPRESPONSES - -#include -#include - -static void secdumpdata(CFDataRef data, const char *name) { - int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666); - write(fd, CFDataGetBytePtr(data), CFDataGetLength(data)); - close(fd); -} - -#endif - - -/******************************************************** - ****************** SecPolicy object ******************** - ********************************************************/ - -static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix); -static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc); -static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc); -static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints); - -static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL; -static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL; - -static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID) -{ - CFArrayRef result = NULL; - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiRef) - { - return result; - } - - CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef); - CFRelease(otapkiRef); - - if (NULL == evToPolicyAnchorDigest) - { - return result; - } - - CFArrayRef roots = NULL; - CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID); - if (oid && evToPolicyAnchorDigest) - { - result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid); - if (roots && CFGetTypeID(result) != CFArrayGetTypeID()) - { - secerror("EVRoot.plist has non array value"); - result = NULL; - } - CFRelease(oid); - } - CFReleaseSafe(evToPolicyAnchorDigest); - return result; -} - - -bool SecPolicyIsEVPolicy(const DERItem *policyOID) { - return SecPolicyAnchorDigestsForEVPolicy(policyOID); -} - -static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate, - policy_set_t valid_policies) { - CFDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - bool isEV = false; - /* Ensure that this certificate is a valid anchor for one of the - certificate policy oids specified in the leaf. */ - CFDataRef digest = SecCertificateGetSHA1Digest(certificate); - policy_set_t ix; - bool good_ev_anchor = false; - for (ix = valid_policies; ix; ix = ix->oid_next) { - CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid); - if (digests && CFArrayContainsValue(digests, - CFRangeMake(0, CFArrayGetCount(digests)), digest)) { - secdebug("ev", "found anchor for policy oid"); - good_ev_anchor = true; - break; - } - } - require_action_quiet(good_ev_anchor, notEV, secnotice("ev", "anchor not in plist")); - - CFAbsoluteTime october2006 = 178761600; - if (SecCertificateNotValidBefore(certificate) >= october2006) { - require_action_quiet(SecCertificateVersion(certificate) >= 3, notEV, - secnotice("ev", "Anchor issued after October 2006 and is not v3")); - } - if (SecCertificateVersion(certificate) >= 3 - && SecCertificateNotValidBefore(certificate) >= october2006) { - const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); - require_action_quiet(bc && bc->isCA == true, notEV, - secnotice("ev", "Anchor has invalid basic constraints")); - SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); - require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) - == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV, - secnotice("ev", "Anchor has invalid key usage %u", ku)); - } - - /* At least RSA 2048 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); - require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); - const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; - const void *values[] = { rsaSize, ecSize }; - require_quiet(keySizes = CFDictionaryCreate(NULL, keys, values, 2, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), notEV); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "Anchor's public key is too weak for EV")); - - isEV = true; - -notEV: - CFReleaseNull(rsaSize); - CFReleaseNull(ecSize); - CFReleaseNull(keySizes); - return isEV; -} - -static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) { - CFMutableDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - bool isEV = false; - - const SecCECertificatePolicies *cp; - cp = SecCertificateGetCertificatePolicies(certificate); - require_action_quiet(cp && cp->numPolicies > 0, notEV, - secnotice("ev", "SubCA missing certificate policies")); - CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate); - require_action_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV, - secnotice("ev", "SubCA missing CRLDP")); - const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); - require_action_quiet(bc && bc->isCA == true, notEV, - secnotice("ev", "SubCA has invalid basic constraints")); - SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); - require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) - == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV, - secnotice("ev", "SubCA has invalid key usage %u", ku)); - - /* 6.1.5 Key Sizes */ - CFAbsoluteTime jan2011 = 315532800; - CFAbsoluteTime jan2014 = 410227200; - require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); - require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); - if (SecCertificateNotValidBefore(certificate) < jan2011 || - SecCertificateNotValidAfter(certificate) < jan2014) { - /* At least RSA 1024 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014")); - } else { - /* At least RSA 2028 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013")); - } - - /* 7.1.3 Algorithm Object Identifiers */ - CFAbsoluteTime jan2016 = 473299200; - if (SecCertificateNotValidBefore(certificate) > jan2016) { - /* SHA-2 only */ - require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, - notEV, secnotice("ev", "SubCA was issued with SHA-1 after 2015")); - } - - isEV = true; - -notEV: - CFReleaseNull(rsaSize); - CFReleaseNull(ecSize); - CFReleaseNull(keySizes); - return isEV; -} - -/******************************************************** - **************** SecPolicy Callbacks ******************* - ********************************************************/ -static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc, - CFStringRef key) { -} - -static void SecPolicyCheckIdLinkage(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - CFDataRef parentSubjectKeyID = NULL; - for (ix = count - 1; ix >= 0; --ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - /* If the previous certificate in the chain had a SubjectKeyID, - make sure it matches the current certificates AuthorityKeyID. */ - if (parentSubjectKeyID) { - /* @@@ According to RFC 2459 neither AuthorityKeyID nor - SubjectKeyID can be critical. Currenty we don't check - for this. */ - CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert); - if (authorityKeyID) { - if (!CFEqual(parentSubjectKeyID, authorityKeyID)) { - /* AuthorityKeyID doesn't match issuers SubjectKeyID. */ - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } - } - - parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert); - } -} - -static void SecPolicyCheckKeyUsage(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef xku = CFDictionaryGetValue(policy->_options, key); - if (!SecPolicyCheckCertKeyUsage(leaf, xku)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) { - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key); - if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -static void SecPolicyCheckBasicConstraints(SecPVCRef pvc, - CFStringRef key) { - //SecPolicyCheckBasicContraintsCommon(pvc, key, false); -} - -static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key); - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertNonEmptySubject(cert, pvcValue)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckSSLHostname(SecPVCRef pvc, - CFStringRef key) { - /* @@@ Consider what to do if the caller passes in no hostname. Should - we then still fail if the leaf has no dnsNames or IPAddresses at all? */ - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef hostName = (CFStringRef) - CFDictionaryGetValue(policy->_options, key); - if (!isString(hostName)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - bool dnsMatch = SecPolicyCheckCertSSLHostname(leaf, hostName); - - if (!dnsMatch) { - /* Hostname mismatch or no hostnames found in certificate. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key); - if (!isString(email)) { - /* We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - - if (!SecPolicyCheckCertEmail(leaf, email)) { - /* Hostname mismatch or no hostnames found in certificate. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -static void SecPolicyCheckTemporalValidity(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecCertificateIsValid(cert, verifyTime)) { - /* Intermediate certificate has expired. */ - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc, - CFStringRef key) { - CFIndex count = SecPVCGetCertificateCount(pvc); - if (count < 2) { - /* Can't check intermediates common name if there is no intermediate. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - return; - } - - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef commonName = - (CFStringRef)CFDictionaryGetValue(policy->_options, key); - if (!isString(commonName)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectCommonName(cert, commonName)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, - key); - if (!isString(common_name)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectCommonName(cert, common_name)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options, - key); - if (!isString(prefix)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert, prefix)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, - key); - if (!isString(common_name)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectCommonNameTEST(cert, common_name)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckNotValidBefore(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key); - if (!isDate(date)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertNotValidBefore(cert, date)) { - if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) - return; - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckChainLength(SecPVCRef pvc, - CFStringRef key) { - CFIndex count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFNumberRef chainLength = - (CFNumberRef)CFDictionaryGetValue(policy->_options, key); - CFIndex value; - if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() || - !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (value != count) { - /* Chain length doesn't match policy requirement. */ - if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) - return; - } -} - -static bool isDigestInPolicy(SecPVCRef pvc, CFStringRef key, CFDataRef digest) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - - bool foundMatch = false; - if (isData(value)) - foundMatch = CFEqual(digest, value); - else if (isArray(value)) - foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest); - else { - /* @@@ We only support Data and Array but we can't return an error here so. - we let the evaluation fail (not much help) and assert in debug. */ - assert(false); - } - - return foundMatch; -} - -static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) { - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); - CFDataRef anchorSHA256 = NULL; - anchorSHA256 = SecCertificateCopySHA256Digest(cert); - - if (!isDigestInPolicy(pvc, key, anchorSHA256)) { - SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA256, count-1, kCFBooleanFalse); - } - - CFReleaseNull(anchorSHA256); - return; -} - - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc, - CFStringRef key) { - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); - CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert); - - if (!isDigestInPolicy(pvc, key, anchorSHA1)) - if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, count-1, kCFBooleanFalse)) - return; - - return; -} - -/* - Check the SHA256 of SPKI of the first intermediate CA certificate in the path - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = NULL; - CFDataRef digest = NULL; - - if (SecPVCGetCertificateCount(pvc) < 2) { - SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse); - return; - } - - cert = SecPVCGetCertificateAtIndex(pvc, 1); - digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert); - - if (!isDigestInPolicy(pvc, key, digest)) { - SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 1, kCFBooleanFalse); - } - CFReleaseNull(digest); -} - -/* - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckAnchorApple(SecPVCRef pvc, - CFStringRef key) { - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); - SecAppleTrustAnchorFlags flags = 0; - - - bool foundMatch = SecIsAppleTrustAnchor(cert, flags); - - if (!foundMatch) - if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse)) - return; - - return; -} - - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options, - key); - if (!isString(org)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectOrganization(cert, org)) { - /* Leaf Subject Organization mismatch. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options, - key); - if (!isString(orgUnit)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert, orgUnit)) { - /* Leaf Subject Organization mismatch. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc, - CFStringRef key) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFArrayRef trustedServerNames = (CFArrayRef) - CFDictionaryGetValue(policy->_options, key); - /* No names specified means we accept any name. */ - if (!trustedServerNames) - return; - if (!isArray(trustedServerNames)) { - /* @@@ We can't return an error here and making the evaluation fail - won't help much either. */ - return; - } - - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - if (!SecPolicyCheckCertEAPTrustedServerNames(leaf, trustedServerNames)) { - /* Hostname mismatch or no hostnames found in certificate. */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = { -{ 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 }, -{ 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 }, -{ 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 }, -{ 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 }, -{ 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 }, -{ 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 }, -{ 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 }, -{ 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e }, -{ 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } }; - -static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = { - 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, - 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, - 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, - 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43, - 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, - 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, - 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31, - 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54, - 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45, - 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f, - 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e, - 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48, - 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45 -}; -static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151; - - -static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc, - CFStringRef key) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL; - - if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) && - (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer), - UTN_USERFirst_Hardware_Normalized_Issuer_len))) - { - CFDataRef serial = SecCertificateCopySerialNumberData(cert, NULL); - if (serial) { - CFIndex serial_length = CFDataGetLength(serial); - const uint8_t *serial_ptr = CFDataGetBytePtr(serial); - - while ((serial_length > 0) && (*serial_ptr == 0)) { - serial_ptr++; - serial_length--; - } - - if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) { - unsigned int i; - for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++) - { - if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i], - serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial))) - { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - CFReleaseSafe(serial); - return; - } - } - } - CFRelease(serial); - } - } - - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL != otapkiRef) - { - CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); - CFRelease(otapkiRef); - if (NULL != blackListedKeys) - { - /* Check for blacklisted intermediates keys. */ - CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); - if (dgst) - { - /* Check dgst against blacklist. */ - if (CFSetContainsValue(blackListedKeys, dgst)) - { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - CFRelease(dgst); - } - CFRelease(blackListedKeys); - } - } -} - -static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key) -{ - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL != otapkiRef) - { - CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef); - CFRelease(otapkiRef); - if (NULL != grayListedKeys) - { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - - CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); - if (dgst) - { - /* Check dgst against gray. */ - if (CFSetContainsValue(grayListedKeys, dgst)) - { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - CFRelease(dgst); - } - CFRelease(grayListedKeys); - } - } -} - -static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key) -{ - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - - if (!SecPolicyCheckCertLeafMarkerOid(cert, value)) { - // Don't use 'key' because that may be the legacy key (see ) - // Force because we may have gotten the legacy key instead of the new key in the policy - SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkerOid, 0, kCFBooleanFalse, true); - } -} - -static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key) -{ - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - - if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - - -/* - * The value is a dictionary. The dictionary contains keys indicating - * whether the value is for Prod or QA. The values are the same as - * in the options dictionary for SecPolicyCheckLeafMarkerOid. - */ -static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc, CFStringRef key) -{ - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFDictionaryRef value = CFDictionaryGetValue(policy->_options, key); - CFTypeRef prodValue = CFDictionaryGetValue(value, kSecPolicyLeafMarkerProd); - - if (!SecPolicyCheckCertLeafMarkerOid(cert, prodValue)) { - bool result = false; - if (!result) { - // Don't use 'key' because that may be the legacy key (see ) - // Force because we may have gotten the legacy key instead of the new key in the policy - SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkersProdAndQA, 0, kCFBooleanFalse, true); - } - } -} - -static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key) -{ - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - - for (ix = 1; ix < count - 1; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (SecCertificateHasMarkerExtension(cert, value)) - return; - } - // Don't use 'key' because that may be the legacy key (see ) - // Force because we may have gotten the legacy key instead of the new key in the policy - SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateMarkerOid, 0, kCFBooleanFalse, true); -} - -static void SecPolicyCheckIntermediateMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key) -{ - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - - for (ix = 1; ix < count - 1; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - } -} - -static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc, CFStringRef key) -{ - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef peku = CFDictionaryGetValue(policy->_options, key); - - for (ix = 1; ix < count - 1; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertExtendedKeyUsage(cert, peku)) { - SecPVCSetResult(pvc, key, ix, kCFBooleanFalse); - } - } -} - -static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc, CFStringRef key) -{ - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef organization = CFDictionaryGetValue(policy->_options, key); - - for (ix = 1; ix < count - 1; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertSubjectOrganization(cert, organization)) { - // Don't use 'key' because that may be the legacy key (see ) - // Force because we may have gotten the legacy key instead of the new key in the policy - SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateOrganization, ix, kCFBooleanFalse, true); - } - } -} - -static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key) -{ - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef country = CFDictionaryGetValue(policy->_options, key); - - for (ix = 1; ix < count - 1; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertSubjectCountry(cert, country)) { - // Don't use 'key' because that may be the legacy key (see ) - // Force because we may have gotten the legacy key instead of the new key in the policy - SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateCountry, ix, kCFBooleanFalse, true); - } - } -} - -/**************************************************************************** - *********************** New rfc5280 Chain Validation *********************** - ****************************************************************************/ - -#define POLICY_MAPPING 1 -#define POLICY_SUBTREES 1 - -/* rfc5280 basic cert processing. */ -static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, - CFStringRef key) { - /* Inputs */ - //cert_path_t path; - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */ - assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ - uint32_t n = (uint32_t)count; - - bool is_anchored = SecPathBuilderIsAnchored(pvc->builder); - bool is_anchor_trusted = false; - if (is_anchored) { - CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, n - 1); - if (CFArrayGetCount(constraints) == 0) { - /* Given that the path builder has already indicated the last cert in this chain has - * trust set on it, empty constraints means trusted. */ - is_anchor_trusted = true; - } else { - /* Determine whether constraints say to trust this cert for this PVC. */ - SecTrustSettingsResult tsResult = SecPVCGetTrustSettingsResult(pvc, SecCertificatePathVCGetCertificateAtIndex(path, n - 1), - constraints); - if (tsResult == kSecTrustSettingsResultTrustRoot || tsResult == kSecTrustSettingsResultTrustAsRoot) { - is_anchor_trusted = true; - } - } - } - - if (is_anchor_trusted) { - /* If the anchor is trusted we don't process the last cert in the - chain (root). */ - n--; - } else { - Boolean isSelfSigned = false; - (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path, n - 1), &isSelfSigned); - if (isSelfSigned) { - /* Add a detail for the root not being trusted. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted, - n - 1, kCFBooleanFalse, true)) { - return; - } - } else { - /* Add a detail for the missing intermediate. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckMissingIntermediate, - n - 1, kCFBooleanFalse, true)) { - return; - } - } - } - - CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc); - //policy_set_t user_initial_policy_set = NULL; - //trust_anchor_t anchor; - - /* Initialization */ -#if POLICY_SUBTREES - CFMutableArrayRef permitted_subtrees = NULL; - CFMutableArrayRef excluded_subtrees = NULL; - /* set the initial subtrees to the trusted anchor's subtrees, if it has them */ - SecCertificateRef anchor = SecCertificatePathVCGetRoot(path); - CFArrayRef anchor_permitted_subtrees = SecCertificateGetPermittedSubtrees(anchor); - if (is_anchor_trusted && anchor_permitted_subtrees) { - permitted_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_permitted_subtrees); - } else { - permitted_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - } - - CFArrayRef anchor_excluded_subtrees = SecCertificateGetExcludedSubtrees(anchor); - if (is_anchor_trusted && anchor_excluded_subtrees) { - excluded_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_excluded_subtrees); - } else { - excluded_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - } - - require_action_quiet(permitted_subtrees != NULL, errOut, - SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true)); - require_action_quiet(excluded_subtrees != NULL, errOut, - SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true)); -#endif - - if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) { - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckPolicyConstraints, 0, kCFBooleanFalse, true)) { - goto errOut; - } - } - -#if 0 - /* Path builder ensures we only get cert chains with proper issuer - chaining with valid signatures along the way. */ - algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm; - SecKeyRef working_public_key = anchor->public_key; - x500_name_t working_issuer_name = anchor->issuer_name; -#endif - uint32_t i, max_path_length = n; - SecCertificateRef cert = NULL; - for (i = 1; i <= n; ++i) { - /* Process Cert */ - cert = SecPVCGetCertificateAtIndex(pvc, n - i); - bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i); - - /* (a) Verify the basic certificate information. */ - /* @@@ Ensure that cert was signed with working_public_key_algorithm - using the working_public_key and the working_public_key_parameters. */ - - /* Already done by chain builder. */ - if (!SecCertificateIsValid(cert, verify_time)) { - if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, n - i, kCFBooleanFalse)) { - goto errOut; - } - } - if (SecCertificateIsWeakKey(cert)) { - if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, n - i, kCFBooleanFalse)) { - goto errOut; - } - } - if (!SecPolicyCheckCertWeakSignature(cert, NULL)) { - if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, n - i, kCFBooleanFalse)) { - goto errOut; - } - } - - /* @@@ cert.issuer == working_issuer_name. */ - -#if POLICY_SUBTREES - /* (b) (c) */ - if (!is_self_issued || i == n) { - bool found = false; - /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */ - if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) { - if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) { - secnotice("policy", "name in excluded subtrees"); - if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; } - } - } - /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */ - if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) { - if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) { - secnotice("policy", "name not in permitted subtrees"); - if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; } - } - } - } -#endif - /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */ - - /* If Last Cert in Path */ - if (i == n) - break; - - /* Prepare for Next Cert */ - /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */ - /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */ -#if POLICY_SUBTREES - /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables. - */ - CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert); - if (permitted_subtrees_in_cert) { - SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert); - } - - // could do something smart here to avoid inserting the exact same constraint - CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert); - if (excluded_subtrees_in_cert) { - CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert); - CFRange range = { 0, num_trees }; - CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range); - } -#endif - /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */ - - /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ - - /* (l) */ - if (!is_self_issued) { - if (max_path_length > 0) { - max_path_length--; - } else { - /* max_path_len exceeded, illegal. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsPathLen, - n - i, kCFBooleanFalse, true)) { - goto errOut; - } - } - } - /* (m) */ - const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(cert); - if (bc && bc->pathLenConstraintPresent - && bc->pathLenConstraint < max_path_length) { - max_path_length = bc->pathLenConstraint; - } - - /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ - /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ - - /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */ - if (SecCertificateHasUnknownCriticalExtension(cert)) { - /* Certificate contains one or more unknown critical extensions. */ - if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, n - i, kCFBooleanFalse)) { - goto errOut; - } - } - - if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) { - /* Certificate contains one or more known exensions where parsing failed. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, n-i, kCFBooleanFalse, true)) { - goto errOut; - } - } - - } /* end loop over certs in path */ - /* Wrap up */ - /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */ - /* (c) */ - /* (d) */ - /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the -working_public_key_algorithm are different, set the working_public_key_parameters to null. */ - /* (e) */ - /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */ - if (SecCertificateHasUnknownCriticalExtension(cert)) { - /* Certificate contains one or more unknown critical extensions. */ - if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, 0, kCFBooleanFalse)) { - goto errOut; - } - } - - if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) { - /* Certificate contains one or more known exensions where parsing failed. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, 0, kCFBooleanFalse, true)) { - goto errOut; - } - } - /* (g) done by SecCertificatePathVCVerifyPolicyTree */ - -errOut: - CFReleaseNull(permitted_subtrees); - CFReleaseNull(excluded_subtrees); -} - -static policy_set_t policies_for_cert(SecCertificateRef cert) { - policy_set_t policies = NULL; - const SecCECertificatePolicies *cp = - SecCertificateGetCertificatePolicies(cert); - size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; - for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { - policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier); - } - return policies; -} - -static void SecPolicyCheckEV(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - policy_set_t valid_policies = NULL; - - /* 6.1.7. Key Usage Purposes */ - if (count) { - CFAbsoluteTime jul2016 = 489024000; - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) { - /* Root CAs may not sign subscriber certificates after 30 June 2016. */ - if (SecPVCSetResultForced(pvc, key, - 0, kCFBooleanFalse, true)) { - return; - } - } - } - - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - policy_set_t policies = policies_for_cert(cert); - if (ix == 0) { - /* Subscriber */ - /* anyPolicy in the leaf isn't allowed for EV, so only init - valid_policies if we have real policies. */ - if (!policy_set_contains(policies, &oidAnyPolicy)) { - valid_policies = policies; - policies = NULL; - } - } else if (ix < count - 1) { - /* Subordinate CA */ - if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) { - secnotice("ev", "subordinate certificate is not ev"); - if (SecPVCSetResultForced(pvc, key, - ix, kCFBooleanFalse, true)) { - policy_set_free(valid_policies); - policy_set_free(policies); - return; - } - } - policy_set_intersect(&valid_policies, policies); - } else { - /* Root CA */ - if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) { - secnotice("ev", "anchor certificate is not ev"); - if (SecPVCSetResultForced(pvc, key, - ix, kCFBooleanFalse, true)) { - policy_set_free(valid_policies); - policy_set_free(policies); - return; - } - } - } - policy_set_free(policies); - if (!valid_policies) { - secnotice("ev", "valid_policies set is empty: chain not ev"); - /* If we ever get into a state where no policies are valid anymore - this can't be an ev chain. */ - if (SecPVCSetResultForced(pvc, key, - ix, kCFBooleanFalse, true)) { - return; - } - } - } - - policy_set_free(valid_policies); - - /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a -Subscriber MUST contain an OID defined by the CA in the certificate’s -certificatePolicies extension that: (i) indicates which CA policy statement relates -to that certificate, (ii) asserts the CA’s adherence to and compliance with these -Guidelines, and (iii), by pre-agreement with the Application Software Vendor, -marks the certificate as being an EV Certificate. -(b) EV Subordinate CA Certificates -(1) Certificates issued to Subordinate CAs that are not controlled by the issuing -CA MUST contain one or more OIDs defined by the issuing CA that -explicitly identify the EV Policies that are implemented by the Subordinate -CA; -(2) Certificates issued to Subordinate CAs that are controlled by the Root CA -MAY contain the special anyPolicy OID (2.5.29.32.0). -(c) Root CA Certificates Root CA Certificates SHOULD NOT contain the -certificatePolicies or extendedKeyUsage extensions. -*/ -} - - -/* - * MARK: Certificate Transparency support - */ -const CFStringRef kSecCTRetirementDateKey = CFSTR("expiry"); // For backwards compatibility, retirement date is represented with the "expiry" key -const CFStringRef kSecCTReadOnlyDateKey = CFSTR("frozen"); // For backwards compatibility, read-only date is represented with the "frozen" key -const CFStringRef kSecCTShardStartDateKey = CFSTR("start_inclusive"); -const CFStringRef kSecCTShardEndDateKey = CFSTR("end_exclusive"); -const CFStringRef kSecCTPublicKeyKey = CFSTR("key"); - -enum { - kSecCTEntryTypeCert = 0, - kSecCTEntryTypePreCert = 1, -}; - -/*** - -struct { - Version sct_version; // 1 byte - LogID id; // 32 bytes - uint64 timestamp; // 8 bytes - CtExtensions extensions; // 2 bytes len field, + n bytes data - digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature - Version sct_version; - SignatureType signature_type = certificate_timestamp; - uint64 timestamp; - LogEntryType entry_type; - select(entry_type) { - case x509_entry: ASN.1Cert; - case precert_entry: PreCert; - } signed_entry; - CtExtensions extensions; - }; -} SignedCertificateTimestamp; - -***/ - -#include - -static const -SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg) -{ - switch(alg) { - case SSL_SignatureAlgorithmRSA: - switch (hash) { - case SSL_HashAlgorithmSHA1: - return &CSSMOID_SHA1WithRSA; - case SSL_HashAlgorithmSHA256: - return &CSSMOID_SHA256WithRSA; - case SSL_HashAlgorithmSHA384: - return &CSSMOID_SHA384WithRSA; - default: - break; - } - case SSL_SignatureAlgorithmECDSA: - switch (hash) { - case SSL_HashAlgorithmSHA1: - return &CSSMOID_ECDSA_WithSHA1; - case SSL_HashAlgorithmSHA256: - return &CSSMOID_ECDSA_WithSHA256; - case SSL_HashAlgorithmSHA384: - return &CSSMOID_ECDSA_WithSHA384; - default: - break; - } - default: - break; - } - - return NULL; -} - - -static size_t SSLDecodeUint16(const uint8_t *p) -{ - return (p[0]<<8 | p[1]); -} - -static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len) -{ - p[0] = (len >> 8)&0xff; - p[1] = (len & 0xff); - return p+2; -} - -static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len) -{ - p[0] = (len >> 16)&0xff; - p[1] = (len >> 8)&0xff; - p[2] = (len & 0xff); - return p+3; -} - - -static -uint64_t SSLDecodeUint64(const uint8_t *p) -{ - uint64_t u = 0; - for(int i=0; i<8; i++) { - u=(u<<8)|p[0]; - p++; - } - return u; -} - -#include -#include -#include - - -static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc) -{ - SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - - CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert)); - - CFDataSetLength(data, 3+SecCertificateGetLength(leafCert)); - - uint8_t *q = CFDataGetMutableBytePtr(data); - q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert)); - memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert)); - - return data; -} - - -static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc) -{ - SecCertificateRef leafCert = NULL; - SecCertificateRef issuer = NULL; - CFDataRef issuerKeyHash = NULL; - CFDataRef tbs_precert = NULL; - CFMutableDataRef data= NULL; - - require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. - leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - issuer = SecPVCGetCertificateAtIndex(pvc, 1); - - require(leafCert, out); - require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above. - issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer); - tbs_precert = SecCertificateCopyPrecertTBS(leafCert); - - require(issuerKeyHash, out); - require(tbs_precert, out); - data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); - CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); - - uint8_t *q = CFDataGetMutableBytePtr(data); - memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash - q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert)); - memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert)); - -out: - CFReleaseSafe(issuerKeyHash); - CFReleaseSafe(tbs_precert); - return data; -} - -static -CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts) -{ - return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970; -} - -static -uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at) -{ - return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000; -} - -static bool isSCTValidForLogData(CFDictionaryRef logData, int entry_type, CFAbsoluteTime sct_time, CFAbsoluteTime cert_expiry_date) { - /* only embedded SCTs can be used from retired logs. */ - if(entry_type==kSecCTEntryTypeCert && CFDictionaryContainsKey(logData, kSecCTRetirementDateKey)) { - return false; - } - - /* SCTs from after the transition to read-only are not valid (and indicate a operator failure) */ - CFDateRef frozen_date = CFDictionaryGetValue(logData, kSecCTReadOnlyDateKey); - if (frozen_date && (sct_time > CFDateGetAbsoluteTime(frozen_date))) { - secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData); - return false; - } - - /* If the log is temporally sharded, the certificate expiry date must be within the temporal shard window */ - CFDateRef start_inclusive = CFDictionaryGetValue(logData, kSecCTShardStartDateKey); - CFDateRef end_exclusive = CFDictionaryGetValue(logData, kSecCTShardEndDateKey); - if (start_inclusive && (cert_expiry_date < CFDateGetAbsoluteTime(start_inclusive))) { - return false; - } - if (end_exclusive && (cert_expiry_date >= CFDateGetAbsoluteTime(end_exclusive))) { - return false; - } - - return true; -} - - -/* - If the 'sct' is valid, add it to the validatingLogs dictionary. - - Inputs: - - validatingLogs: mutable dictionary to which to add the log that validate this SCT. - - sct: the SCT date - - entry_type: 0 for x509 cert, 1 for precert. - - entry: the cert or precert data. - - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch) - - trustedLog: Dictionary contain the Trusted Logs. - - The SCT is valid if: - - It decodes properly. - - Its timestamp is less than 'verifyTime'. - - It is signed by a log in 'trustedLogs'. - - If entry_type = 0, the log must be currently qualified. - - If entry_type = 1, the log may be expired. - - If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value. - If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier. - - */ -static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFAbsoluteTime cert_expiry_date, CFDictionaryRef trustedLogs, CFAbsoluteTime *sct_at) -{ - uint8_t version; - const uint8_t *logID; - const uint8_t *timestampData; - uint64_t timestamp; - size_t extensionsLen; - const uint8_t *extensionsData; - uint8_t hashAlg; - uint8_t sigAlg; - size_t signatureLen; - const uint8_t *signatureData; - SecKeyRef pubKey = NULL; - uint8_t *signed_data = NULL; - const SecAsn1Oid *oid = NULL; - SecAsn1AlgId algId; - CFDataRef logIDData = NULL; - CFDictionaryRef result = 0; - - const uint8_t *p = CFDataGetBytePtr(sct); - size_t len = CFDataGetLength(sct); - - require(len>=43, out); - - version = p[0]; p++; len--; - logID = p; p+=32; len-=32; - timestampData = p; p+=8; len-=8; - extensionsLen = SSLDecodeUint16(p); p+=2; len-=2; - - require(len>=extensionsLen, out); - extensionsData = p; p+=extensionsLen; len-=extensionsLen; - - require(len>=4, out); - hashAlg=p[0]; p++; len--; - sigAlg=p[0]; p++; len--; - signatureLen = SSLDecodeUint16(p); p+=2; len-=2; - require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */ - signatureData = p; - - /* verify version: only v1(0) is supported */ - if(version!=0) { - secerror("SCT version unsupported: %d\n", version); - goto out; - } - - /* verify timestamp not in the future */ - timestamp = SSLDecodeUint64(timestampData); - if(timestamp > vt) { - secerror("SCT is in the future: %llu > %llu\n", timestamp, vt); - goto out; - } - - uint8_t *q; - - /* signed entry */ - size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ; - signed_data = malloc(signed_data_len); - require(signed_data, out); - q = signed_data; - *q++ = version; - *q++ = 0; // certificate_timestamp - memcpy(q, timestampData, 8); q+=8; - q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert - memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry); - q = SSLEncodeUint16(q, extensionsLen); - memcpy(q, extensionsData, extensionsLen); - - logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull); - - CFDictionaryRef logData = CFDictionaryGetValue(trustedLogs, logIDData); - CFAbsoluteTime sct_time = TimestampToCFAbsoluteTime(timestamp); - require(logData && isSCTValidForLogData(logData, entry_type, sct_time, cert_expiry_date), out); - - CFDataRef logKeyData = CFDictionaryGetValue(logData, kSecCTPublicKeyKey); - require(logKeyData, out); // This failing would be an internal logic error - pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData); - require(pubKey, out); - - oid = oidForSigAlg(hashAlg, sigAlg); - require(oid, out); - - algId.algorithm = *oid; - algId.parameters.Data = NULL; - algId.parameters.Length = 0; - - if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) { - *sct_at = sct_time; - result = logData; - } else { - secerror("SCT signature failed (log=%@)\n", logData); - } - -out: - CFReleaseSafe(logIDData); - CFReleaseSafe(pubKey); - free(signed_data); - return result; -} - - -static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at) -{ - CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log); - - if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) { - CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at); - CFDictionarySetValue(validatingLogs, log, sct_time); - CFReleaseSafe(sct_time); - } -} - -static CFArrayRef copy_ocsp_scts(SecPVCRef pvc) -{ - CFMutableArrayRef SCTs = NULL; - SecCertificateRef leafCert = NULL; - SecCertificateRef issuer = NULL; - CFArrayRef ocspResponsesData = NULL; - SecOCSPRequestRef ocspRequest = NULL; - - ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder); - require_quiet(ocspResponsesData, out); - - require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. - leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - issuer = SecPVCGetCertificateAtIndex(pvc, 1); - - require(leafCert, out); - require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above. - ocspRequest = SecOCSPRequestCreate(leafCert, issuer); - - SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - require(SCTs, out); - - CFArrayForEach(ocspResponsesData, ^(const void *value) { - /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */ - SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); - if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) { - SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest); - if(ocspSingleResponse) { - CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse); - if(singleResponseSCTs) { - CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs))); - CFRelease(singleResponseSCTs); - } - SecOCSPSingleResponseDestroy(ocspSingleResponse); - } - } - if(ocspResponse) SecOCSPResponseFinalize(ocspResponse); - }); - - if(CFArrayGetCount(SCTs)==0) { - CFReleaseNull(SCTs); - } - -out: - CFReleaseSafe(ocspResponsesData); - if(ocspRequest) - SecOCSPRequestFinalize(ocspRequest); - - return SCTs; -} - -static void SecPolicyCheckCT(SecPVCRef pvc) -{ - SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert); - CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder); - CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); - CFArrayRef ocspScts = copy_ocsp_scts(pvc); - CFDataRef precertEntry = copy_precert_entry_from_chain(pvc); - CFDataRef x509Entry = copy_x509_entry_from_chain(pvc); - __block uint32_t trustedSCTCount = 0; - __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc); - __block CFAbsoluteTime certExpiry = SecCertificateNotValidAfter(leafCert); - TA_CTFailureReason failureReason = TA_CTNoFailure; - - if (!trustedLogs) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref); - CFReleaseSafe(otapkiref); - } - - // This eventually contain list of logs who validated the SCT. - CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc)); - - __block bool at_least_one_currently_valid_external = 0; - __block bool at_least_one_currently_valid_embedded = 0; - __block bool unknown_log = 0; - __block bool disqualified_log = 0; - - require(logsValidatingEmbeddedScts, out); - require(currentLogsValidatingScts, out); - - /* Skip if there are no SCTs. */ - bool no_scts = (embeddedScts && CFArrayGetCount(embeddedScts) > 0) || - (builderScts && CFArrayGetCount(builderScts) > 0) || - (ocspScts && CFArrayGetCount(ocspScts) > 0); - require_action_quiet(no_scts, out, - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); - if (analytics) { - analytics->ct_failure_reason = TA_CTNoSCTs; - } - ); - - if(trustedLogs && CFDictionaryGetCount(trustedLogs) > 0) { // Don't bother trying to validate SCTs if we don't have any trusted logs. - if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert. - CFArrayForEach(embeddedScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(logsValidatingEmbeddedScts, log, sct_at); - if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_embedded = true; - trustedSCTCount++; - } else { - disqualified_log = true; - } - } else { - unknown_log = true; - } - }); - } - - if(builderScts && x509Entry) { // Don't bother if we could not get the cert. - CFArrayForEach(builderScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_external = true; - trustedSCTCount++; - } else { - unknown_log = true; - } - }); - } - - if(ocspScts && x509Entry) { - CFArrayForEach(ocspScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_external = true; - trustedSCTCount++; - } else { - unknown_log = true; - } - }); - } - } else { - failureReason = TA_CTMissingLogs; - } - - - /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision. - - Current Policy: - is_ct = (A1 AND A2) OR (B1 AND B2). - - A1: embedded SCTs from 2+ to 5+ logs valid at issuance time - A2: At least one embedded SCT from a currently valid log. - - B1: SCTs from 2 currently valid logs (from any source) - B2: At least 1 external SCT from a currently valid log. - - */ - - bool hasValidExternalSCT = (at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2); - bool hasValidEmbeddedSCT = (at_least_one_currently_valid_embedded); - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - SecCertificatePathVCSetIsCT(path, false); - - if (hasValidEmbeddedSCT) { - /* Calculate issuance time based on timestamp of SCTs from current logs */ - CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) { - CFDictionaryRef log = key; - if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { - // Log is still qualified - CFDateRef ts = (CFDateRef) value; - CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts); - if(timestamp < issuanceTime) { - issuanceTime = timestamp; - } - } - }); - SecCertificatePathVCSetIssuanceTime(path, issuanceTime); - } - if (hasValidExternalSCT) { - /* Note: since external SCT validates this cert, we do not need to - override issuance time here. If the cert also has a valid embedded - SCT, issuanceTime will be calculated and set in the block above. */ - SecCertificatePathVCSetIsCT(path, true); - } else if (hasValidEmbeddedSCT) { - __block int lifetime; // in Months - __block unsigned once_or_current_qualified_embedded = 0; - - /* Count Logs */ - __block bool failed_once_check = false; - CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) { - CFDictionaryRef log = key; - CFDateRef ts = value; - CFDateRef expiry = CFDictionaryGetValue(log, kSecCTRetirementDateKey); - if (expiry == NULL) { // Currently qualified OR - once_or_current_qualified_embedded++; - } else if (CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan && // Once qualified. That is, qualified at the time of SCT AND - issuanceTime < CFDateGetAbsoluteTime(expiry)) { // at the time of issuance.) - once_or_current_qualified_embedded++; - trustedSCTCount++; - } else { - failed_once_check = true; - } - }); - - SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { - int _lifetime; - CFCalendarGetComponentDifference(zuluCalendar, - SecCertificateNotValidBefore(leafCert), - SecCertificateNotValidAfter(leafCert), - 0, "M", &_lifetime); - lifetime = _lifetime; - }); - - unsigned requiredEmbeddedSctsCount; - - if (lifetime < 15) { - requiredEmbeddedSctsCount = 2; - } else if (lifetime <= 27) { - requiredEmbeddedSctsCount = 3; - } else if (lifetime <= 39) { - requiredEmbeddedSctsCount = 4; - } else { - requiredEmbeddedSctsCount = 5; - } - - if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){ - SecCertificatePathVCSetIsCT(path, true); - } else { - /* Not enough "once or currently qualified" SCTs */ - if (failed_once_check) { - failureReason = TA_CTEmbeddedNotEnoughDisqualified; - } else if (unknown_log) { - failureReason = TA_CTEmbeddedNotEnoughUnknown; - } else { - failureReason = TA_CTEmbeddedNotEnough; - } - } - } else if (!at_least_one_currently_valid_embedded && !at_least_one_currently_valid_external) { - /* No currently valid SCTs */ - if (disqualified_log) { - failureReason = TA_CTNoCurrentSCTsDisqualifiedLog; - } else if (unknown_log) { - failureReason = TA_CTNoCurrentSCTsUnknownLog; - } - } else if (at_least_one_currently_valid_external) { - /* One presented current SCT but failed total current check */ - if (disqualified_log) { - failureReason = TA_CTPresentedNotEnoughDisqualified; - } else if (unknown_log) { - failureReason = TA_CTPresentedNotEnoughUnknown; - } else { - failureReason = TA_CTPresentedNotEnough; - } - } - - /* Record analytics data for CT */ - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); - require_quiet(analytics, out); - uint32_t sctCount = 0; - /* Count the total number of SCTs we found and report where we got them */ - if (embeddedScts && CFArrayGetCount(embeddedScts) > 0) { - analytics->sct_sources |= TA_SCTEmbedded; - sctCount += CFArrayGetCount(embeddedScts); - } - if (builderScts && CFArrayGetCount(builderScts) > 0) { - analytics->sct_sources |= TA_SCT_TLS; - sctCount += CFArrayGetCount(builderScts); - } - if (ocspScts && CFArrayGetCount(ocspScts) > 0) { - analytics->sct_sources |= TA_SCT_OCSP; - sctCount += CFArrayGetCount(ocspScts); - } - /* Report how many of those SCTs were once or currently qualified */ - analytics->number_trusted_scts = trustedSCTCount; - /* Report how many SCTs we got */ - analytics->number_scts = sctCount; - /* Why we failed */ - analytics->ct_failure_reason = failureReason; - /* Only one current SCT -- close to failure */ - if (CFDictionaryGetCount(currentLogsValidatingScts) == 1) { - analytics->ct_one_current = true; - } -out: - CFReleaseSafe(logsValidatingEmbeddedScts); - CFReleaseSafe(currentLogsValidatingScts); - CFReleaseSafe(builderScts); - CFReleaseSafe(embeddedScts); - CFReleaseSafe(ocspScts); - CFReleaseSafe(precertEntry); - CFReleaseSafe(trustedLogs); - CFReleaseSafe(x509Entry); -} - -static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - DERItem key_value; - key_value.data = (DERByte *)CFDataGetBytePtr(oid); - key_value.length = (DERSize)CFDataGetLength(oid); - - for (ix = 0; ix < count; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - policy_set_t policies = policies_for_cert(cert); - - if (policy_set_contains(policies, &key_value)) { - policy_set_free(policies); - return true; - } - policy_set_free(policies); - } - return false; -} - -static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc, CFStringRef key) -{ - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - bool result = false; - - if (CFGetTypeID(value) == CFDataGetTypeID()) - { - result = checkPolicyOidData(pvc, value); - } else if (CFGetTypeID(value) == CFStringGetTypeID()) { - CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value); - if (dataOid) { - result = checkPolicyOidData(pvc, dataOid); - CFRelease(dataOid); - } - } - if(!result) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - - -static void SecPolicyCheckRevocation(SecPVCRef pvc, - CFStringRef key) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - if (isString(value)) { - SecPathBuilderSetRevocationMethod(pvc->builder, value); - } -} - -static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc, - CFStringRef key) { - pvc->require_revocation_response = true; - secdebug("policy", "revocation response required"); -} - -static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) { - SecPathBuilderSetCheckRevocationOnline(pvc->builder); -} - -static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc, CFStringRef key) { - SecPathBuilderSetCheckRevocationIfTrusted(pvc->builder); -} - -static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc, - CFStringRef key) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); - if (value == kCFBooleanTrue) { - SecPathBuilderSetCanAccessNetwork(pvc->builder, false); - } else { - SecPathBuilderSetCanAccessNetwork(pvc->builder, true); - } -} - -static void SecPolicyCheckWeakKeySize(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (cert && SecCertificateIsWeakKey(cert)) { - /* Intermediate certificate has a weak key. */ - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } -} - -static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key); - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - - /* Don't check key size for user-anchored leafs */ -#if TARGET_OS_IPHONE - SecCertificateSourceRef userSource = kSecUserAnchorSource; -#else - SecCertificateSourceRef userSource = kSecLegacyAnchorSource; -#endif - if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) { - return; - } - - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } -} - -static void SecPolicyCheckWeakSignature(SecPVCRef pvc, CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key); - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecPolicyCheckCertWeakSignature(cert, pvcValue)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } -} - -static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc); - - /* Ignore (a non-self-signed) anchor if it's trusted by the user */ -#if TARGET_OS_IPHONE - bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1)); -#else - bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1)); -#endif - if (SecPathBuilderIsAnchored(pvc->builder) && userAnchored) { - count--; - } - - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key); - while (ix < count) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - /* note that these checks skip self-signed certs */ - if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - ix++; - } -} - -static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) { - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - require_quiet(leaf, out); - - /* And now a special snowflake from our tests */ - - /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */ - /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */ - /* Not After : May 26 09:37:50 2017 GMT */ - static const uint8_t vodafone[] = { - 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a, - 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18 - }; - - CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf); - require_quiet(leafFingerprint, out); - const unsigned int len = 20; - const uint8_t *dp = CFDataGetBytePtr(leafFingerprint); - if (dp && (!memcmp(vodafone, dp, len))) { - return true; - } - -out: - return false; -} - -static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key); - -static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - - Boolean keyInPolicy = false; - CFArrayRef policies = pvc->policies; - CFIndex policyIX, policyCount = CFArrayGetCount(policies); - for (policyIX = 0; policyIX < policyCount; ++policyIX) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); - if (policy && CFDictionaryContainsKey(policy->_options, key)) { - keyInPolicy = true; - } - } - - /* We only enforce this check when *both* of the following are true: - * 1. One of the certs in the path has this usage constraint, and - * 2. One of the policies in the PVC has this key - * (As compared to normal policy options which require only one to be true..) */ - require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) && - keyInPolicy, out); - - /* Ignore the anchor if it's trusted */ - if (SecPathBuilderIsAnchored(pvc->builder)) { - count--; - } - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (SecCertificateIsWeakHash(cert)) { - if (!leaf_is_on_weak_hash_whitelist(pvc)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { - return; - } - } - } - } -out: - return; -} - -static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc, - CFStringRef key) { - CFIndex ix, count = SecPVCGetCertificateCount(pvc); - - Boolean keyInPolicy = false; - CFArrayRef policies = pvc->policies; - CFIndex policyIX, policyCount = CFArrayGetCount(policies); - for (policyIX = 0; policyIX < policyCount; ++policyIX) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); - if (policy && CFDictionaryContainsKey(policy->_options, key)) { - keyInPolicy = true; - } - } - - /* We only enforce this check when *both* of the following are true: - * 1. One of the certs in the path has this usage constraint, and - * 2. One of the policies in the PVC has this key - * (As compared to normal policy options which require only one to be true..) */ - require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) && - keyInPolicy, out); - - /* Ignore the anchor if it's trusted */ - if (SecPathBuilderIsAnchored(pvc->builder)) { - count--; - } - for (ix = 0; ix < count; ++ix) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!SecCertificateIsStrongKey(cert)) { - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { - return; - } - } - - } /* Cert loop */ -out: - return; -} - -static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) { - /* Pinning is disabled on the system, skip. */ - if (SecIsInternalRelease()) { - if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"), - CFSTR("com.apple.security"), NULL)) { - return; - } - } - - CFArrayRef policies = pvc->policies; - CFIndex policyIX, policyCount = CFArrayGetCount(policies); - for (policyIX = 0; policyIX < policyCount; ++policyIX) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); - CFStringRef policyName = SecPolicyGetName(policy); - if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) { - /* policy required pinning, but we didn't use a pinning policy */ - if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) { - return; - } - } - } -} - -static bool is_configured_test_system_root(SecCertificateRef root, CFStringRef preference) { - if (!SecIsInternalRelease()) { - return false; - } - bool result = false; - CFDataRef rootHash = SecCertificateCopySHA256Digest(root); - CFTypeRef value = CFPreferencesCopyAppValue(preference, CFSTR("com.apple.security")); - require_quiet(isData(value), out); - require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out); - result = true; - -out: - CFReleaseNull(value); - CFReleaseNull(rootHash); - return result; -} - -static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) { - if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) { - /* exact match */ - return true; - } else if (CFStringHasPrefix(exception, CFSTR("."))) { - /* subdomains */ - CFIndex elength = CFStringGetLength(exception); - CFIndex hlength = CFStringGetLength(hostname); - if (hlength > elength) { - CFRange compareRange = { hlength - elength, elength }; - if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) { - return true; - } - } else if (hlength + 1 == elength) { - CFRange compareRange = { 1, hlength }; - if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) { - return true; - } - } - } - return false; -} - -static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { - if (gnType != GNT_DirectoryName) { - return errSecInternal; - } - - DERDecodedInfo subtreeName_content; - if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) { - return errSecDecode; - } - - CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content); - if (subtree_orgs) { - CFReleaseNull(subtree_orgs); - return errSecSuccess; - } - return errSecInternal; -} - -static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) { - __block bool result = false; - CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey); - - /* exception for a leaf is always allowed */ - SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0); - CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf); - if (CFEqualSafe(exceptionHash, spkiHash)) { - result = true; - } - CFReleaseNull(spkiHash); - - if (result) { return result; } - - /* exceptions for CAs */ - for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) { - SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX); - - spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca); - if (!CFEqualSafe(exceptionHash, spkiHash)) { - CFReleaseNull(spkiHash); - continue; - } - CFReleaseNull(spkiHash); - - /* this CA matches but exceptions for CAs have constraints */ - if (SecCertificateGetPermittedSubtrees(ca)) { - /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */ - CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) { - CFDataRef subtree = (CFDataRef)value; - const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) }; - DERDecodedInfo general_name_content; - if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) { - OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, - &general_name_content.content, - NULL, - is_subtree_dn_with_org); - if (status == errSecSuccess) { - result = true; - } - } - }); - } - - if (!result) { - /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */ - CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf); - CFArrayRef caOrgs = SecCertificateCopyOrganization(ca); - if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) { - result = true; - } - CFReleaseNull(leafOrgs); - CFReleaseNull(caOrgs); - } - - if (result) { - break; - } - } - - return result; -} - -static bool is_ct_excepted(SecPVCRef pvc) { - CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL); - if (!ct_exceptions) { - return false; - } - - __block bool result = false; - CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey); - if (domainExceptions) { - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); - if (hostname) { - CFArrayForEach(domainExceptions, ^(const void *value) { - result = result || is_ct_excepted_domain(hostname, value); - }); - } - } - if (result) { - secinfo("policy", "domain-based CT exception applied"); - CFReleaseNull(ct_exceptions); - return result; - } - - CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey); - if (keyExceptions) { - __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFArrayForEach(keyExceptions, ^(const void *value) { - result = result || has_ct_excepted_key(path, value); - }); - } - - if (result) { - secinfo("policy" , "key-based CT exceptions applied"); - } - - CFReleaseNull(ct_exceptions); - return result; -} - -/* some Apple servers not getting certs with embedded SCTs - * some Google apps have their own TLS stacks and aren't passing us TLS SCTs */ -static bool is_ct_allowlisted_ca(SecCertificatePathVCRef path) { - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlist"), CFSTR("com.apple.security"), NULL)) { - return false; - } - - /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */ - /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ - static const uint8_t appleISTCA8G1_spkiSHA256[] = { - 0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47, - 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3 - }; - - /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */ - /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ - static const uint8_t appleISTCA2G1_spkiSHA256[] = { - 0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e, - 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5 - }; - - /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */ - /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */ - static const uint8_t googleIAG3_spkiSHA256[] = { - 0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15, - 0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf - }; - - bool result = false; - for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) { - SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX); - - bool allowlistAppleCAs = true, allowlistGoogleCA = true; - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistApple"), CFSTR("com.apple.security"), NULL)) { - allowlistAppleCAs = false; - } - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistGoogle"), CFSTR("com.apple.security"), NULL)) { - allowlistGoogleCA = false; - } - - CFDataRef caSPKIHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca); - const uint8_t *dp = CFDataGetBytePtr(caSPKIHash); - if (dp && allowlistAppleCAs && (!memcmp(appleISTCA8G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) || - !memcmp(appleISTCA2G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH))) { - result = true; - } - if (dp && allowlistGoogleCA && !memcmp(googleIAG3_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH)) { - result = true; - } - CFReleaseNull(caSPKIHash); - if (result) { - break; - } - } - return result; -} - -static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) { - SecCertificateSourceRef appleAnchorSource = NULL; - SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); - - /* Skip this check if we haven't done the CT checks yet */ - require_quiet(SecCertificatePathVCIsPathValidated(path), out); - - /* We only enforce this check when all of the following are true: - * 0. Kill Switch not enabled */ - require_quiet(!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT), out); - - /* 1. Not a pinning policy */ - SecPolicyRef policy = SecPVCGetPolicy(pvc); - require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out); - - /* 2. Device has checked in to MobileAsset for a current log list within the last 60 days. - * Or the caller passed in the trusted log list. */ - require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out); - - /* 3. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */ - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0 && - SecCertificateIsValid(leaf, SecPVCGetVerifyTime(pvc)), out); - - /* 4. Chain is anchored with root in the system anchor source but not the Apple anchor source - * with certain excepted CAs and configurable included CAs. */ - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); - appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false)); - require_quiet(SecPathBuilderIsAnchored(pvc->builder), out); - require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) && - appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) && - !is_ct_allowlisted_ca(path)) || - is_configured_test_system_root(root, CFSTR("TestCTRequiredSystemRoot")), out); - - if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) { - /* Set failure. By not using the Forced variant, we implicitly check that this - * policy had this options set. */ - SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse); - } - -out: - CFReleaseNull(trustedLogs); - CFReleaseNull(otaref); - if (appleAnchorSource) { - SecMemoryCertificateSourceDestroy(appleAnchorSource); - } -} - -static bool SecPolicyCheckSystemTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) { - CFAbsoluteTime jul2016 = 489024000.0; // 1 July 2016 00:00:00 UTC - CFAbsoluteTime mar2018 = 541555200.0; // 1 March 2018 00:00:00 UTC - if (notBefore < jul2016) { - /* Validity Period no greater than 60 months. - 60 months is no more than 5 years and 2 leap days (and 1 hour slip). */ - CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2) + 3600; - if (notAfter - notBefore > maxPeriod) { - secnotice("policy", "System-trusted leaf validity period is more than 60 months"); - return false; - } - } else if (notBefore < mar2018) { - /* Validity Period no greater than 39 months. - 39 months is no more than 3 years, 2 31-day months, - 1 30-day month, and 1 leap day (and 1 hour slip) */ - CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1) + 3600; - if (notAfter - notBefore > maxPeriod) { - secnotice("policy", "System-trusted leaf validity period longer than 39 months and issued after 30 June 2016"); - return false; - } - } else { - /* Validity Period no greater than 825 days (and 1 hour slip). */ - CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600; - if (notAfter - notBefore > maxPeriod) { - secnotice("policy", "System-trusted leaf validity period longer than 825 days and issued on or after 1 March 2018"); - return false; - } - } - return true; -} - -static bool SecPolicyCheckOtherTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) { - /* Check whether we will enforce the validity period maximum for a non-system trusted leaf. */ - if (SecIsInternalRelease()) { - if (CFPreferencesGetAppBooleanValue(CFSTR("IgnoreMaximumValidityPeriod"), - CFSTR("com.apple.security"), NULL)) { - return true; - } - } - CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC - if (notBefore > jul2019) { - /* Validity Period no greater than 825 days (and 1 hour slip). */ - CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600; - if (notAfter - notBefore > maxPeriod) { - secnotice("policy", "Non-system-trusted leaf validity period longer than 825 days and issued on or after 1 July 2019"); - return false; - } - } - return true; -} - -static void SecPolicyCheckValidityPeriodMaximums(SecPVCRef pvc, CFStringRef key) { - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - CFAbsoluteTime notAfter = SecCertificateNotValidAfter(leaf); - CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf); - - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); - if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) { - if (!SecPolicyCheckSystemTrustValidityPeriodMaximums(notBefore, notAfter)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - return; - } - - /* Don't check validity periods against maximums for user-anchored leafs */ -#if TARGET_OS_IPHONE - SecCertificateSourceRef userSource = kSecUserAnchorSource; -#else - SecCertificateSourceRef userSource = kSecLegacyAnchorSource; -#endif - if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) { - return; - } - - /* all other trust */ - if (!SecPolicyCheckOtherTrustValidityPeriodMaximums(notBefore, notAfter)) { - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } -} - -static void SecPolicyCheckServerAuthEKU(SecPVCRef pvc, CFStringRef key) { - /* The ExtendedKeyUsage check will verify a looser version of this check for all TLS server certs. - * Here we want to be stricter (enforcing that there is an EKU extension and that it contains the - * one true Server Auth EKU OID) for system and app anchors */ - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); - if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) { - /* all system-anchored chains must be compliant */ - if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - return; - } - - /* skip user/admin-anchored chains */ -#if TARGET_OS_IPHONE - SecCertificateSourceRef userSource = kSecUserAnchorSource; -#else - SecCertificateSourceRef userSource = kSecLegacyAnchorSource; -#endif - if (SecPVCIsAnchorPerConstraints(pvc, userSource, root)) { - return; - } - - /* All other anchor types must be compliant if issued on or after 1 July 2019 */ - CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf); - CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC - if (notBefore > jul2019) { - if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - } -} - -void SecPolicyServerInitialize(void) { - gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, NULL); - gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, NULL); - -#undef POLICYCHECKMACRO -#define __PC_ADD_CHECK_(NAME) -#define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME); -#define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME); - -#define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ -__PC_ADD_CHECK_##LEAFCHECK(NAME) \ -__PC_ADD_CHECK_##PATHCHECK(NAME) -#include "../Security/SecPolicyChecks.list" - - /* Some of these don't follow the naming conventions but are in the Pinning DB. - * fix policy check constant values */ - CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid); - CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA); - CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid); - CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry); - CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization); -} - -// MARK: - -// MARK: SecPVCRef -/******************************************************** - ****************** SecPVCRef Functions ***************** - ********************************************************/ - -void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) { - secdebug("alloc", "pvc %p", pvc); - // Weird logging policies crashes. - //secdebug("policy", "%@", policies); - - // Zero the pvc struct so only non-zero fields need to be explicitly set - memset(pvc, 0, sizeof(struct OpaqueSecPVC)); - pvc->builder = builder; - pvc->policies = policies; - if (policies) - CFRetain(policies); - pvc->result = kSecTrustResultUnspecified; - - CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail, - 1, &kCFTypeArrayCallBacks); - CFRelease(certDetail); -} - -void SecPVCDelete(SecPVCRef pvc) { - secdebug("alloc", "delete pvc %p", pvc); - CFReleaseNull(pvc->policies); - CFReleaseNull(pvc->details); - CFReleaseNull(pvc->leafDetails); -} - -void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) { - secdebug("policy", "%@", path); - pvc->policyIX = 0; - pvc->result = kSecTrustResultUnspecified; - CFReleaseNull(pvc->details); -} - -void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) { - pvc->policyIX = 0; - - /* Since we don't run the LeafChecks again, we need to preserve the - * result the leaf had. */ - CFIndex ix, pathLength = SecCertificatePathVCGetCount(path); - CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault, - pathLength, pvc->leafDetails); - for (ix = 1; ix < pathLength; ++ix) { - CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFArrayAppendValue(details, certDetail); - CFRelease(certDetail); - } - CFRetainAssign(pvc->details, details); - pvc->result = pvc->leafResult; - CFReleaseSafe(details); -} - -SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) { - return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX); -} - -static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { - return SecPathBuilderGetCertificateCount(pvc->builder); -} - -static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { - return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); -} - -static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { - return SecPathBuilderGetVerifyTime(pvc->builder); -} - -static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) { - CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder); - if (!exceptions) { return false; } - CFIndex exceptionsCount = CFArrayGetCount(exceptions); - - /* There are two types of exceptions: - * 1. Those that are built from SecTrustCopyExceptions, which are particular to the - * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary. - * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors. - */ -#if TARGET_OS_OSX - CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0); - /* Type 2 */ - if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) { - /* SHA1Digest not allowed */ - if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; } - /* Key excepted */ - if (CFDictionaryContainsKey(options, key)) { - /* Special case -- AnchorTrusted only for self-signed certs */ - if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) { - Boolean isSelfSigned = false; - SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); - if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) { - return false; - } - } - return true; - } else if (CFEqual(key, kSecPolicyCheckTemporalValidity) && CFDictionaryContainsKey(options, kSecPolicyCheckValidRoot)) { - /* Another special case - ValidRoot excepts Valid only for self-signed certs */ - Boolean isSelfSigned = false; - SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); - if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) { - return false; - } - return true; - } - } -#endif - - /* Type 1 */ - if (ix >= exceptionsCount) { return false; } - CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix); - - /* Compare the cert hash */ - if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; } - SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); - if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) { - return false; - } - - /* Key Excepted */ - CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key); - if (exceptionValue && CFEqual(value, exceptionValue)) { - /* Only change result if PVC is already ok */ - if (SecPVCIsOkResult(pvc)) { - // Chains that pass due to exceptions get Proceed result. - pvc->result = kSecTrustResultProceed; - } - return true; - } - - return false; -} - -static int32_t detailKeyToCssmErr(CFStringRef key) { - int32_t result = 0; - - if (CFEqual(key, kSecPolicyCheckSSLHostname)) { - result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH - } - else if (CFEqual(key, kSecPolicyCheckEmail)) { - result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND - } - else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) { - result = -2147409654; // CSSMERR_TP_CERT_EXPIRED - } - - return result; -} - -static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint); - -static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) { - bool result = false; - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); - - for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { - CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); - CFNumberRef allowedErrorNumber = NULL; - if (!isDictionary(constraint)) { - continue; - } - allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError); - int32_t allowedErrorValue = 0; - if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) { - continue; - } - - if (SecPVCMeetsConstraint(pvc, cert, constraint)) { - if (allowedErrorValue == detailKeyToCssmErr(key)) { - result = true; - break; - } - } - } - return result; -} - -static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) { - CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); - for (certIX = 0; certIX < certCount; certIX++) { - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); - CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); - for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { - CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); - if (!isDictionary(constraint)) { - continue; - } - - CFDictionaryRef policyOptions = NULL; - policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions); - if (policyOptions && isDictionary(policyOptions) && - CFDictionaryContainsKey(policyOptions, key)) { - return true; - } - } - } - return false; -} - -static SecTrustResultType trust_result_for_key(CFStringRef key) { - SecTrustResultType result = kSecTrustResultRecoverableTrustFailure; -#undef POLICYCHECKMACRO -#define __PC_TYPE_MEMBER_ false -#define __PC_TYPE_MEMBER_R false -#define __PC_TYPE_MEMBER_F true -#define __PC_TYPE_MEMBER_D true - -#define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure -#define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure -#define __TRUSTRESULT_D kSecTrustResultDeny -#define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure - -#define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ -if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \ - result = __TRUSTRESULT_##TRUSTRESULT; \ -} -#include "../Security/SecPolicyChecks.list" - return result; -} - - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -bool SecPVCSetResultForced(SecPVCRef pvc, - CFStringRef key, CFIndex ix, CFTypeRef result, bool force) { - - /* If this is not something the current policy cares about ignore - this error and return true so our caller continues evaluation. */ - if (!force) { - /* Either the policy or the usage constraints have to have this key */ - SecPolicyRef policy = SecPVCGetPolicy(pvc); - if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) || - (policy && CFDictionaryContainsKey(policy->_options, key)))) { - return true; - } - } - - /* Check to see if the SecTrustSettings for the certificate in question - tell us to ignore this error. */ - if (SecPVCIsAllowedError(pvc, ix, key)) { - secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key); - return true; - } - - /* Check to see if exceptions tells us to ignore this error. */ - if (SecPVCIsExceptedError(pvc, ix, key, result)) { - secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key); - return true; - } - - secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key, - (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf" - : (pvc->callbacks == gSecPolicyPathCallbacks ? "path" - : "custom")), - (force ? "force" : ""), result); - - /* Avoid resetting deny or fatal to recoverable */ - SecTrustResultType trustResult = trust_result_for_key(key); - if (SecPVCIsOkResult(pvc) || trustResult == kSecTrustResultFatalTrustFailure) { - pvc->result = trustResult; - } else if (trustResult == kSecTrustResultDeny && - pvc->result == kSecTrustResultRecoverableTrustFailure) { - pvc->result = trustResult; - } - - if (!pvc->details) - return false; - - CFMutableDictionaryRef detail = - (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix); - if (!detail) { - secerror("SecPVCSetResultForced: failed to get detail at index %ld (array length %ld)", - ix, CFArrayGetCount(pvc->details)); - return false; - } - - /* Perhaps detail should have an array of results per key? As it stands - in the case of multiple policy failures the last failure stands. */ - CFDictionarySetValue(detail, key, result); - - return true; -} - -bool SecPVCSetResult(SecPVCRef pvc, - CFStringRef key, CFIndex ix, CFTypeRef result) { - return SecPVCSetResultForced(pvc, key, ix, result, false); -} - -/* AUDIT[securityd](done): - key(ok) is a caller provided. - value(ok, unused) is a caller provided. - */ -static void SecPVCValidateKey(const void *key, const void *value, - void *context) { - SecPVCRef pvc = (SecPVCRef)context; - - /* If our caller doesn't want full details and we failed earlier there is - no point in doing additional checks. */ - if (!SecPVCIsOkResult(pvc) && !pvc->details) - return; - - SecPolicyCheckFunction fcn = (SecPolicyCheckFunction) - CFDictionaryGetValue(pvc->callbacks, key); - - if (!fcn) { - /* "Optional" policy checks. This may be a new key from the - * pinning DB which is not implemented in this OS version. Log a - * warning, and on debug builds fail evaluation, to encourage us - * to ensure that checks are synchronized across the same build. */ - if (pvc->callbacks == gSecPolicyLeafCallbacks) { - if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) { - secwarning("policy: unknown policy key %@, skipping", key); -#if DEBUG - pvc->result = kSecTrustResultOtherError; -#endif - } - } else if (pvc->callbacks == gSecPolicyPathCallbacks) { - if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) { - secwarning("policy: unknown policy key %@, skipping", key); -#if DEBUG - pvc->result = kSecTrustResultOtherError; -#endif - } - } else { - /* Non standard validation phase, nothing is optional. */ - pvc->result = kSecTrustResultOtherError; - } - return; - } - - fcn(pvc, (CFStringRef)key); -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) { - /* We need to compute details for the leaf. */ - CFRetainAssign(pvc->details, pvc->leafDetails); - - CFArrayRef policies = pvc->policies; - CFIndex ix, count = CFArrayGetCount(policies); - for (ix = 0; ix < count; ++ix) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix); - pvc->policyIX = ix; - /* Validate all keys for all policies. */ - pvc->callbacks = gSecPolicyLeafCallbacks; - CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); - } - - pvc->leafResult = pvc->result; - CFRetainAssign(pvc->leafDetails, pvc->details); - - return pvc->result; -} - -bool SecPVCIsOkResult(SecPVCRef pvc) { - if (pvc->result == kSecTrustResultRecoverableTrustFailure || - pvc->result == kSecTrustResultDeny || - pvc->result == kSecTrustResultFatalTrustFailure || - pvc->result == kSecTrustResultOtherError) { - return false; - } - return true; -} - -bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) { - /* Check stuff common to intermediate and anchors. */ - CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1; - bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder)); - - if (!SecCertificateIsValid(cert, verifyTime)) { - /* Certificate has expired. */ - if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, ix, kCFBooleanFalse)) { - goto errOut; - } - } - - if (SecCertificateIsWeakKey(cert)) { - /* Certificate uses weak key. */ - if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, ix, kCFBooleanFalse)) { - goto errOut; - } - } - - if (!SecPolicyCheckCertWeakSignature(cert, NULL)) { - /* Certificate uses weak hash. */ - if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, ix, kCFBooleanFalse)) { - goto errOut; - } - } - - if (is_anchor) { - /* Perform anchor specific checks. */ - /* Don't think we have any of these. */ - } else { - /* Perform intermediate specific checks. */ - - /* (k) Basic constraints only relevant for v3 and later. */ - if (SecCertificateVersion(cert) >= 3) { - const SecCEBasicConstraints *bc = - SecCertificateGetBasicConstraints(cert); - if (!bc) { - /* Basic constraints not present, illegal. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, - ix, kCFBooleanFalse, true)) { - goto errOut; - } - } else if (!bc->isCA) { - /* Basic constraints not marked as isCA, illegal. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsCA, - ix, kCFBooleanFalse, true)) { - goto errOut; - } - } - } - /* For a v1 or v2 certificate in an intermediate slot (not a leaf and - not an anchor), we additionally require that the certificate chain - does not end in a v3 or later anchor. [rdar://32204517] */ - else if (ix > 0 && ix < anchor_ix) { - SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix); - if (SecCertificateVersion(anchor) >= 3) { - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, - ix, kCFBooleanFalse, true)) { - goto errOut; - } - } - } - /* (l) max_path_length is checked elsewhere. */ - - /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ - SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); - if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage, - ix, kCFBooleanFalse, true)) { - goto errOut; - } - } - } - -errOut: - return SecPVCIsOkResult(pvc); -} - -static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { - /* Check stuff common to intermediate and anchors. */ - - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL != otapkiRef) - { - CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); - CFRelease(otapkiRef); - if (NULL != blackListedKeys) - { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - CFIndex count = SecPVCGetCertificateCount(pvc); - bool is_last = (ix == count - 1); - bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); - if (!is_anchor) { - /* Check for blacklisted intermediate issuer keys. */ - CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); - if (dgst) { - /* Check dgst against blacklist. */ - if (CFSetContainsValue(blackListedKeys, dgst)) { - /* Check allow list for this blacklisted issuer key, - which is the authority key of the issued cert at ix-1. - */ - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - bool allowed = path && SecCertificatePathVCIsAllowlisted(path); - if (!allowed) { - SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, - ix, kCFBooleanFalse, true); - } - } - CFRelease(dgst); - } - } - CFRelease(blackListedKeys); - return SecPVCIsOkResult(pvc); - } - } - // Assume OK - return true; -} - -static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) -{ - /* Check stuff common to intermediate and anchors. */ - SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL != otapkiRef) - { - CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef); - CFRelease(otapkiRef); - if (NULL != grayListKeys) - { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - CFIndex count = SecPVCGetCertificateCount(pvc); - bool is_last = (ix == count - 1); - bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); - if (!is_anchor) { - /* Check for gray listed intermediate issuer keys. */ - CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); - if (dgst) { - /* Check dgst against gray list. */ - if (CFSetContainsValue(grayListKeys, dgst)) { - /* Check allow list for this graylisted issuer key, - which is the authority key of the issued cert at ix-1. - */ - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - bool allowed = path && SecCertificatePathVCIsAllowlisted(path); - if (!allowed) { - SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey, - ix, kCFBooleanFalse, true); - } - } - CFRelease(dgst); - } - } - CFRelease(grayListKeys); - return SecPVCIsOkResult(pvc); - } - } - // Assume ok - return true; -} - -static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) { - if (!isString(searchName) && !isString(searchOid)) { - return false; - } - CFArrayRef policies = pvc->policies; - CFIndex ix, count = CFArrayGetCount(policies); - for (ix = 0; ix < count; ++ix) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix); - CFStringRef policyName = SecPolicyGetName(policy); - CFStringRef policyOid = SecPolicyGetOidString(policy); - /* Prefer a match of both name and OID */ - if (searchOid && searchName && policyOid && policyName) { - if (CFEqual(searchOid, policyOid) && - CFEqual(searchName, policyName)) { - if (policyIX) { *policyIX = ix; } - return true; - } - /* sslServer trust settings need to apply to evals using policyName pinning - * but make sure we don't use this for SSL Client trust settings or policies. */ - if (CFEqual(searchOid, policyOid) && - CFEqual(searchName, kSecPolicyNameSSLServer) && !CFEqual(policyName, kSecPolicyNameSSLClient)) { - if (policyIX) { *policyIX = ix; } - return true; - } - } - /* Next best is just OID. */ - if (!searchName && searchOid && policyOid) { - if (CFEqual(searchOid, policyOid)) { - if (policyIX) { *policyIX = ix; } - return true; - } - } - if (!searchOid && searchName && policyName) { - if (CFEqual(searchName, policyName)) { - if (policyIX) { *policyIX = ix; } - return true; - } - } - } - return false; -} - -static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) { - if (!isString(stringValue)) { - return false; - } - bool result = false; - - /* Previous versions of macOS null-terminated the string, so we need to strip it. */ - CFStringRef tmpStringValue = NULL; - if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) { - tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1); - } else { - tmpStringValue = CFStringCreateCopy(NULL, stringValue); - } - /* Some users have strings that only contain the null-termination, so we need to check that we - * still have a string. */ - require(tmpStringValue, out); - - if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX); - /* Have to look for all the possible locations of name string */ - CFStringRef policyString = NULL; - policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); - if (!policyString) { - policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail); - } - if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) { - result = true; - goto out; - } - - CFArrayRef policyStrings = NULL; - policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames); - if (policyStrings && CFArrayContainsValue(policyStrings, - CFRangeMake(0, CFArrayGetCount(policyStrings)), - tmpStringValue)) { - result = true; - goto out; - } - } - -out: - CFReleaseNull(tmpStringValue); - return result; -} - - -static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) { - uint32_t ourTSKeyUsage = 0; - uint32_t keyUsage = 0; - if (keyUsageNumber && - CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) { - if (keyUsage & kSecKeyUsageDigitalSignature) { - ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature; - } - if (keyUsage & kSecKeyUsageDataEncipherment) { - ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData; - } - if (keyUsage & kSecKeyUsageKeyEncipherment) { - ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey; - } - if (keyUsage & kSecKeyUsageKeyAgreement) { - ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange; - } - if (keyUsage == kSecKeyUsageAll) { - ourTSKeyUsage = kSecTrustSettingsKeyUseAny; - } - } - return ourTSKeyUsage; -} - -static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) { - uint32_t ourTSKeyUsage = 0; - CFTypeRef policyKeyUsageType = NULL; - - policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage); - if (isArray(policyKeyUsageType)) { - CFIndex ix, count = CFArrayGetCount(policyKeyUsageType); - for (ix = 0; ix < count; ix++) { - CFNumberRef policyKeyUsageNumber = NULL; - policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix); - ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber); - } - } else if (isNumber(policyKeyUsageType)) { - ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType); - } - - return ourTSKeyUsage; -} - -static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc, - SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) { - int64_t keyUsageValue = 0; - uint32_t ourKeyUsage = 0; - - if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) { - return false; - } - - if (keyUsageValue == kSecTrustSettingsKeyUseAny) { - return true; - } - - /* We're using the key for revocation if we have the OCSPSigner policy. - * @@@ If we support CRLs, we'd need to check for that policy here too. - */ - if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) { - ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation; - } - - /* We're using the key for verifying a cert if it's a root/intermediate - * in the chain. If the cert isn't in the path yet, we're about to add it, - * so it's a root/intermediate. If there is no path, this is the leaf. - */ - CFIndex pathIndex = -1; - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - if (path) { - pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate); - } else { - pathIndex = 0; - } - if (pathIndex != 0) { - ourKeyUsage |= kSecTrustSettingsKeyUseSignCert; - } - - /* The rest of the key usages may be specified by the policy(ies). */ - if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX); - ourKeyUsage |= ts_key_usage_for_policy(policy); - } else { - /* Get key usage from ALL policies */ - CFIndex ix, count = CFArrayGetCount(pvc->policies); - for (ix = 0; ix < count; ix++) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix); - ourKeyUsage |= ts_key_usage_for_policy(policy); - } - } - - if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) { - return true; - } - - return false; -} - -#if TARGET_OS_OSX -#include -#include -#include -#include -#include - -extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); - -static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) { - bool result = false; - audit_token_t auditToken = {}; - SecTaskRef task = NULL; - SecRequirementRef requirement = NULL; - CFStringRef stringRequirement = NULL; - - require(appRef && clientAuditToken, out); - require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out); - require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out); - require(requirement, out); - require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out); - require(stringRequirement, out); - - require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); - CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); - require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); - - if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) { - result = true; - } - -out: - CFReleaseNull(task); - CFReleaseNull(requirement); - CFReleaseNull(stringRequirement); - return result; -} -#endif - -static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) { - if (!isDictionary(options)) { - return false; - } - - /* Push */ - CFDictionaryRef currentCallbacks = pvc->callbacks; - - /* We need to run the leaf and path checks using these options. */ - pvc->callbacks = gSecPolicyLeafCallbacks; - CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc); - - pvc->callbacks = gSecPolicyPathCallbacks; - CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc); - - /* Pop */ - pvc->callbacks = currentCallbacks; - - /* Our work here is done; no need to claim a match */ - return false; -} - -static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) { - CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL; - CFNumberRef keyUsageNumber = NULL; - CFTypeRef trustedApplicationData = NULL; - CFDictionaryRef policyOptions = NULL; - - bool policyMatch = false, policyStringMatch = false, applicationMatch = false , - keyUsageMatch = false, policyOptionMatch = false; - bool result = false; - -#if TARGET_OS_OSX - /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */ - SecPolicyRef policy = NULL; - policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy); - policyOid = (policy) ? policy->_oid : NULL; -#else - policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy); -#endif - policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName); - policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString); - keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage); - policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions); - - CFIndex policyIX = -1; - policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX); - policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString); - keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber); - policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions); - -#if TARGET_OS_OSX - trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication); - CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder); - applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData); - CFReleaseNull(clientAuditToken); -#else - if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) { - secerror("kSecTrustSettingsApplication is not yet supported on this platform"); - } -#endif - - /* If we either didn't find the parameter in the dictionary or we got a match - * against that parameter, for all possible parameters in the dictionary, then - * this trust setting result applies to the output. */ - if (((!policyOid && !policyName) || policyMatch) && - (!policyString || policyStringMatch) && - (!trustedApplicationData || applicationMatch) && - (!keyUsageNumber || keyUsageMatch) && - (!policyOptions || policyOptionMatch)) { - result = true; - } - - return result; -} - -static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) { - SecTrustSettingsResult result = kSecTrustSettingsResultInvalid; - CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); - for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { - CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); - if (!isDictionary(constraint)) { - continue; - } - - CFNumberRef resultNumber = NULL; - resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult); - uint32_t resultValue = kSecTrustSettingsResultInvalid; - if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) { - /* no SecTrustSettingsResult entry defaults to TrustRoot*/ - resultValue = kSecTrustSettingsResultTrustRoot; - } - - if (SecPVCMeetsConstraint(pvc, certificate, constraint)) { - result = resultValue; - break; - } - } - return result; -} - -/* This function assumes that the input source is an anchor source */ -bool SecPVCIsAnchorPerConstraints(SecPVCRef pvc, SecCertificateSourceRef source, SecCertificateRef certificate) { - __block bool result = false; - CFArrayRef constraints = NULL; - constraints = SecCertificateSourceCopyUsageConstraints(source, certificate); - - /* Unrestricted certificates: - * -those that come from anchor sources with no constraints - * -self-signed certificates with empty contraints arrays - */ - Boolean selfSigned = false; - require(errSecSuccess == SecCertificateIsSelfSigned(certificate, &selfSigned), out); - if ((NULL == source->copyUsageConstraints) || - (constraints && (CFArrayGetCount(constraints) == 0) && selfSigned)) { - secinfo("trust", "unrestricted anchor%s", - (NULL == source->copyUsageConstraints) ? " source" : ""); - result = true; - goto out; - } - - /* Get the trust settings result for the PVC. Only one PVC need match to - * trigger the anchor behavior -- policy validation will handle whether the - * path is truly anchored for that PVC. */ - require_quiet(constraints, out); - SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid; - settingsResult = SecPVCGetTrustSettingsResult(pvc, - certificate, - constraints); - if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) || - (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) { - // For our purposes, this is an anchor. - secinfo("trust", "complex trust settings anchor"); - result = true; - } - - if (settingsResult == kSecTrustSettingsResultDeny) { - /* We consider denied certs "anchors" because the trust decision - is set regardless of building the chain further. The policy - validation will handle rejecting this chain. */ - secinfo("trust", "complex trust settings denied anchor"); - result = true; - } - -out: - CFReleaseNull(constraints); - return result; -} - -static void SecPVCCheckUsageConstraints(SecPVCRef pvc) { - CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); - for (certIX = 0; certIX < certCount; certIX++) { - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); - SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints); - - /* Set the pvc trust result based on the usage constraints and anchor source. */ - if (result == kSecTrustSettingsResultDeny) { - SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true); - } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot || - result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) { - /* If we already think the PVC is ok and this cert is from one of the user/ - * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints), - * all mean we should use the special "Proceed" trust result. */ -#if TARGET_OS_IPHONE - if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) && - SecCertificateSourceContains(kSecUserAnchorSource, cert)) -#else - if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) && - SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) -#endif - { - pvc->result = kSecTrustResultProceed; - } - } - } -} - -static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = { - 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C, - 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D -}; -static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = { - 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2, - 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16 -}; -static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = { - 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47, - 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08 -}; -static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = { - 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39, - 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54 -}; -static const UInt8 kWS_ECC[kSecPolicySHA256Size] = { - 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB, - 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02 -}; -static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = { - 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13, - 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA -}; -static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = { - 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37, - 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11 -}; -static const UInt8 kSC_G2[kSecPolicySHA256Size] = { - 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37, - 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95 -}; - -static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { - static CFSetRef sConstrainedRoots = NULL; - static dispatch_once_t _t; - dispatch_once(&_t, ^{ - const UInt8 *v_hashes[] = { - kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC, - kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot - }; - CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); - CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes); - for (ix=0; ix= 0 && !shouldDeny; certIX--) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); - CFDataRef sha256 = SecCertificateCopySHA256Digest(cert); - if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) { - /* matched a constrained root; check notBefore dates on all its children. */ - CFIndex childIX = certIX; - while (--childIX >= 0) { - SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX); - /* 1 Dec 2016 00:00:00 GMT */ - if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) { - SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true); - shouldDeny = true; - break; - } - } - } - CFReleaseNull(sha256); - } -} - -static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) { - if (!pvc || !pvc->policies) { - return false; - } - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); - if (!policy) { - return false; - } - CFStringRef policyName = SecPolicyGetName(policy); - if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) { - return true; - } - CFDictionaryRef options = policy->_options; - if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) { - return true; - } - return false; -} - -/* ASSUMPTIONS: - 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT, - so earliest issuance time has already been obtained from SCTs. - 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we - assume it was not set, and thus we did not have CT info. -*/ -static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) { - SecCertificatePathVCRef path = (pvc) ? SecPathBuilderGetPath(pvc->builder) : NULL; - if (!path) { - return; - } - /* If we are evaluating for a SSL server authentication policy, make sure - SCT issuance time is prior to the earliest not-after date constraint. - Note that CT will already be required if there is a not-after date - constraint present (set in SecRVCProcessValidDateConstraints). - */ - if (SecPVCIsSSLServerAuthenticationPolicy(pvc)) { - CFIndex ix, certCount = SecCertificatePathVCGetCount(path); - SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0); - CFAbsoluteTime earliestNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ - CFAbsoluteTime issuanceTime = SecCertificatePathVCIssuanceTime(path); - if (issuanceTime <= 0) { - /* if not set (or prior to 2001-01-01), use leaf's not-before time. */ - issuanceTime = SecCertificateNotValidBefore(certificate); - } - for (ix = 0; ix < certCount; ix++) { - SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix); - if (!rvc || !rvc->valid_info || !rvc->valid_info->hasDateConstraints || !rvc->valid_info->notAfterDate) { - continue; - } - /* Found CA certificate with a not-after date constraint. */ - CFAbsoluteTime caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate); - if (caNotAfter < earliestNotAfter) { - earliestNotAfter = caNotAfter; - } - if (issuanceTime > earliestNotAfter) { - /* Issuance time violates the not-after date constraint. */ - secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)", - issuanceTime, earliestNotAfter); - SecRVCSetValidDeterminedErrorResult(rvc); - break; - } - } - } - /* If path is CT validated, nothing further to do here. */ - if (SecCertificatePathVCIsCT(path)) { - return; - } - - /* Path is not CT validated, so check if CT was required. */ - SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path); - if (ctp <= kSecPathCTNotRequired || !SecPVCIsSSLServerAuthenticationPolicy(pvc)) { - return; - } - - /* We need to have a recent log list or the CT check may have failed due to the list being out of date. - * Also, honor the CT kill switch. */ - SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); - if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) && - SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable)) { - /* CT was required. Error is always set on leaf certificate. */ - SecPVCSetResultForced(pvc, kSecPolicyCheckCTRequired, - 0, kCFBooleanFalse, true); - if (ctp != kSecPathCTRequiredOverridable) { - /* Normally kSecPolicyCheckCTRequired is recoverable, - so need to manually change trust result here. */ - pvc->result = kSecTrustResultFatalTrustFailure; - } - } - CFReleaseNull(otaref); -} - -/* "Deep" copy the details array */ -static CFArrayRef CF_RETURNS_RETAINED SecPVCCopyDetailsArray(SecPVCRef pvc) { - CFArrayRef details = pvc->details; - CFMutableArrayRef copiedDetails = CFArrayCreateMutable(NULL, CFArrayGetCount(details), &kCFTypeArrayCallBacks); - CFArrayForEach(details, ^(const void *value) { - CFMutableDictionaryRef copiedValue = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value); - CFArrayAppendValue(copiedDetails, copiedValue); - CFReleaseNull(copiedValue); - }); - return copiedDetails; -} - -/* AUDIT[securityd](done): - policy->_options is a caller provided dictionary, only its cf type has - been checked. - */ -void SecPVCPathChecks(SecPVCRef pvc) { - secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder)); - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - /* This needs to be initialized before we call any function that might call - SecPVCSetResultForced(). */ - pvc->policyIX = 0; - SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage); - if (SecPVCIsOkResult(pvc) || pvc->details) { - SecPolicyCheckBasicCertificateProcessing(pvc, - kSecPolicyCheckBasicCertificateProcessing); - } - - CFArrayRef policies = pvc->policies; - CFIndex count = CFArrayGetCount(policies); - for (; pvc->policyIX < count; ++pvc->policyIX) { - /* Validate all keys for all policies. */ - pvc->callbacks = gSecPolicyPathCallbacks; - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); - if (!SecPVCIsOkResult(pvc) && !pvc->details) - return; - } - - // Reset - pvc->policyIX = 0; - - /* Check whether the TrustSettings say to deny a cert in the path. */ - SecPVCCheckUsageConstraints(pvc); - - /* Check for Blocklisted certs */ - SecPVCCheckIssuerDateConstraints(pvc); - CFIndex ix; - count = SecCertificatePathVCGetCount(path); - for (ix = 1; ix < count; ix++) { - SecPVCGrayListedKeyChecks(pvc, ix); - SecPVCBlackListedKeyChecks(pvc, ix); - } - - /* Path-based check tests. */ - if (!SecCertificatePathVCIsPathValidated(path)) { - bool ev_check_ok = false; - if (SecCertificatePathVCIsOptionallyEV(path)) { - SecTrustResultType pre_ev_check_result = pvc->result; - CFArrayRef pre_ev_check_details = pvc->details ? SecPVCCopyDetailsArray(pvc) : NULL; - SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation); - ev_check_ok = SecPVCIsOkResult(pvc); - /* If ev checking failed, we still want to accept this chain - as a non EV one, if it was valid as such. */ - pvc->result = pre_ev_check_result; - CFAssignRetained(pvc->details, pre_ev_check_details); - } - - /* Check for CT */ - /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */ - SecPolicyCheckCT(pvc); - - /* Certs are only EV if they are also CT verified (when the Kill Switch isn't enabled and against a recent log list) */ - SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); - if (ev_check_ok && (SecCertificatePathVCIsCT(path) || SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) || - !SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable))) { - SecCertificatePathVCSetIsEV(path, true); - } - CFReleaseNull(otaref); - } - - /* Say that we did the expensive path checks (that we want to skip on the second call) */ - SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder)); - - /* Check that this path meets CT constraints. */ - SecPVCCheckRequireCTConstraints(pvc); - SecPolicyCheckSystemTrustedCTRequired(pvc); - - /* Check that this path meets known-intermediate constraints. */ - SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder); - - secdebug("policy", "end %strusted path: %@", - (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder)); - - return; -} - -void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc) { -#if TARGET_OS_WATCH - /* Since we don't currently allow networking on watchOS, - * don't enforce the revocation-required check here. (32728029) */ - bool required = false; -#else - bool required = true; -#endif - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - CFIndex ix, certCount = SecCertificatePathVCGetCount(path); - for (ix = 0; ix < certCount; ix++) { - SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix); - /* Do we have a valid revocation response? */ - if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) { - /* No valid revocation response. - * Do we require revocation (for that cert per the - * SecCertificateVCRef, or per the pvc)? */ - if (required && (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) || - ((ix == 0) && pvc->require_revocation_response))) { - SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired, - ix, kCFBooleanFalse, true); - } - /* Do we have a definitive Valid revocation result for this cert? */ - if (SecRVCHasDefinitiveValidInfo(rvc) && SecRVCHasRevokedValidInfo(rvc)) { - SecRVCSetValidDeterminedErrorResult(rvc); - } - } - } -} diff --git a/OSX/sec/securityd/SecPolicyServer.h b/OSX/sec/securityd/SecPolicyServer.h deleted file mode 100644 index 5c58babb..00000000 --- a/OSX/sec/securityd/SecPolicyServer.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008-2010,2012-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecPolicyServer - The functions provided in SecPolicyServer.h provide an interface to - trust policies dealing with certificate revocation. -*/ - -#ifndef _SECURITY_SECPOLICYSERVER_H_ -#define _SECURITY_SECPOLICYSERVER_H_ - -#include -#include "Security/SecPolicyInternal.h" -#include - -#include "securityd/SecTrustServer.h" -#include "securityd/SecCertificateServer.h" - -__BEGIN_DECLS - -#define kSecPolicySHA256Size 32 - -void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies); -void SecPVCDelete(SecPVCRef pvc); -void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path); -SecPolicyRef SecPVCGetPolicy(SecPVCRef pv); - -/* Set the string result as the reason for the sub policy check key - failing. The policy check function should continue processing if - this function returns true. */ -bool SecPVCSetResult(SecPVCRef pv, CFStringRef key, CFIndex ix, - CFTypeRef result); -bool SecPVCSetResultForced(SecPVCRef pvc, - CFStringRef key, CFIndex ix, CFTypeRef result, bool force); -bool SecPVCIsOkResult(SecPVCRef pvc); - -/* Is the current result considered successful. */ -bool SecPVCIsOkResult(SecPVCRef pvc); - -/* Compute details */ -void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path); - -/* Run static leaf checks on the path in pvc. */ -SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc); - -/* Run static parent checks on the path in pvc. */ -bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix); - -/* Run dynamic checks on the complete path in pvc. Return true if the - operation is complete, returns false if an async backgroup request was - scheduled. Upon completion of the async background job - SecPathBuilderStep() should be called. */ -void SecPVCPathChecks(SecPVCRef pvc); - -/* Check whether revocation responses were received for certificates - * in the path in pvc. If a valid response was not obtained for a - * certificate, this sets the appropriate error result if revocation - * was required, and/or definitive revocation info is present. */ -void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc); - -typedef void (*SecPolicyCheckFunction)(SecPVCRef pv, CFStringRef key); - -/* - * Used by SecTrust to verify if a particular certificate chain matches - * this policy. Returns true if the policy accepts the certificate chain. -*/ -bool SecPolicyValidate(SecPolicyRef policy, SecPVCRef pvc, CFStringRef key); - -void SecPolicyServerInitialize(void); - -bool SecPolicyIsEVPolicy(const DERItem *policyOID); - -bool SecPVCIsAnchorPerConstraints(SecPVCRef pvc, SecCertificateSourceRef source, SecCertificateRef certificate); - -__END_DECLS - -#endif /* !_SECURITY_SECPOLICYSERVER_H_ */ diff --git a/OSX/sec/securityd/SecRevocationDb.c b/OSX/sec/securityd/SecRevocationDb.c deleted file mode 100644 index 2e29051c..00000000 --- a/OSX/sec/securityd/SecRevocationDb.c +++ /dev/null @@ -1,3978 +0,0 @@ -/* - * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/* - * SecRevocationDb.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utilities/debugging.h" -#include "utilities/sec_action.h" -#include "utilities/sqlutils.h" -#include "utilities/SecAppleAnchorPriv.h" -#include "utilities/iOSforOSX.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - ============================================================================== - CoreFoundation utilities - ============================================================================== -*/ - -static bool hashCFThing(CFTypeRef thing, CC_SHA256_CTX* hash_ctx); - -/* comparison function for sorting dictionary keys alphabetically */ -static int compareCFStrings(const void *p, const void *q) { - CFStringRef str1 = *(CFStringRef *)p; - CFStringRef str2 = *(CFStringRef *)q; - if (!(isString(str1) && isString(str2))) { - return -1; /* can't compare non-string types */ - } - CFComparisonResult result = CFStringCompare(str1, str2, 0); - if (result == kCFCompareLessThan) { - return -1; - } else if (result == kCFCompareGreaterThan) { - return 1; - } - return 0; /* (result == kCFCompareEqualTo) */ -} - -static bool hashData(CFDataRef data, CC_SHA256_CTX* hash_ctx) { - if (!isData(data)) { return false; } - uint32_t length = (uint32_t)(CFDataGetLength(data) & 0xFFFFFFFF); - uint32_t n = OSSwapInt32(length); - CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); - const uint8_t *p = (uint8_t*)CFDataGetBytePtr(data); - if (p) { CC_SHA256_Update(hash_ctx, p, length); } - return (p != NULL); -} - -static bool hashString(CFStringRef str, CC_SHA256_CTX* hash_ctx) { - if (!isString(str)) { return false; } - __block bool ok = false; - CFStringPerformWithCString(str, ^(const char *strbuf) { - // hash string length (in bytes, not counting null terminator) - uint32_t c = (uint32_t)(strlen(strbuf) & 0xFFFFFFFF); - uint32_t n = OSSwapInt32(c); - CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); - // hash string bytes - CC_SHA256_Update(hash_ctx, strbuf, c); - ok = true; - }); - return ok; -} - -static bool hashNumber(CFNumberRef num, CC_SHA256_CTX* hash_ctx) { - uint32_t n = 0; - if (!isNumber(num) || !CFNumberGetValue(num, kCFNumberSInt32Type, &n)) { - return false; - } - n = OSSwapInt32(n); - CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); - return true; -} - -static bool hashBoolean(CFBooleanRef value, CC_SHA256_CTX* hash_ctx) { - if (!isBoolean(value)) { return false; } - uint8_t c = CFBooleanGetValue(value) ? 1 : 0; - CC_SHA256_Update(hash_ctx, &c, sizeof(uint8_t)); - return true; -} - -static bool hashArray(CFArrayRef array, CC_SHA256_CTX* hash_ctx) { - if (!isArray(array)) { return false; } - CFIndex count = CFArrayGetCount(array); - uint32_t n = OSSwapInt32(count & 0xFFFFFFFF); - CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); - __block bool ok = true; - CFArrayForEach(array, ^(const void *thing) { - ok &= hashCFThing(thing, hash_ctx); - }); - return ok; -} - -static bool hashDictionary(CFDictionaryRef dictionary, CC_SHA256_CTX* hash_ctx) { - if (!isDictionary(dictionary)) { return false; } - CFIndex count = CFDictionaryGetCount(dictionary); - const void **keys = (const void **)malloc(sizeof(void*) * count); - const void **vals = (const void **)malloc(sizeof(void*) * count); - bool ok = (keys && vals); - if (ok) { - CFDictionaryGetKeysAndValues(dictionary, keys, vals); - qsort(keys, count, sizeof(CFStringRef), compareCFStrings); - uint32_t n = OSSwapInt32(count & 0xFFFFFFFF); - CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); - } - for (CFIndex idx = 0; ok && idx < count; idx++) { - CFStringRef key = (CFStringRef)keys[idx]; - CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(dictionary, key); - ok &= hashString(key, hash_ctx); - ok &= hashCFThing(value, hash_ctx); - } - free(keys); - free(vals); - return ok; -} - -static bool hashCFThing(CFTypeRef thing, CC_SHA256_CTX* hash_ctx) { - if (isArray(thing)) { - return hashArray(thing, hash_ctx); - } else if (isDictionary(thing)) { - return hashDictionary(thing, hash_ctx); - } else if (isData(thing)) { - return hashData(thing, hash_ctx); - } else if (isString(thing)) { - return hashString(thing, hash_ctx); - } else if (isNumber(thing)) { - return hashNumber(thing, hash_ctx); - } else if (isBoolean(thing)) { - return hashBoolean(thing, hash_ctx); - } - return false; -} - -static double htond(double h) { - /* no-op if big endian */ - if (OSHostByteOrder() == OSBigEndian) { - return h; - } - double n; - size_t i=0; - char *hp = (char*)&h; - char *np = (char*)&n; - while (i < sizeof(h)) { np[i] = hp[(sizeof(h)-1)-i]; ++i; } - return n; -} - - -// MARK: - -// MARK: Valid definitions -/* - ============================================================================== - Valid definitions - ============================================================================== -*/ - -const CFStringRef kValidUpdateProdServer = CFSTR("valid.apple.com"); -const CFStringRef kValidUpdateSeedServer = CFSTR("valid.apple.com/seed"); -const CFStringRef kValidUpdateCarryServer = CFSTR("valid.apple.com/carry"); - -static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); -static CFStringRef kUpdateServerKey = CFSTR("ValidUpdateServer"); -static CFStringRef kUpdateEnabledKey = CFSTR("ValidUpdateEnabled"); -static CFStringRef kVerifyEnabledKey = CFSTR("ValidVerifyEnabled"); -static CFStringRef kUpdateIntervalKey = CFSTR("ValidUpdateInterval"); -static CFStringRef kBoolTrueKey = CFSTR("1"); -static CFStringRef kBoolFalseKey = CFSTR("0"); - -/* constant length of boolean string keys */ -#define BOOL_STRING_KEY_LENGTH 1 - -typedef CF_OPTIONS(CFOptionFlags, SecValidInfoFlags) { - kSecValidInfoComplete = 1u << 0, - kSecValidInfoCheckOCSP = 1u << 1, - kSecValidInfoKnownOnly = 1u << 2, - kSecValidInfoRequireCT = 1u << 3, - kSecValidInfoAllowlist = 1u << 4, - kSecValidInfoNoCACheck = 1u << 5, - kSecValidInfoOverridable = 1u << 6, - kSecValidInfoDateConstraints = 1u << 7, - kSecValidInfoNameConstraints = 1u << 8, - kSecValidInfoPolicyConstraints = 1u << 9, - kSecValidInfoNoCAv2Check = 1u << 10, -}; - -/* minimum update interval */ -#define kSecMinUpdateInterval (60.0 * 5) - -/* standard update interval */ -#define kSecStdUpdateInterval (60.0 * 60 * 3) - -/* maximum allowed interval */ -#define kSecMaxUpdateInterval (60.0 * 60 * 24 * 7) - -#define kSecRevocationBasePath "/Library/Keychains/crls" -#define kSecRevocationCurUpdateFile "update-current" -#define kSecRevocationDbFileName "valid.sqlite3" -#define kSecRevocationDbReplaceFile ".valid_replace" - -#define isDbOwner SecOTAPKIIsSystemTrustd - -#define kSecRevocationDbChanged "com.apple.trustd.valid.db-changed" - -/* database schema version - v1 = initial version - v2 = fix for group entry transitions - v3 = handle optional entries in update dictionaries - v4 = add db_format and db_source entries - v5 = add date constraints table, with updated group flags - v6 = explicitly set autovacuum and journal modes at db creation - v7 = add policies column to groups table (policy constraints) - - Note: kSecRevocationDbMinSchemaVersion is the lowest version whose - results can be used. This allows revocation results to be obtained - from an existing db before the next update interval occurs, at which - time we'll update to the current version (kSecRevocationDbSchemaVersion). -*/ -#define kSecRevocationDbSchemaVersion 7 /* current version we support */ -#define kSecRevocationDbMinSchemaVersion 7 /* minimum version we can use */ - -/* update file format -*/ -CF_ENUM(CFIndex) { - kSecValidUpdateFormatG1 = 1, /* initial version */ - kSecValidUpdateFormatG2 = 2, /* signed content, single plist */ - kSecValidUpdateFormatG3 = 3 /* signed content, multiple plists */ -}; - -#define kSecRevocationDbUpdateFormat 3 /* current version we support */ -#define kSecRevocationDbMinUpdateFormat 2 /* minimum version we can use */ - -#define kSecRevocationDbCacheSize 100 - -typedef struct __SecRevocationDb *SecRevocationDbRef; -struct __SecRevocationDb { - SecDbRef db; - dispatch_queue_t update_queue; - bool updateInProgress; - bool unsupportedVersion; - bool changed; - CFMutableArrayRef info_cache_list; - CFMutableDictionaryRef info_cache; - os_unfair_lock info_cache_lock; -}; - -typedef struct __SecRevocationDbConnection *SecRevocationDbConnectionRef; -struct __SecRevocationDbConnection { - SecRevocationDbRef db; - SecDbConnectionRef dbconn; - CFIndex precommitVersion; - CFIndex precommitDbVersion; - CFIndex precommitInterval; - bool fullUpdate; -}; - -bool SecRevocationDbVerifyUpdate(void *update, CFIndex length); -bool SecRevocationDbIngestUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex chunkVersion, CFIndex *outVersion, CFErrorRef *error); -bool _SecRevocationDbApplyUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex version, CFErrorRef *error); -CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval); -bool SecRevocationDbUpdateSchema(SecRevocationDbRef rdb); -CFIndex SecRevocationDbGetUpdateFormat(void); -bool _SecRevocationDbSetUpdateSource(SecRevocationDbConnectionRef dbc, CFStringRef source, CFErrorRef *error); -bool SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef source); -CFStringRef SecRevocationDbCopyUpdateSource(void); -bool SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate, CFErrorRef *error); -CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void); -dispatch_queue_t SecRevocationDbGetUpdateQueue(void); -bool _SecRevocationDbRemoveAllEntries(SecRevocationDbConnectionRef dbc, CFErrorRef *error); -void SecRevocationDbReleaseAllConnections(void); -static bool SecValidUpdateForceReplaceDatabase(void); -static void SecRevocationDbWith(void(^dbJob)(SecRevocationDbRef db)); -static bool SecRevocationDbPerformWrite(SecRevocationDbRef rdb, CFErrorRef *error, bool(^writeJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)); -static bool SecRevocationDbPerformRead(SecRevocationDbRef rdb, CFErrorRef *error, bool(^readJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)); -static SecValidInfoFormat _SecRevocationDbGetGroupFormat(SecRevocationDbConnectionRef dbc, int64_t groupId, SecValidInfoFlags *flags, CFDataRef *data, CFDataRef *policies, CFErrorRef *error); -static bool _SecRevocationDbSetUpdateInterval(SecRevocationDbConnectionRef dbc, int64_t interval, CFErrorRef *error); -static int64_t _SecRevocationDbGetUpdateInterval(SecRevocationDbConnectionRef dbc, CFErrorRef *error); -static bool _SecRevocationDbSetVersion(SecRevocationDbConnectionRef dbc, CFIndex version, CFErrorRef *error); -static int64_t _SecRevocationDbGetVersion(SecRevocationDbConnectionRef dbc, CFErrorRef *error); -static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef rdb, SecRevocationDbConnectionRef dbc, CFErrorRef *error); -static CFArrayRef _SecRevocationDbCopyHashes(SecRevocationDbConnectionRef dbc, CFErrorRef *error); -static bool _SecRevocationDbSetHashes(SecRevocationDbConnectionRef dbc, CFArrayRef hashes, CFErrorRef *error); -static void SecRevocationDbResetCaches(void); -static SecRevocationDbConnectionRef SecRevocationDbConnectionInit(SecRevocationDbRef db, SecDbConnectionRef dbconn, CFErrorRef *error); -static bool SecRevocationDbComputeDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error); - - -static CFDataRef copyInflatedData(CFDataRef data) { - if (!data) { - return NULL; - } - z_stream zs; - memset(&zs, 0, sizeof(zs)); - /* 32 is a magic value which enables automatic header detection - of gzip or zlib compressed data. */ - if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) { - return NULL; - } - zs.next_in = (UInt8 *)(CFDataGetBytePtr(data)); - zs.avail_in = (uInt)CFDataGetLength(data); - - CFMutableDataRef outData = CFDataCreateMutable(NULL, 0); - if (!outData) { - return NULL; - } - CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); - unsigned char *buf = malloc(buf_sz); - int rc; - do { - zs.next_out = (Bytef*)buf; - zs.avail_out = (uInt)buf_sz; - rc = inflate(&zs, 0); - CFIndex outLen = CFDataGetLength(outData); - if (outLen < (CFIndex)zs.total_out) { - CFDataAppendBytes(outData, (const UInt8*)buf, (CFIndex)zs.total_out - outLen); - } - } while (rc == Z_OK); - - inflateEnd(&zs); - free(buf); - if (rc != Z_STREAM_END) { - CFReleaseSafe(outData); - return NULL; - } - return (CFDataRef)outData; -} - -static CFDataRef copyDeflatedData(CFDataRef data) { - if (!data) { - return NULL; - } - z_stream zs; - memset(&zs, 0, sizeof(zs)); - if (deflateInit(&zs, Z_BEST_COMPRESSION) != Z_OK) { - return NULL; - } - zs.next_in = (UInt8 *)(CFDataGetBytePtr(data)); - zs.avail_in = (uInt)CFDataGetLength(data); - - CFMutableDataRef outData = CFDataCreateMutable(NULL, 0); - if (!outData) { - return NULL; - } - CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); - unsigned char *buf = malloc(buf_sz); - int rc = Z_BUF_ERROR; - do { - zs.next_out = (Bytef*)buf; - zs.avail_out = (uInt)buf_sz; - rc = deflate(&zs, Z_FINISH); - - if (rc == Z_OK || rc == Z_STREAM_END) { - CFIndex buf_used = buf_sz - zs.avail_out; - CFDataAppendBytes(outData, (const UInt8*)buf, buf_used); - } - else if (rc == Z_BUF_ERROR) { - free(buf); - buf_sz = malloc_good_size(buf_sz * 2); - buf = malloc(buf_sz); - if (buf) { - rc = Z_OK; /* try again with larger buffer */ - } - } - } while (rc == Z_OK && zs.avail_in); - - deflateEnd(&zs); - free(buf); - if (rc != Z_STREAM_END) { - CFReleaseSafe(outData); - return NULL; - } - return (CFDataRef)outData; -} - -/* Read file opens the file, mmaps it and then closes the file. */ -int readValidFile(const char *fileName, - CFDataRef *bytes) { // mmapped and returned -- must be munmapped! - int rtn, fd; - const uint8_t *buf = NULL; - struct stat sb; - size_t size = 0; - - *bytes = NULL; - fd = open(fileName, O_RDONLY); - if (fd < 0) { return errno; } - rtn = fstat(fd, &sb); - if (rtn) { goto errOut; } - if (sb.st_size > (off_t) ((UINT32_MAX >> 1)-1)) { - rtn = EFBIG; - goto errOut; - } - size = (size_t)sb.st_size; - - buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (!buf || buf == MAP_FAILED) { - rtn = errno; - secerror("unable to map %s (errno %d)", fileName, rtn); - goto errOut; - } - - *bytes = CFDataCreateWithBytesNoCopy(NULL, buf, size, kCFAllocatorNull); - -errOut: - close(fd); - if(rtn) { - CFReleaseNull(*bytes); - if (buf) { - int unmap_err = munmap((void *)buf, size); - if (unmap_err != 0) { - secerror("unable to unmap %ld bytes at %p (error %d)", (long)size, buf, rtn); - } - } - } - return rtn; -} - -static bool removeFileWithSuffix(const char *basepath, const char *suffix) { - bool result = false; - char *path = NULL; - asprintf(&path, "%s%s", basepath, suffix); - if (path) { - if (remove(path) == -1) { - int error = errno; - if (error == ENOENT) { - result = true; // not an error if the file did not exist - } else { - secnotice("validupdate", "remove (%s): %s", path, strerror(error)); - } - } else { - result = true; - } - free(path); - } - return result; -} - -static CFDataRef CF_RETURNS_RETAINED createPoliciesData(CFArrayRef policies) { - /* - * Given an array of CFNumber values (in the range 0..127), - * allocate and return a CFDataRef representation. Per Valid specification, - * a zero-length array is allowed, meaning no policies are permitted. - */ - CFIndex count = (policies) ? CFArrayGetCount(policies) : -1; - if (count < 0 || count > 127) { - return NULL; /* either no constraints, or far more than we expect. */ - } - CFDataRef data = NULL; - CFIndex length = 1 + (sizeof(int8_t) * count); - int8_t *bytes = malloc(length); - if (bytes) { - int8_t *p = bytes; - *p++ = (int8_t)(count & 0xFF); - for (CFIndex idx = 0; idx < count; idx++) { - int8_t pval = 0; - CFNumberRef value = (CFNumberRef)CFArrayGetValueAtIndex(policies, idx); - if (isNumber(value)) { - (void)CFNumberGetValue(value, kCFNumberSInt8Type, &pval); - } - *p++ = pval; - } - data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)bytes, length); - } - free(bytes); - return data; -} - -static CFDataRef CF_RETURNS_RETAINED cfToHexData(CFDataRef data, bool prependWildcard) { - if (!isData(data)) { return NULL; } - CFIndex len = CFDataGetLength(data) * 2; - CFMutableStringRef hex = CFStringCreateMutable(NULL, len+1); - static const char* digits[]={ - "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; - if (prependWildcard) { - CFStringAppendCString(hex, "%", 1); - } - const uint8_t* p = CFDataGetBytePtr(data); - for (CFIndex i = 0; i < CFDataGetLength(data); i++) { - CFStringAppendCString(hex, digits[p[i] >> 4], 1); - CFStringAppendCString(hex, digits[p[i] & 0xf], 1); - } - CFDataRef result = CFStringCreateExternalRepresentation(NULL, hex, kCFStringEncodingUTF8, 0); - CFReleaseSafe(hex); - return result; -} - -static bool copyFilterComponents(CFDataRef xmlData, CFDataRef * CF_RETURNS_RETAINED xor, - CFArrayRef * CF_RETURNS_RETAINED params) { - /* - The 'xmlData' parameter is a flattened XML dictionary, - containing 'xor' and 'params' keys. First order of - business is to reconstitute the blob into components. - */ - bool result = false; - CFRetainSafe(xmlData); - CFDataRef propListData = xmlData; - /* Expand data blob if needed */ - CFDataRef inflatedData = copyInflatedData(propListData); - if (inflatedData) { - CFReleaseSafe(propListData); - propListData = inflatedData; - } - CFDataRef xorData = NULL; - CFArrayRef paramsArray = NULL; - CFPropertyListRef nto1 = CFPropertyListCreateWithData(kCFAllocatorDefault, propListData, 0, NULL, NULL); - CFReleaseSafe(propListData); - if (nto1) { - xorData = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("xor")); - CFRetainSafe(xorData); - paramsArray = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("params")); - CFRetainSafe(paramsArray); - CFReleaseSafe(nto1); - } - result = (xorData && paramsArray); - if (xor) { - *xor = xorData; - } else { - CFReleaseSafe(xorData); - } - if (params) { - *params = paramsArray; - } else { - CFReleaseSafe(paramsArray); - } - return result; -} - -// MARK: - -// MARK: SecValidUpdate -/* - ============================================================================== - SecValidUpdate - ============================================================================== -*/ - -CFAbsoluteTime gUpdateStarted = 0.0; -CFAbsoluteTime gNextUpdate = 0.0; -static CFIndex gUpdateInterval = 0; -static CFIndex gLastVersion = 0; - -/* Update Format: - 1. The length of the signed data, as a 4-byte integer in network byte order. - 2. The signed data, which consists of: - a. A 4-byte integer in network byte order, the count of plists to follow; and then for each plist: - i. A 4-byte integer, the length of each plist - ii. A plist, in binary form - b. There may be other data after the plists in the signed data, described by a future version of this specification. - 3. The length of the following CMS blob, as a 4-byte integer in network byte order. - 4. A detached CMS signature of the signed data described above. - 5. There may be additional data after the CMS blob, described by a future version of this specification. - - Note: the difference between g2 and g3 format is the addition of the 4-byte count in (2a). -*/ -static bool SecValidUpdateProcessData(SecRevocationDbConnectionRef dbc, CFIndex format, CFDataRef updateData, CFErrorRef *error) { - bool result = false; - if (!updateData || format < 2) { - SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: invalid update format")); - return result; - } - CFIndex version = 0; - CFIndex interval = 0; - const UInt8* p = CFDataGetBytePtr(updateData); - size_t bytesRemaining = (p) ? (size_t)CFDataGetLength(updateData) : 0; - /* make sure there is enough data to contain length and count */ - if (bytesRemaining < ((CFIndex)sizeof(uint32_t) * 2)) { - secinfo("validupdate", "Skipping property list creation (length %ld is too short)", (long)bytesRemaining); - SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: data length is too short")); - return result; - } - /* get length of signed data */ - uint32_t dataLength = OSSwapInt32(*((uint32_t *)p)); - bytesRemaining -= sizeof(uint32_t); - p += sizeof(uint32_t); - - /* get plist count (G3 format and later) */ - uint32_t plistCount = 1; - uint32_t plistTotal = 1; - if (format > kSecValidUpdateFormatG2) { - plistCount = OSSwapInt32(*((uint32_t *)p)); - plistTotal = plistCount; - bytesRemaining -= sizeof(uint32_t); - p += sizeof(uint32_t); - } - if (dataLength > bytesRemaining) { - secinfo("validupdate", "Skipping property list creation (dataLength=%ld, bytesRemaining=%ld)", - (long)dataLength, (long)bytesRemaining); - SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: data longer than expected")); - return result; - } - - /* process each chunked plist */ - bool ok = true; - CFErrorRef localError = NULL; - uint32_t plistProcessed = 0; - while (plistCount > 0 && bytesRemaining > 0) { - CFPropertyListRef propertyList = NULL; - uint32_t plistLength = dataLength; - if (format > kSecValidUpdateFormatG2) { - plistLength = OSSwapInt32(*((uint32_t *)p)); - bytesRemaining -= sizeof(uint32_t); - p += sizeof(uint32_t); - } - --plistCount; - ++plistProcessed; - - if (plistLength <= bytesRemaining) { - CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, p, plistLength, kCFAllocatorNull); - propertyList = CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable, NULL, NULL); - CFReleaseNull(data); - } - if (isDictionary(propertyList)) { - secdebug("validupdate", "Ingesting plist chunk %u of %u, length: %u", - plistProcessed, plistTotal, plistLength); - CFIndex curVersion = -1; - ok = ok && SecRevocationDbIngestUpdate(dbc, (CFDictionaryRef)propertyList, version, &curVersion, &localError); - if (plistProcessed == 1) { - dbc->precommitVersion = version = curVersion; - // get server-provided interval - CFTypeRef value = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, - CFSTR("check-again")); - if (isNumber(value)) { - CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); - } - // get server-provided hash list - value = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, - CFSTR("hash")); - ok = _SecRevocationDbSetHashes(dbc, (CFArrayRef)value, &localError); - } - if (ok && curVersion < 0) { - plistCount = 0; // we already had this version; skip remaining plists - result = true; - } - } else { - secinfo("validupdate", "Failed to deserialize update chunk %u of %u", - plistProcessed, plistTotal); - SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: failed to get update chunk")); - if (plistProcessed == 1) { - gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); - } - } - /* All finished with this property list */ - CFReleaseSafe(propertyList); - - bytesRemaining -= plistLength; - p += plistLength; - } - - if (ok && version > 0) { - secdebug("validupdate", "Update received: v%ld", (long)version); - gLastVersion = version; - gNextUpdate = SecRevocationDbComputeNextUpdateTime(interval); - secdebug("validupdate", "Next update time: %f", gNextUpdate); - result = true; - } - - (void) CFErrorPropagate(localError, error); - return result; -} - -void SecValidUpdateVerifyAndIngest(CFDataRef updateData, CFStringRef updateServer, bool fullUpdate) { - if (!updateData) { - secnotice("validupdate", "invalid update data"); - return; - } - /* Verify CMS signature on signed data */ - if (!SecRevocationDbVerifyUpdate((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) { - secerror("failed to verify valid update"); - TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, errSecVerifyFailed); - return; - } - /* Read current update source from database. */ - CFStringRef dbSource = SecRevocationDbCopyUpdateSource(); - if (dbSource && updateServer && (kCFCompareEqualTo != CFStringCompare(dbSource, updateServer, - kCFCompareCaseInsensitive))) { - secnotice("validupdate", "switching db source from \"%@\" to \"%@\"", dbSource, updateServer); - } - CFReleaseNull(dbSource); - - /* Ingest the update. This is now performed under a single immediate write transaction, - so other writers are blocked (but not other readers), and the changes can be rolled back - in their entirety if any error occurs. */ - __block bool ok = true; - __block CFErrorRef localError = NULL; - SecRevocationDbWith(^(SecRevocationDbRef rdb) { - ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - if (fullUpdate) { - /* Must completely replace existing database contents */ - secdebug("validupdate", "starting to process full update; clearing database"); - ok = ok && _SecRevocationDbRemoveAllEntries(dbc, blockError); - ok = ok && _SecRevocationDbSetUpdateSource(dbc, updateServer, blockError); - dbc->precommitVersion = 0; - dbc->fullUpdate = true; - } - CFIndex startingVersion = dbc->precommitVersion; - ok = ok && SecValidUpdateProcessData(dbc, kSecValidUpdateFormatG3, updateData, blockError); - rdb->changed = ok && (startingVersion < dbc->precommitVersion); - if (!ok) { - secerror("failed to process valid update: %@", blockError ? *blockError : NULL); - TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, errSecDecode); - } else { - TrustdHealthAnalyticsLogSuccess(TAEventValidUpdate); - } - return ok; - }); - if (rdb->changed) { - rdb->changed = false; - bool verifyEnabled = false; - CFBooleanRef value = (CFBooleanRef)CFPreferencesCopyValue(kVerifyEnabledKey, - kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isBoolean(value)) { - verifyEnabled = CFBooleanGetValue(value); - } - CFReleaseNull(value); - if (verifyEnabled) { - /* compute and verify database content hashes */ - ok = ok && SecRevocationDbPerformRead(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - ok = ok && SecRevocationDbComputeDigests(dbc, blockError); - if (!ok) { - /* digests failed to verify, so roll back to known-good snapshot */ - (void) SecValidUpdateForceReplaceDatabase(); - } - return ok; - }); - } - /* signal other trustd instances that the database has been updated */ - notify_post(kSecRevocationDbChanged); - } - }); - - /* remember next update time in case of restart (separate write transaction) */ - (void) SecRevocationDbSetNextUpdateTime(gNextUpdate, NULL); - - CFReleaseSafe(localError); -} - -static bool SecValidUpdateForceReplaceDatabase(void) { - __block bool result = false; - - // write semaphore file that we will pick up when we next launch - WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbReplaceFile), ^(const char *utf8String) { - struct stat sb; - int fd = open(utf8String, O_WRONLY | O_CREAT, DEFFILEMODE); - if (fd == -1 || fstat(fd, &sb)) { - secnotice("validupdate", "unable to write %s (error %d)", utf8String, errno); - } else { - result = true; - } - if (fd >= 0) { - close(fd); - } - }); - if (result) { - // exit as gracefully as possible so we can replace the database - secnotice("validupdate", "process exiting to replace db file"); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - xpc_transaction_exit_clean(); - }); - } - return result; -} - -static bool SecValidUpdateSatisfiedLocally(CFStringRef server, CFIndex version, bool safeToReplace) { - __block bool result = false; - SecOTAPKIRef otapkiRef = NULL; - bool relaunching = false; - static int sNumLocalUpdates = 0; - - // if we've replaced the database with a local asset twice in a row, - // something is wrong with it. Get this update from the server. - if (sNumLocalUpdates > 1) { - secdebug("validupdate", "%d consecutive db resets, ignoring local asset", sNumLocalUpdates); - goto updateExit; - } - - // if a non-production server is specified, we will not be able to use a - // local production asset since its update sequence will be different. - if (kCFCompareEqualTo != CFStringCompare(server, kValidUpdateProdServer, - kCFCompareCaseInsensitive)) { - secdebug("validupdate", "non-production server specified, ignoring local asset"); - goto updateExit; - } - - // check static database asset(s) - otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (!otapkiRef) { - goto updateExit; - } - CFIndex assetVersion = SecOTAPKIGetValidSnapshotVersion(otapkiRef); - CFIndex assetFormat = SecOTAPKIGetValidSnapshotFormat(otapkiRef); - // version <= 0 means the database is invalid or empty. - // version > 0 means we have some version, but we need to see if a - // newer version is available as a local asset. - if (assetVersion <= version || assetFormat < kSecValidUpdateFormatG3) { - // asset is not newer than ours, or its version is unknown - goto updateExit; - } - - // replace database only if safe to do so (i.e. called at startup) - if (!safeToReplace) { - relaunching = SecValidUpdateForceReplaceDatabase(); - goto updateExit; - } - - // try to copy uncompressed database asset, if available - const char *validDbPathBuf = SecOTAPKIGetValidDatabaseSnapshot(otapkiRef); - if (validDbPathBuf) { - WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { - secdebug("validupdate", "will copy data from \"%s\"", validDbPathBuf); - copyfile_state_t state = copyfile_state_alloc(); - int retval = copyfile(validDbPathBuf, path, state, COPYFILE_DATA); - copyfile_state_free(state); - if (retval < 0) { - secnotice("validupdate", "copyfile error %d", retval); - } else { - result = true; - } - }); - } - -updateExit: - CFReleaseNull(otapkiRef); - if (result) { - sNumLocalUpdates++; - gLastVersion = SecRevocationDbGetVersion(); - // note: snapshot should already have latest schema and production source, - // but set it here anyway so we don't keep trying to replace the db. - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void)SecRevocationDbSetUpdateSource(db, server); - (void)SecRevocationDbUpdateSchema(db); - }); - gUpdateStarted = 0; - secdebug("validupdate", "local update to g%ld/v%ld complete at %f", - (long)SecRevocationDbGetUpdateFormat(), (long)gLastVersion, - (double)CFAbsoluteTimeGetCurrent()); - } else { - sNumLocalUpdates = 0; // reset counter - } - if (relaunching) { - // request is locally satisfied; don't schedule a network update - result = true; - } - return result; -} - -static bool SecValidUpdateSchedule(bool updateEnabled, CFStringRef server, CFIndex version) { - /* Check if we have a later version available locally */ - if (SecValidUpdateSatisfiedLocally(server, version, false)) { - return true; - } - - /* If update not permitted return */ - if (!updateEnabled) { - return false; - } - -#if !TARGET_OS_BRIDGE - /* Schedule as a maintenance task */ - secdebug("validupdate", "will fetch v%lu from \"%@\"", (unsigned long)version, server); - return SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); -#else - return false; -#endif -} - -static CFStringRef SecRevocationDbGetDefaultServer(void) { -#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE - #if RC_SEED_BUILD - CFStringRef defaultServer = kValidUpdateSeedServer; - #else // !RC_SEED_BUILD - CFStringRef defaultServer = kValidUpdateProdServer; - #endif // !RC_SEED_BUILD - if (os_variant_has_internal_diagnostics("com.apple.security")) { - defaultServer = kValidUpdateCarryServer; - } - return defaultServer; -#else // TARGET_OS_WATCH || TARGET_OS_BRIDGE - /* Because watchOS and bridgeOS can't update over the air, we should - * always use the prod server so that the valid database built into the - * image is used. */ - return kValidUpdateProdServer; -#endif -} - -void SecRevocationDbInitialize() { - if (!isDbOwner()) { return; } - os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.initialize"); - __block bool initializeDb = false; - - /* create base path if it doesn't exist */ - WithPathInRevocationInfoDirectory(NULL, ^(const char *utf8String) { - (void)mkpath_np(utf8String, 0755); - }); - - /* check semaphore file */ - WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbReplaceFile), ^(const char *path) { - struct stat sb; - if (stat(path, &sb) == 0) { - initializeDb = true; /* file was found, so we will replace the database */ - if (remove(path) == -1) { - int error = errno; - secnotice("validupdate", "remove (%s): %s", path, strerror(error)); - } - } - }); - - /* check database */ - WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { - if (initializeDb) { - /* remove old database file(s) */ - (void)removeFileWithSuffix(path, ""); - (void)removeFileWithSuffix(path, "-journal"); - (void)removeFileWithSuffix(path, "-shm"); - (void)removeFileWithSuffix(path, "-wal"); - } - else { - struct stat sb; - if (stat(path, &sb) == -1) { - initializeDb = true; /* file not found, so we will create the database */ - } - } - }); - - if (!initializeDb) { - os_release(transaction); - return; /* database exists and doesn't need replacing */ - } - - /* initialize database from local asset */ - CFTypeRef value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - CFStringRef server = (isString(value)) ? (CFStringRef)value : (CFStringRef)SecRevocationDbGetDefaultServer(); - CFIndex version = 0; - secnotice("validupdate", "initializing database"); - if (!SecValidUpdateSatisfiedLocally(server, version, true)) { -#if !TARGET_OS_BRIDGE - /* Schedule full update as a maintenance task */ - (void)SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); -#endif - } - CFReleaseSafe(value); - os_release(transaction); -} - - -// MARK: - -// MARK: SecValidInfoRef -/* - ============================================================================== - SecValidInfoRef - ============================================================================== -*/ - -CFGiblisWithCompareFor(SecValidInfo); - -static SecValidInfoRef SecValidInfoCreate(SecValidInfoFormat format, - CFOptionFlags flags, - bool isOnList, - CFDataRef certHash, - CFDataRef issuerHash, - CFDataRef anchorHash, - CFDateRef notBeforeDate, - CFDateRef notAfterDate, - CFDataRef nameConstraints, - CFDataRef policyConstraints) { - SecValidInfoRef validInfo; - validInfo = CFTypeAllocate(SecValidInfo, struct __SecValidInfo, kCFAllocatorDefault); - if (!validInfo) { return NULL; } - - CFRetainSafe(certHash); - CFRetainSafe(issuerHash); - CFRetainSafe(anchorHash); - CFRetainSafe(notBeforeDate); - CFRetainSafe(notAfterDate); - CFRetainSafe(nameConstraints); - CFRetainSafe(policyConstraints); - - validInfo->format = format; - validInfo->certHash = certHash; - validInfo->issuerHash = issuerHash; - validInfo->anchorHash = anchorHash; - validInfo->isOnList = isOnList; - validInfo->valid = (flags & kSecValidInfoAllowlist); - validInfo->complete = (flags & kSecValidInfoComplete); - validInfo->checkOCSP = (flags & kSecValidInfoCheckOCSP); - validInfo->knownOnly = (flags & kSecValidInfoKnownOnly); - validInfo->requireCT = (flags & kSecValidInfoRequireCT); - validInfo->noCACheck = (flags & kSecValidInfoNoCAv2Check); - validInfo->overridable = (flags & kSecValidInfoOverridable); - validInfo->hasDateConstraints = (flags & kSecValidInfoDateConstraints); - validInfo->hasNameConstraints = (flags & kSecValidInfoNameConstraints); - validInfo->hasPolicyConstraints = (flags & kSecValidInfoPolicyConstraints); - validInfo->notBeforeDate = notBeforeDate; - validInfo->notAfterDate = notAfterDate; - validInfo->nameConstraints = nameConstraints; - validInfo->policyConstraints = policyConstraints; - - return validInfo; -} - -static void SecValidInfoDestroy(CFTypeRef cf) { - SecValidInfoRef validInfo = (SecValidInfoRef)cf; - if (validInfo) { - CFReleaseNull(validInfo->certHash); - CFReleaseNull(validInfo->issuerHash); - CFReleaseNull(validInfo->anchorHash); - CFReleaseNull(validInfo->notBeforeDate); - CFReleaseNull(validInfo->notAfterDate); - CFReleaseNull(validInfo->nameConstraints); - CFReleaseNull(validInfo->policyConstraints); - } -} - -void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor) { - if (!validInfo) { - return; - } - CFDataRef anchorHash = NULL; - if (anchor) { - anchorHash = SecCertificateCopySHA256Digest(anchor); - - /* clear no-ca flag for anchors where we want OCSP checked [32523118] */ - if (SecIsAppleTrustAnchor(anchor, 0)) { - validInfo->noCACheck = false; - } - } - CFReleaseNull(validInfo->anchorHash); - validInfo->anchorHash = anchorHash; -} - -static Boolean SecValidInfoCompare(CFTypeRef a, CFTypeRef b) { - SecValidInfoRef validInfoA = (SecValidInfoRef)a; - SecValidInfoRef validInfoB = (SecValidInfoRef)b; - if (validInfoA == validInfoB) { - return true; - } - if (!validInfoA || !validInfoB || - (CFGetTypeID(a) != SecValidInfoGetTypeID()) || - (CFGetTypeID(b) != SecValidInfoGetTypeID())) { - return false; - } - return CFEqualSafe(validInfoA->certHash, validInfoB->certHash) && CFEqualSafe(validInfoA->issuerHash, validInfoB->issuerHash); -} - -static CFStringRef SecValidInfoCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - SecValidInfoRef validInfo = (SecValidInfoRef)cf; - CFStringRef certHash = CFDataCopyHexString(validInfo->certHash); - CFStringRef issuerHash = CFDataCopyHexString(validInfo->issuerHash); - CFStringRef desc = CFStringCreateWithFormat(NULL, formatOptions, CFSTR("validInfo certHash: %@ issuerHash: %@"), certHash, issuerHash); - CFReleaseNull(certHash); - CFReleaseNull(issuerHash); - return desc; -} - - -// MARK: - -// MARK: SecRevocationDb -/* - ============================================================================== - SecRevocationDb - ============================================================================== -*/ - -/* SecRevocationDbCheckNextUpdate returns true if we dispatched an - update request, otherwise false. -*/ -static bool _SecRevocationDbCheckNextUpdate(void) { - // are we the db owner instance? - if (!isDbOwner()) { - return false; - } - CFTypeRef value = NULL; - - // is it time to check? - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - CFAbsoluteTime minNextUpdate = now + gUpdateInterval; - gUpdateStarted = now; - - if (0 == gNextUpdate) { - // first time we're called, check if we have a saved nextUpdate value - gNextUpdate = SecRevocationDbGetNextUpdateTime(); - minNextUpdate = now; - if (gNextUpdate < minNextUpdate) { - gNextUpdate = minNextUpdate; - } - // allow pref to override update interval, if it exists - CFIndex interval = -1; - value = (CFNumberRef)CFPreferencesCopyValue(kUpdateIntervalKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isNumber(value)) { - if (CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval)) { - if (interval < kSecMinUpdateInterval) { - interval = kSecMinUpdateInterval; - } else if (interval > kSecMaxUpdateInterval) { - interval = kSecMaxUpdateInterval; - } - } - } - CFReleaseNull(value); - gUpdateInterval = kSecStdUpdateInterval; - if (interval > 0) { - gUpdateInterval = interval; - } - // pin next update time to the preferred update interval - if (gNextUpdate > (gUpdateStarted + gUpdateInterval)) { - gNextUpdate = gUpdateStarted + gUpdateInterval; - } - secdebug("validupdate", "next update at %f (in %f seconds)", - (double)gUpdateStarted, (double)gNextUpdate-gUpdateStarted); - } - if (gNextUpdate > now) { - gUpdateStarted = 0; - return false; - } - secnotice("validupdate", "starting update"); - - // set minimum next update time here in case we can't get an update - gNextUpdate = minNextUpdate; - - // determine which server to query - CFStringRef server; - value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isString(value)) { - server = (CFStringRef) CFRetain(value); - } else { - server = (CFStringRef) CFRetain(SecRevocationDbGetDefaultServer()); - } - CFReleaseNull(value); - - // determine version of our current database - CFIndex version = SecRevocationDbGetVersion(); - secdebug("validupdate", "got version %ld from db", (long)version); - if (version <= 0) { - if (gLastVersion > 0) { - secdebug("validupdate", "error getting version; using last good version: %ld", (long)gLastVersion); - } - version = gLastVersion; - } - - // determine source of our current database - // (if this ever changes, we will need to reload the db) - CFStringRef db_source = SecRevocationDbCopyUpdateSource(); - if (!db_source) { - db_source = (CFStringRef) CFRetain(kValidUpdateProdServer); - } - - // determine whether we need to recreate the database - CFIndex db_version = SecRevocationDbGetSchemaVersion(); - CFIndex db_format = SecRevocationDbGetUpdateFormat(); - if (db_version < kSecRevocationDbSchemaVersion || - db_format < kSecRevocationDbUpdateFormat || - kCFCompareEqualTo != CFStringCompare(server, db_source, kCFCompareCaseInsensitive)) { - // we need to fully rebuild the db contents, so we set our version to 0. - version = gLastVersion = 0; - } - - // determine whether update fetching is enabled -#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) - bool updateEnabled = true; // macOS 10.13 or iOS 11.0 -#else - bool updateEnabled = false; -#endif - value = (CFBooleanRef)CFPreferencesCopyValue(kUpdateEnabledKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isBoolean(value)) { - updateEnabled = CFBooleanGetValue((CFBooleanRef)value); - } - CFReleaseNull(value); - - // Schedule maintenance work - bool result = SecValidUpdateSchedule(updateEnabled, server, version); - CFReleaseNull(server); - CFReleaseNull(db_source); - return result; -} - -void SecRevocationDbCheckNextUpdate(void) { - static dispatch_once_t once; - static sec_action_t action; - - dispatch_once(&once, ^{ - dispatch_queue_t update_queue = SecRevocationDbGetUpdateQueue(); - action = sec_action_create_with_queue(update_queue, "update_check", kSecMinUpdateInterval); - sec_action_set_handler(action, ^{ - os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.checkNextUpdate"); - (void)_SecRevocationDbCheckNextUpdate(); - os_release(transaction); - }); - }); - sec_action_perform(action); -} - -/* This function verifies an update, in this format: - 1) unsigned 32-bit network-byte-order length of binary plist - 2) binary plist data - 3) unsigned 32-bit network-byte-order length of CMS message - 4) CMS message (containing certificates and signature over binary plist) - - The length argument is the total size of the packed update data. -*/ -bool SecRevocationDbVerifyUpdate(void *update, CFIndex length) { - if (!update || length <= (CFIndex)sizeof(uint32_t)) { - return false; - } - uint32_t plistLength = OSSwapInt32(*((uint32_t *)update)); - if ((plistLength + (CFIndex)(sizeof(uint32_t)*2)) > (uint64_t) length) { - secdebug("validupdate", "ERROR: reported plist length (%lu)+%lu exceeds total length (%lu)\n", - (unsigned long)plistLength, (unsigned long)sizeof(uint32_t)*2, (unsigned long)length); - return false; - } - uint8_t *plistData = (uint8_t *)update + sizeof(uint32_t); - uint8_t *sigData = (uint8_t *)plistData + plistLength; - uint32_t sigLength = OSSwapInt32(*((uint32_t *)sigData)); - sigData += sizeof(uint32_t); - if ((plistLength + sigLength + (CFIndex)(sizeof(uint32_t) * 2)) != (uint64_t) length) { - secdebug("validupdate", "ERROR: reported lengths do not add up to total length\n"); - return false; - } - - OSStatus status = 0; - CMSSignerStatus signerStatus; - CMSDecoderRef cms = NULL; - SecPolicyRef policy = NULL; - SecTrustRef trust = NULL; - CFDataRef content = NULL; - - if ((content = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, - (const UInt8 *)plistData, (CFIndex)plistLength, kCFAllocatorNull)) == NULL) { - secdebug("validupdate", "CFDataCreateWithBytesNoCopy failed (%ld bytes)\n", (long)plistLength); - return false; - } - - if ((status = CMSDecoderCreate(&cms)) != errSecSuccess) { - secdebug("validupdate", "CMSDecoderCreate failed with error %d\n", (int)status); - goto verifyExit; - } - if ((status = CMSDecoderUpdateMessage(cms, sigData, sigLength)) != errSecSuccess) { - secdebug("validupdate", "CMSDecoderUpdateMessage failed with error %d\n", (int)status); - goto verifyExit; - } - if ((status = CMSDecoderSetDetachedContent(cms, content)) != errSecSuccess) { - secdebug("validupdate", "CMSDecoderSetDetachedContent failed with error %d\n", (int)status); - goto verifyExit; - } - if ((status = CMSDecoderFinalizeMessage(cms)) != errSecSuccess) { - secdebug("validupdate", "CMSDecoderFinalizeMessage failed with error %d\n", (int)status); - goto verifyExit; - } - - policy = SecPolicyCreateApplePinned(CFSTR("ValidUpdate"), // kSecPolicyNameAppleValidUpdate - CFSTR("1.2.840.113635.100.6.2.10"), // System Integration 2 Intermediate Certificate - CFSTR("1.2.840.113635.100.6.51")); // Valid update signing OID - - // Check that the first signer actually signed this message. - if ((status = CMSDecoderCopySignerStatus(cms, 0, policy, - false, &signerStatus, &trust, NULL)) != errSecSuccess) { - secdebug("validupdate", "CMSDecoderCopySignerStatus failed with error %d\n", (int)status); - goto verifyExit; - } - // Make sure the signature verifies against the detached content - if (signerStatus != kCMSSignerValid) { - secdebug("validupdate", "ERROR: signature did not verify (signer status %d)\n", (int)signerStatus); - status = errSecInvalidSignature; - goto verifyExit; - } - // Make sure the signing certificate is valid for the specified policy - SecTrustResultType trustResult = kSecTrustResultInvalid; - status = SecTrustEvaluate(trust, &trustResult); - if (status != errSecSuccess) { - secdebug("validupdate", "SecTrustEvaluate failed with error %d (trust=%p)\n", (int)status, (void *)trust); - } else if (!(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) { - secdebug("validupdate", "SecTrustEvaluate failed with trust result %d\n", (int)trustResult); - status = errSecVerificationFailure; - goto verifyExit; - } - -verifyExit: - CFReleaseSafe(content); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(cms); - - return (status == errSecSuccess); -} - -CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval) { - CFIndex interval = updateInterval; - // try to use interval preference if it exists - CFTypeRef value = (CFNumberRef)CFPreferencesCopyValue(kUpdateIntervalKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isNumber(value)) { - CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); - } - CFReleaseNull(value); - - if (interval <= 0) { - interval = kSecStdUpdateInterval; - } - - // sanity check - if (interval < kSecMinUpdateInterval) { - interval = kSecMinUpdateInterval; - } else if (interval > kSecMaxUpdateInterval) { - interval = kSecMaxUpdateInterval; - } - - // compute randomization factor, between 0 and 50% of the interval - CFIndex fuzz = arc4random() % (long)(interval/2.0); - CFAbsoluteTime nextUpdate = CFAbsoluteTimeGetCurrent() + interval + fuzz; - secdebug("validupdate", "next update in %ld seconds", (long)(interval + fuzz)); - return nextUpdate; -} - -void SecRevocationDbComputeAndSetNextUpdateTime(void) { - gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); - (void) SecRevocationDbSetNextUpdateTime(gNextUpdate, NULL); - gUpdateStarted = 0; /* no update is currently in progress */ -} - -bool SecRevocationDbIngestUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex chunkVersion, CFIndex *outVersion, CFErrorRef *error) { - bool ok = false; - CFIndex version = 0; - CFErrorRef localError = NULL; - if (!update) { - SecError(errSecParam, &localError, CFSTR("SecRevocationDbIngestUpdate: invalid update parameter")); - goto setVersionAndExit; - } - CFTypeRef value = (CFNumberRef)CFDictionaryGetValue(update, CFSTR("version")); - if (isNumber(value)) { - if (!CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &version)) { - version = 0; - } - } - if (version == 0) { - // only the first chunk will have a version, so the second and - // subsequent chunks will need to pass it in chunkVersion. - version = chunkVersion; - } - // check precommitted version since update hasn't been committed yet - CFIndex curVersion = dbc->precommitVersion; - if (version > curVersion || chunkVersion > 0) { - ok = _SecRevocationDbApplyUpdate(dbc, update, version, &localError); - secdebug("validupdate", "_SecRevocationDbApplyUpdate=%s, v%ld, precommit=%ld, full=%s", - (ok) ? "1" : "0", (long)version, (long)dbc->precommitVersion, - (dbc->fullUpdate) ? "1" : "0"); - } else { - secdebug("validupdate", "we have v%ld, skipping update to v%ld", - (long)curVersion, (long)version); - version = -1; // invalid, so we know to skip subsequent chunks - ok = true; // this is not an error condition - } -setVersionAndExit: - if (outVersion) { - *outVersion = version; - } - (void) CFErrorPropagate(localError, error); - return ok; -} - - -/* Database schema */ - -/* admin table holds these key-value (or key-ival) pairs: - 'version' (integer) // version of database content - 'check_again' (double) // CFAbsoluteTime of next check (optional) - 'db_version' (integer) // version of database schema - 'db_hash' (blob) // SHA-256 database hash - --> entries in admin table are unique by text key - - issuers table holds map of issuing CA hashes to group identifiers: - groupid (integer) // associated group identifier in group ID table - issuer_hash (blob) // SHA-256 hash of issuer certificate (primary key) - --> entries in issuers table are unique by issuer_hash; - multiple issuer entries may have the same groupid! - - groups table holds records with these attributes: - groupid (integer) // ordinal ID associated with this group entry - flags (integer) // a bitmask of the following values: - kSecValidInfoComplete (0x00000001) set if we have all revocation info for this issuer group - kSecValidInfoCheckOCSP (0x00000002) set if must check ocsp for certs from this issuer group - kSecValidInfoKnownOnly (0x00000004) set if any CA from this issuer group must be in database - kSecValidInfoRequireCT (0x00000008) set if all certs from this issuer group must have SCTs - kSecValidInfoAllowlist (0x00000010) set if this entry describes valid certs (i.e. is allowed) - kSecValidInfoNoCACheck (0x00000020) set if this entry does not require an OCSP check to accept (deprecated) - kSecValidInfoOverridable (0x00000040) set if the trust status is recoverable and can be overridden - kSecValidInfoDateConstraints (0x00000080) set if this group has not-before or not-after constraints - kSecValidInfoNameConstraints (0x00000100) set if this group has name constraints in database - kSecValidInfoPolicyConstraints (0x00000200) set if this group has policy constraints in database - kSecValidInfoNoCAv2Check (0x00000400) set if this entry does not require an OCSP check to accept - format (integer) // an integer describing format of entries: - kSecValidInfoFormatUnknown (0) unknown format - kSecValidInfoFormatSerial (1) serial number, not greater than 20 bytes in length - kSecValidInfoFormatSHA256 (2) SHA-256 hash, 32 bytes in length - kSecValidInfoFormatNto1 (3) filter data blob of arbitrary length - data (blob) // Bloom filter data if format is 'nto1', otherwise NULL - policies (blob) // NULL, or uint8_t count value followed by array of int8_t policy values - --> entries in groups table are unique by groupid - - serials table holds serial number blobs with these attributes: - groupid (integer) // identifier for issuer group in the groups table - serial (blob) // serial number - --> entries in serials table are unique by serial and groupid - - hashes table holds SHA-256 hashes of certificates with these attributes: - groupid (integer) // identifier for issuer group in the groups table - sha256 (blob) // SHA-256 hash of subject certificate - --> entries in hashes table are unique by sha256 and groupid - - dates table holds notBefore and notAfter dates (as CFAbsoluteTime) with these attributes: - groupid (integer) // identifier for issuer group in the groups table (primary key) - notbefore (real) // issued certs are invalid if their notBefore is prior to this date - notafter (real) // issued certs are invalid after this date (or their notAfter, if earlier) - --> entries in dates table are unique by groupid, and only exist if kSecValidInfoDateConstraints is true - - */ -#define createTablesSQL CFSTR("CREATE TABLE IF NOT EXISTS admin(" \ - "key TEXT PRIMARY KEY NOT NULL," \ - "ival INTEGER NOT NULL," \ - "value BLOB" \ - ");" \ - "CREATE TABLE IF NOT EXISTS issuers(" \ - "groupid INTEGER NOT NULL," \ - "issuer_hash BLOB PRIMARY KEY NOT NULL" \ - ");" \ - "CREATE INDEX IF NOT EXISTS issuer_idx ON issuers(issuer_hash);" \ - "CREATE TABLE IF NOT EXISTS groups(" \ - "groupid INTEGER PRIMARY KEY AUTOINCREMENT," \ - "flags INTEGER," \ - "format INTEGER," \ - "data BLOB," \ - "policies BLOB" \ - ");" \ - "CREATE TABLE IF NOT EXISTS serials(" \ - "groupid INTEGER NOT NULL," \ - "serial BLOB NOT NULL," \ - "UNIQUE(groupid,serial)" \ - ");" \ - "CREATE TABLE IF NOT EXISTS hashes(" \ - "groupid INTEGER NOT NULL," \ - "sha256 BLOB NOT NULL," \ - "UNIQUE(groupid,sha256)" \ - ");" \ - "CREATE TABLE IF NOT EXISTS dates(" \ - "groupid INTEGER PRIMARY KEY NOT NULL," \ - "notbefore REAL," \ - "notafter REAL" \ - ");" \ - "CREATE TRIGGER IF NOT EXISTS group_del " \ - "BEFORE DELETE ON groups FOR EACH ROW " \ - "BEGIN " \ - "DELETE FROM serials WHERE groupid=OLD.groupid; " \ - "DELETE FROM hashes WHERE groupid=OLD.groupid; " \ - "DELETE FROM issuers WHERE groupid=OLD.groupid; " \ - "DELETE FROM dates WHERE groupid=OLD.groupid; " \ - "END;") - -#define selectGroupIdSQL CFSTR("SELECT DISTINCT groupid " \ - "FROM issuers WHERE issuer_hash=?") -#define selectVersionSQL CFSTR("SELECT ival FROM admin " \ - "WHERE key='version'") -#define selectDbVersionSQL CFSTR("SELECT ival FROM admin " \ - "WHERE key='db_version'") -#define selectDbFormatSQL CFSTR("SELECT ival FROM admin " \ - "WHERE key='db_format'") -#define selectDbHashSQL CFSTR("SELECT value FROM admin " \ - "WHERE key='db_hash'") -#define selectDbSourceSQL CFSTR("SELECT value FROM admin " \ - "WHERE key='db_source'") -#define selectNextUpdateSQL CFSTR("SELECT value FROM admin " \ - "WHERE key='check_again'") -#define selectUpdateIntervalSQL CFSTR("SELECT ival FROM admin " \ - "WHERE key='interval'") -#define selectGroupRecordSQL CFSTR("SELECT flags,format,data,policies " \ - "FROM groups WHERE groupid=?") -#define selectSerialRecordSQL CFSTR("SELECT rowid FROM serials " \ - "WHERE groupid=? AND serial=?") -#define selectDateRecordSQL CFSTR("SELECT notbefore,notafter FROM " \ - "dates WHERE groupid=?") -#define selectHashRecordSQL CFSTR("SELECT rowid FROM hashes " \ - "WHERE groupid=? AND sha256=?") -#define insertAdminRecordSQL CFSTR("INSERT OR REPLACE INTO admin " \ - "(key,ival,value) VALUES (?,?,?)") -#define insertIssuerRecordSQL CFSTR("INSERT OR REPLACE INTO issuers " \ - "(groupid,issuer_hash) VALUES (?,?)") -#define insertGroupRecordSQL CFSTR("INSERT OR REPLACE INTO groups " \ - "(groupid,flags,format,data,policies) VALUES (?,?,?,?,?)") -#define insertSerialRecordSQL CFSTR("INSERT OR REPLACE INTO serials " \ - "(groupid,serial) VALUES (?,?)") -#define deleteSerialRecordSQL CFSTR("DELETE FROM serials " \ - "WHERE groupid=? AND hex(serial) LIKE ?") -#define insertSha256RecordSQL CFSTR("INSERT OR REPLACE INTO hashes " \ - "(groupid,sha256) VALUES (?,?)") -#define deleteSha256RecordSQL CFSTR("DELETE FROM hashes " \ - "WHERE groupid=? AND hex(sha256) LIKE ?") -#define insertDateRecordSQL CFSTR("INSERT OR REPLACE INTO dates " \ - "(groupid,notbefore,notafter) VALUES (?,?,?)") -#define deleteGroupRecordSQL CFSTR("DELETE FROM groups " \ - "WHERE groupid=?") -#define deleteGroupIssuersSQL CFSTR("DELETE FROM issuers " \ - "WHERE groupid=?") -#define addPoliciesColumnSQL CFSTR("ALTER TABLE groups " \ - "ADD COLUMN policies BLOB") -#define updateGroupPoliciesSQL CFSTR("UPDATE OR IGNORE groups " \ - "SET policies=? WHERE groupid=?") - -#define updateConstraintsTablesSQL CFSTR("" \ -"CREATE TABLE IF NOT EXISTS dates(" \ - "groupid INTEGER PRIMARY KEY NOT NULL," \ - "notbefore REAL," \ - "notafter REAL" \ -");") - -#define updateGroupDeleteTriggerSQL CFSTR("" \ - "DROP TRIGGER IF EXISTS group_del;" \ - "CREATE TRIGGER group_del BEFORE DELETE ON groups FOR EACH ROW " \ - "BEGIN " \ - "DELETE FROM serials WHERE groupid=OLD.groupid; " \ - "DELETE FROM hashes WHERE groupid=OLD.groupid; " \ - "DELETE FROM issuers WHERE groupid=OLD.groupid; " \ - "DELETE FROM dates WHERE groupid=OLD.groupid; " \ - "END;") - -#define deleteAllEntriesSQL CFSTR("" \ - "DELETE FROM groups; " \ - "DELETE FROM admin WHERE key='version'; " \ - "DELETE FROM sqlite_sequence") - - -/* Database management */ - -static SecDbRef SecRevocationDbCreate(CFStringRef path) { - /* only the db owner should open a read-write connection. */ - __block bool readWrite = isDbOwner(); - mode_t mode = 0644; - - SecDbRef result = SecDbCreate(path, mode, readWrite, false, true, true, 1, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { - __block bool ok = true; - if (readWrite) { - ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - /* Create all database tables, indexes, and triggers. - * SecDbOpen will set auto_vacuum and journal_mode for us before we get called back.*/ - ok = ok && SecDbExec(dbconn, createTablesSQL, error); - *commit = ok; - }); - } - if (!ok || (error && *error)) { - CFIndex errCode = errSecInternalComponent; - if (error && *error) { - errCode = CFErrorGetCode(*error); - } - secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationCreate, TAFatalError, errCode); - } - return ok; - }); - - return result; -} - -static dispatch_once_t kSecRevocationDbOnce; -static SecRevocationDbRef kSecRevocationDb = NULL; - -static SecRevocationDbRef SecRevocationDbInit(CFStringRef db_name) { - SecRevocationDbRef rdb; - dispatch_queue_attr_t attr; - - require(rdb = (SecRevocationDbRef)malloc(sizeof(struct __SecRevocationDb)), errOut); - rdb->db = NULL; - rdb->update_queue = NULL; - rdb->updateInProgress = false; - rdb->unsupportedVersion = false; - rdb->changed = false; - - require(rdb->db = SecRevocationDbCreate(db_name), errOut); - attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0); - attr = dispatch_queue_attr_make_with_autorelease_frequency(attr, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM); - require(rdb->update_queue = dispatch_queue_create(NULL, attr), errOut); - require(rdb->info_cache_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut); - require(rdb->info_cache = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - rdb->info_cache_lock = OS_UNFAIR_LOCK_INIT; - - if (!isDbOwner()) { - /* register for changes signaled by the db owner instance */ - int out_token = 0; - notify_register_dispatch(kSecRevocationDbChanged, &out_token, rdb->update_queue, ^(int __unused token) { - secnotice("validupdate", "Got notification of database change"); - SecRevocationDbResetCaches(); - }); - } - return rdb; - -errOut: - secdebug("validupdate", "Failed to create db at \"%@\"", db_name); - if (rdb) { - if (rdb->update_queue) { - dispatch_release(rdb->update_queue); - } - CFReleaseSafe(rdb->db); - free(rdb); - } - return NULL; -} - -static CFStringRef SecRevocationDbCopyPath(void) { - CFURLRef revDbURL = NULL; - CFStringRef revInfoRelPath = NULL; - if ((revInfoRelPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), kSecRevocationDbFileName)) != NULL) { - revDbURL = SecCopyURLForFileInRevocationInfoDirectory(revInfoRelPath); - } - CFReleaseSafe(revInfoRelPath); - - CFStringRef revDbPath = NULL; - if (revDbURL) { - revDbPath = CFURLCopyFileSystemPath(revDbURL, kCFURLPOSIXPathStyle); - CFRelease(revDbURL); - } - return revDbPath; -} - -static void SecRevocationDbWith(void(^dbJob)(SecRevocationDbRef db)) { - dispatch_once(&kSecRevocationDbOnce, ^{ - CFStringRef dbPath = SecRevocationDbCopyPath(); - if (dbPath) { - kSecRevocationDb = SecRevocationDbInit(dbPath); - CFRelease(dbPath); - if (kSecRevocationDb && isDbOwner()) { - /* check and update schema immediately after database is opened */ - SecRevocationDbUpdateSchema(kSecRevocationDb); - } - } - }); - // Do pre job run work here (cancel idle timers etc.) - if (kSecRevocationDb->updateInProgress) { - return; // this would block since SecDb has an exclusive transaction lock - } - dbJob(kSecRevocationDb); - // Do post job run work here (gc timer, etc.) -} - -static bool SecRevocationDbPerformWrite(SecRevocationDbRef rdb, CFErrorRef *error, - bool(^writeJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)) { - __block bool ok = true; - __block CFErrorRef localError = NULL; - - ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { - ok &= SecDbTransaction(dbconn, kSecDbImmediateTransactionType, &localError, ^(bool *commit) { - SecRevocationDbConnectionRef dbc = SecRevocationDbConnectionInit(rdb, dbconn, &localError); - ok = ok && writeJob(dbc, &localError); - *commit = ok; - free(dbc); - }); - }); - ok &= CFErrorPropagate(localError, error); - return ok; -} - -static bool SecRevocationDbPerformRead(SecRevocationDbRef rdb, CFErrorRef *error, - bool(^readJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)) { - __block CFErrorRef localError = NULL; - __block bool ok = true; - - ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { - SecRevocationDbConnectionRef dbc = SecRevocationDbConnectionInit(rdb, dbconn, &localError); - ok = ok && readJob(dbc, &localError); - free(dbc); - }); - ok &= CFErrorPropagate(localError, error); - return ok; -} - -static SecRevocationDbConnectionRef SecRevocationDbConnectionInit(SecRevocationDbRef db, SecDbConnectionRef dbconn, CFErrorRef *error) { - SecRevocationDbConnectionRef dbc = NULL; - CFErrorRef localError = NULL; - - dbc = (SecRevocationDbConnectionRef)malloc(sizeof(struct __SecRevocationDbConnection)); - if (dbc) { - dbc->db = db; - dbc->dbconn = dbconn; - dbc->precommitVersion = (CFIndex)_SecRevocationDbGetVersion(dbc, &localError); - dbc->precommitDbVersion = (CFIndex)_SecRevocationDbGetSchemaVersion(db, dbc, &localError); - dbc->precommitInterval = 0; /* set only if we are explicitly given a new value */ - dbc->fullUpdate = false; - } - (void) CFErrorPropagate(localError, error); - return dbc; -} - -static CF_RETURNS_RETAINED CFDataRef createCacheKey(CFDataRef certHash, CFDataRef issuerHash) { - CFMutableDataRef concat = CFDataCreateMutableCopy(NULL, 0, certHash); - CFDataAppend(concat, issuerHash); - CFDataRef result = SecSHA256DigestCreateFromData(NULL, concat); - CFReleaseNull(concat); - return result; -} - -static CF_RETURNS_RETAINED SecValidInfoRef SecRevocationDbCacheRead(SecRevocationDbRef db, - SecCertificateRef certificate, - CFDataRef issuerHash) { - if (!db) { - return NULL; - } - SecValidInfoRef result = NULL; - if (!db || !db->info_cache || !db->info_cache_list) { - return result; - } - CFIndex ix = kCFNotFound; - CFDataRef certHash = SecCertificateCopySHA256Digest(certificate); - CFDataRef cacheKey = createCacheKey(certHash, issuerHash); - - os_unfair_lock_lock(&db->info_cache_lock); // grab the cache lock before using the cache - if (0 <= (ix = CFArrayGetFirstIndexOfValue(db->info_cache_list, - CFRangeMake(0, CFArrayGetCount(db->info_cache_list)), - cacheKey))) { - result = (SecValidInfoRef)CFDictionaryGetValue(db->info_cache, cacheKey); - // Verify this really is the right result - if (CFEqualSafe(result->certHash, certHash) && CFEqualSafe(result->issuerHash, issuerHash)) { - // Cache hit. Move the entry to the bottom of the list. - CFArrayRemoveValueAtIndex(db->info_cache_list, ix); - CFArrayAppendValue(db->info_cache_list, cacheKey); - secdebug("validcache", "cache hit: %@", cacheKey); - } else { - // Just remove this bad entry - CFArrayRemoveValueAtIndex(db->info_cache_list, ix); - CFDictionaryRemoveValue(db->info_cache, cacheKey); - secdebug("validcache", "cache remove bad: %@", cacheKey); - secnotice("validcache", "found a bad valid info cache entry at %ld", (long)ix); - } - } - CFRetainSafe(result); - os_unfair_lock_unlock(&db->info_cache_lock); - CFReleaseSafe(certHash); - CFReleaseSafe(cacheKey); - return result; -} - -static void SecRevocationDbCacheWrite(SecRevocationDbRef db, - SecValidInfoRef validInfo) { - if (!db || !validInfo || !db->info_cache || !db->info_cache_list) { - return; - } - - CFDataRef cacheKey = createCacheKey(validInfo->certHash, validInfo->issuerHash); - - os_unfair_lock_lock(&db->info_cache_lock); // grab the cache lock before using the cache - // check to make sure another thread didn't add this entry to the cache already - if (0 > CFArrayGetFirstIndexOfValue(db->info_cache_list, - CFRangeMake(0, CFArrayGetCount(db->info_cache_list)), - cacheKey)) { - CFDictionaryAddValue(db->info_cache, cacheKey, validInfo); - if (kSecRevocationDbCacheSize <= CFArrayGetCount(db->info_cache_list)) { - // Remove least recently used cache entry. - secdebug("validcache", "cache remove stale: %@", CFArrayGetValueAtIndex(db->info_cache_list, 0)); - CFDictionaryRemoveValue(db->info_cache, CFArrayGetValueAtIndex(db->info_cache_list, 0)); - CFArrayRemoveValueAtIndex(db->info_cache_list, 0); - } - CFArrayAppendValue(db->info_cache_list, cacheKey); - secdebug("validcache", "cache add: %@", cacheKey); - } - os_unfair_lock_unlock(&db->info_cache_lock); - CFReleaseNull(cacheKey); -} - -static void SecRevocationDbCachePurge(SecRevocationDbRef db) { - if (!db || !db->info_cache || !db->info_cache_list) { - return; - } - - /* grab the cache lock and clear all entries */ - os_unfair_lock_lock(&db->info_cache_lock); - CFArrayRemoveAllValues(db->info_cache_list); - CFDictionaryRemoveAllValues(db->info_cache); - secdebug("validcache", "cache purge"); - os_unfair_lock_unlock(&db->info_cache_lock); -} - -static int64_t _SecRevocationDbGetUpdateInterval(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up interval entry in admin table; returns -1 on error */ - __block int64_t interval = -1; - __block bool ok = true; - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectUpdateIntervalSQL, &localError, ^bool(sqlite3_stmt *selectInterval) { - ok = ok && SecDbStep(dbc->dbconn, selectInterval, &localError, ^void(bool *stop) { - interval = sqlite3_column_int64(selectInterval, 0); - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbGetUpdateInterval failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return interval; -} - -static bool _SecRevocationDbSetUpdateInterval(SecRevocationDbConnectionRef dbc, int64_t interval, CFErrorRef *error) { - secdebug("validupdate", "setting interval to %lld", interval); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertInterval) { - const char *intervalKey = "interval"; - ok = ok && SecDbBindText(insertInterval, 1, intervalKey, strlen(intervalKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertInterval, 2, - (sqlite3_int64)interval, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertInterval, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetUpdateInterval failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static CFArrayRef _SecRevocationDbCopyHashes(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* return a retained copy of the db_hash array stored in the admin table; or NULL on error */ - __block CFMutableArrayRef hashes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - __block bool ok = (dbc && hashes); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectDbHashSQL, &localError, ^bool(sqlite3_stmt *selectDbHash) { - ok = ok && SecDbStep(dbc->dbconn, selectDbHash, &localError, ^void(bool *stop) { - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectDbHash, 0); - uint64_t len = sqlite3_column_bytes(selectDbHash, 0); - CFIndex hashLen = CC_SHA256_DIGEST_LENGTH; - while (p && len >= (uint64_t)hashLen) { - CFDataRef hash = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)p, hashLen); - if (hash) { - CFArrayAppendValue(hashes, hash); - CFReleaseNull(hash); - } - len -= hashLen; - p += hashLen; - } - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - CFReleaseNull(hashes); - } - (void) CFErrorPropagate(localError, error); - return hashes; -} - -static bool _SecRevocationDbSetHashes(SecRevocationDbConnectionRef dbc, CFArrayRef hashes, CFErrorRef *error) { - /* flatten and store db_hash array in the admin table */ - __block CFErrorRef localError = NULL; - __block bool ok = (dbc && hashes); - - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertHashes) { - CFIndex count = CFArrayGetCount(hashes); - CFIndex hashLen = CC_SHA256_DIGEST_LENGTH, dataLen = hashLen * count; - uint8_t *dataPtr = (uint8_t *)calloc(dataLen, 1); - uint8_t *p = dataPtr; - for (CFIndex idx = 0; idx < count && p; idx++) { - CFDataRef hash = CFArrayGetValueAtIndex(hashes, idx); - uint8_t *h = (hash) ? (uint8_t *)CFDataGetBytePtr(hash) : NULL; - if (h && CFDataGetLength(hash) == hashLen) { memcpy(p, h, hashLen); } - p += hashLen; - } - const char *hashKey = "db_hash"; - ok = ok && SecDbBindText(insertHashes, 1, hashKey, strlen(hashKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertHashes, 2, - (sqlite3_int64)0, &localError); - ok = ok && SecDbBindBlob(insertHashes, 3, - dataPtr, dataLen, - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertHashes, &localError, NULL); - free(dataPtr); - return ok; - }); - if (!ok || localError) { - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static int64_t _SecRevocationDbGetVersion(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up version entry in admin table; returns -1 on error */ - __block int64_t version = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectVersionSQL, &localError, ^bool(sqlite3_stmt *selectVersion) { - ok = ok && SecDbStep(dbc->dbconn, selectVersion, &localError, ^void(bool *stop) { - version = sqlite3_column_int64(selectVersion, 0); - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbGetVersion failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return version; -} - -static bool _SecRevocationDbSetVersion(SecRevocationDbConnectionRef dbc, CFIndex version, CFErrorRef *error) { - secdebug("validupdate", "setting version to %ld", (long)version); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertVersion) { - const char *versionKey = "version"; - ok = ok && SecDbBindText(insertVersion, 1, versionKey, strlen(versionKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertVersion, 2, - (sqlite3_int64)version, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertVersion, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetVersion failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static int64_t _SecRevocationDbReadSchemaVersionFromDb(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up db_version entry in admin table; returns -1 on error */ - __block int64_t db_version = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectDbVersionSQL, &localError, ^bool(sqlite3_stmt *selectDbVersion) { - ok = ok && SecDbStep(dbc->dbconn, selectDbVersion, &localError, ^void(bool *stop) { - db_version = sqlite3_column_int64(selectDbVersion, 0); - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbReadSchemaVersionFromDb failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return db_version; -} - -static _Atomic int64_t gSchemaVersion = -1; -static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef rdb, SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - if (dbc) { - atomic_init(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, error)); - } else { - (void) SecRevocationDbPerformRead(rdb, error, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - atomic_init(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); - return true; - }); - } - }); - if (atomic_load(&gSchemaVersion) == -1) { - /* Initial read(s) failed. Try to read the schema version again. */ - if (dbc) { - atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, error)); - } else { - (void) SecRevocationDbPerformRead(rdb, error, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); - return true; - }); - } - } - return atomic_load(&gSchemaVersion); -} - -static void SecRevocationDbResetCaches(void) { - SecRevocationDbWith(^(SecRevocationDbRef db) { - db->unsupportedVersion = false; - db->changed = false; - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); - return true; - }); - SecRevocationDbCachePurge(db); - }); -} - -static bool _SecRevocationDbSetSchemaVersion(SecRevocationDbConnectionRef dbc, CFIndex dbversion, CFErrorRef *error) { - if (dbversion > 0) { - int64_t db_version = (dbc) ? dbc->precommitDbVersion : -1; - if (db_version >= dbversion) { - return true; /* requested schema is earlier than current schema */ - } - } - secdebug("validupdate", "setting db_version to %ld", (long)dbversion); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbVersion) { - const char *dbVersionKey = "db_version"; - ok = ok && SecDbBindText(insertDbVersion, 1, dbVersionKey, strlen(dbVersionKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertDbVersion, 2, - (sqlite3_int64)dbversion, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertDbVersion, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetSchemaVersion failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } else { - dbc->db->changed = true; /* will notify clients of this change */ - dbc->db->unsupportedVersion = false; - dbc->precommitDbVersion = dbversion; - atomic_store(&gSchemaVersion, (int64_t)dbversion); - } - CFReleaseSafe(localError); - return ok; -} - -static bool _SecRevocationDbUpdateSchema(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - __block int64_t db_version = (dbc) ? dbc->precommitDbVersion : 0; - if (db_version >= kSecRevocationDbSchemaVersion) { - return ok; /* schema version already up to date */ - } - secdebug("validupdate", "updating db schema from v%lld to v%lld", - (long long)db_version, (long long)kSecRevocationDbSchemaVersion); - - if (ok && db_version < 5) { - /* apply v5 changes (add dates table and replace trigger) */ - ok &= SecDbWithSQL(dbc->dbconn, updateConstraintsTablesSQL, &localError, ^bool(sqlite3_stmt *updateTables) { - ok = SecDbStep(dbc->dbconn, updateTables, &localError, NULL); - return ok; - }); - ok &= SecDbWithSQL(dbc->dbconn, updateGroupDeleteTriggerSQL, &localError, ^bool(sqlite3_stmt *updateTrigger) { - ok = SecDbStep(dbc->dbconn, updateTrigger, &localError, NULL); - return ok; - }); - secdebug("validupdate", "applied schema update to v5 (%s)", (ok) ? "ok" : "failed!"); - } - if (ok && db_version < 6) { - /* apply v6 changes (the SecDb layer will update autovacuum mode if needed, so we don't execute - any SQL here, but we do want the database to be replaced in case transaction scope problems - with earlier versions caused missing entries.) */ - secdebug("validupdate", "applied schema update to v6 (%s)", (ok) ? "ok" : "failed!"); - if (db_version > 0) { - SecValidUpdateForceReplaceDatabase(); - } - } - if (ok && db_version < 7) { - /* apply v7 changes (add policies column in groups table) */ - ok &= SecDbWithSQL(dbc->dbconn, addPoliciesColumnSQL, &localError, ^bool(sqlite3_stmt *addPoliciesColumn) { - ok = SecDbStep(dbc->dbconn, addPoliciesColumn, &localError, NULL); - return ok; - }); - secdebug("validupdate", "applied schema update to v7 (%s)", (ok) ? "ok" : "failed!"); - } - - if (!ok) { - secerror("_SecRevocationDbUpdateSchema failed: %@", localError); - } else { - ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -bool SecRevocationDbUpdateSchema(SecRevocationDbRef rdb) { - /* note: this function assumes it is called only by the database owner. - non-owner (read-only) clients will fail if changes to the db are needed. */ - if (!rdb || !rdb->db) { - return false; - } - __block bool ok = true; - __block CFErrorRef localError = NULL; - ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - return _SecRevocationDbUpdateSchema(dbc, blockError); - }); - CFReleaseSafe(localError); - return ok; -} - -static int64_t _SecRevocationDbGetUpdateFormat(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up db_format entry in admin table; returns -1 on error */ - __block int64_t db_format = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectDbFormatSQL, &localError, ^bool(sqlite3_stmt *selectDbFormat) { - ok &= SecDbStep(dbc->dbconn, selectDbFormat, &localError, ^void(bool *stop) { - db_format = sqlite3_column_int64(selectDbFormat, 0); - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbGetUpdateFormat failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return db_format; -} - -static bool _SecRevocationDbSetUpdateFormat(SecRevocationDbConnectionRef dbc, CFIndex dbformat, CFErrorRef *error) { - secdebug("validupdate", "setting db_format to %ld", (long)dbformat); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbFormat) { - const char *dbFormatKey = "db_format"; - ok = ok && SecDbBindText(insertDbFormat, 1, dbFormatKey, strlen(dbFormatKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertDbFormat, 2, - (sqlite3_int64)dbformat, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertDbFormat, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetUpdateFormat failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } else { - dbc->db->changed = true; /* will notify clients of this change */ - dbc->db->unsupportedVersion = false; - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static CFStringRef _SecRevocationDbCopyUpdateSource(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up db_source entry in admin table; returns NULL on error */ - __block CFStringRef updateSource = NULL; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectDbSourceSQL, &localError, ^bool(sqlite3_stmt *selectDbSource) { - ok &= SecDbStep(dbc->dbconn, selectDbSource, &localError, ^void(bool *stop) { - const UInt8 *p = (const UInt8 *)sqlite3_column_blob(selectDbSource, 0); - if (p != NULL) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectDbSource, 0); - if (length > 0) { - updateSource = CFStringCreateWithBytes(kCFAllocatorDefault, p, length, kCFStringEncodingUTF8, false); - } - } - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbCopyUpdateSource failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return updateSource; -} - -bool _SecRevocationDbSetUpdateSource(SecRevocationDbConnectionRef dbc, CFStringRef updateSource, CFErrorRef *error) { - if (!updateSource) { - secerror("_SecRevocationDbSetUpdateSource failed: %d", errSecParam); - return false; - } - __block char buffer[256]; - __block const char *updateSourceCStr = CFStringGetCStringPtr(updateSource, kCFStringEncodingUTF8); - if (!updateSourceCStr) { - if (CFStringGetCString(updateSource, buffer, 256, kCFStringEncodingUTF8)) { - updateSourceCStr = buffer; - } - } - if (!updateSourceCStr) { - secerror("_SecRevocationDbSetUpdateSource failed: unable to get UTF-8 encoding"); - return false; - } - secdebug("validupdate", "setting update source to \"%s\"", updateSourceCStr); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { - const char *dbSourceKey = "db_source"; - ok = ok && SecDbBindText(insertRecord, 1, dbSourceKey, strlen(dbSourceKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertRecord, 2, - (sqlite3_int64)0, &localError); - ok = ok && SecDbBindBlob(insertRecord, 3, - updateSourceCStr, strlen(updateSourceCStr), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertRecord, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetUpdateSource failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - CFReleaseSafe(localError); - return ok; -} - -bool SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef updateSource) { - /* note: this function assumes it is called only by the database owner. - non-owner (read-only) clients will fail if changes to the db are needed. */ - if (!rdb || !rdb->db) { - return false; - } - CFErrorRef localError = NULL; - bool ok = true; - ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - return _SecRevocationDbSetUpdateSource(dbc, updateSource, error); - }); - CFReleaseSafe(localError); - return ok; -} - -static CFAbsoluteTime _SecRevocationDbGetNextUpdateTime(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* look up check_again entry in admin table; returns 0 on error */ - __block CFAbsoluteTime nextUpdate = 0; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectNextUpdateSQL, &localError, ^bool(sqlite3_stmt *selectNextUpdate) { - ok &= SecDbStep(dbc->dbconn, selectNextUpdate, &localError, ^void(bool *stop) { - CFAbsoluteTime *p = (CFAbsoluteTime *)sqlite3_column_blob(selectNextUpdate, 0); - if (p != NULL) { - if (sizeof(CFAbsoluteTime) == sqlite3_column_bytes(selectNextUpdate, 0)) { - nextUpdate = *p; - } - } - *stop = true; - }); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbGetNextUpdateTime failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return nextUpdate; -} - -static bool _SecRevocationDbSetNextUpdateTime(SecRevocationDbConnectionRef dbc, CFAbsoluteTime nextUpdate, CFErrorRef *error){ - secdebug("validupdate", "setting next update to %f", (double)nextUpdate); - - __block CFErrorRef localError = NULL; - __block bool ok = (dbc != NULL); - ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { - const char *nextUpdateKey = "check_again"; - ok = ok && SecDbBindText(insertRecord, 1, nextUpdateKey, strlen(nextUpdateKey), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(insertRecord, 2, - (sqlite3_int64)0, &localError); - ok = ok && SecDbBindBlob(insertRecord, 3, - &nextUpdate, sizeof(CFAbsoluteTime), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertRecord, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbSetNextUpdate failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -bool _SecRevocationDbRemoveAllEntries(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - /* clear out the contents of the database and start fresh */ - bool ok = (dbc != NULL); - CFErrorRef localError = NULL; - - /* _SecRevocationDbUpdateSchema was called when db was opened, so no need to do it again. */ - - /* delete all entries */ - ok = ok && SecDbExec(dbc->dbconn, deleteAllEntriesSQL, &localError); - secnotice("validupdate", "resetting database, result: %d (expected 1)", (ok) ? 1 : 0); - - /* one more thing: update the schema version and format to current */ - ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); - ok = ok && _SecRevocationDbSetUpdateFormat(dbc, kSecRevocationDbUpdateFormat, &localError); - - if (!ok || localError) { - secerror("_SecRevocationDbRemoveAllEntries failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbUpdateIssuers(SecRevocationDbConnectionRef dbc, int64_t groupId, CFArrayRef issuers, CFErrorRef *error) { - /* insert or replace issuer records in issuers table */ - if (!issuers || groupId < 0) { - return false; /* must have something to insert, and a group to associate with it */ - } - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - if (isArray(issuers)) { - CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers); - for (issuerIX=0; issuerIXdbconn, insertIssuerRecordSQL, &localError, ^bool(sqlite3_stmt *insertIssuer) { - ok = ok && SecDbBindInt64(insertIssuer, 1, - groupId, &localError); - ok = ok && SecDbBindBlob(insertIssuer, 2, - CFDataGetBytePtr(hash), - CFDataGetLength(hash), - SQLITE_TRANSIENT, &localError); - /* Execute the insert statement for this issuer record. */ - ok = ok && SecDbStep(dbc->dbconn, insertIssuer, &localError, NULL); - return ok; - }); - } - } - if (!ok || localError) { - secerror("_SecRevocationDbUpdateIssuers failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static SecValidInfoFormat _SecRevocationDbGetGroupFormatForData(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDataRef data) { - /* determine existing format if groupId is supplied and this is a partial update, - otherwise return the expected format for the given data. */ - SecValidInfoFormat format = kSecValidInfoFormatUnknown; - if (groupId >= 0 && !dbc->fullUpdate) { - format = _SecRevocationDbGetGroupFormat(dbc, groupId, NULL, NULL, NULL, NULL); - } - if (format == kSecValidInfoFormatUnknown && data != NULL) { - /* group doesn't exist, so determine format based on length of specified data. - len <= 20 is a serial number (actually, <=37, but != 32.) - len==32 is a sha256 hash. otherwise: nto1. */ - CFIndex length = CFDataGetLength(data); - if (length == 32) { - format = kSecValidInfoFormatSHA256; - } else if (length <= 37) { - format = kSecValidInfoFormatSerial; - } else if (length > 0) { - format = kSecValidInfoFormatNto1; - } - } - return format; -} - -static bool _SecRevocationDbUpdateIssuerData(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* update/delete records in serials or hashes table. */ - if (!dict || groupId < 0) { - return false; /* must have something to insert, and a group to associate with it */ - } - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - /* process deletions */ - CFArrayRef deleteArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("delete")); - if (isArray(deleteArray)) { - SecValidInfoFormat format = kSecValidInfoFormatUnknown; - CFIndex processed=0, identifierIX, identifierCount = CFArrayGetCount(deleteArray); - for (identifierIX=0; identifierIXdbconn, sql, &localError, ^bool(sqlite3_stmt *deleteIdentifier) { - /* (groupid,serial|sha256) */ - CFDataRef hexData = cfToHexData(identifierData, true); - if (!hexData) { return false; } - ok = ok && SecDbBindInt64(deleteIdentifier, 1, - groupId, &localError); - ok = ok && SecDbBindBlob(deleteIdentifier, 2, - CFDataGetBytePtr(hexData), - CFDataGetLength(hexData), - SQLITE_TRANSIENT, &localError); - /* Execute the delete statement for the identifier record. */ - ok = ok && SecDbStep(dbc->dbconn, deleteIdentifier, &localError, NULL); - CFReleaseSafe(hexData); - return ok; - }); - if (ok) { ++processed; } - } -#if VERBOSE_LOGGING - secdebug("validupdate", "Processed %ld of %ld deletions for group %lld, result=%s", - processed, identifierCount, groupId, (ok) ? "true" : "false"); -#endif - } - /* process additions */ - CFArrayRef addArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("add")); - if (isArray(addArray)) { - SecValidInfoFormat format = kSecValidInfoFormatUnknown; - CFIndex processed=0, identifierIX, identifierCount = CFArrayGetCount(addArray); - for (identifierIX=0; identifierIXdbconn, sql, &localError, ^bool(sqlite3_stmt *insertIdentifier) { - /* rowid,(groupid,serial|sha256) */ - /* rowid is autoincremented and we never set it directly */ - ok = ok && SecDbBindInt64(insertIdentifier, 1, - groupId, &localError); - ok = ok && SecDbBindBlob(insertIdentifier, 2, - CFDataGetBytePtr(identifierData), - CFDataGetLength(identifierData), - SQLITE_TRANSIENT, &localError); - /* Execute the insert statement for the identifier record. */ - ok = ok && SecDbStep(dbc->dbconn, insertIdentifier, &localError, NULL); - return ok; - }); - if (ok) { ++processed; } - } -#if VERBOSE_LOGGING - secdebug("validupdate", "Processed %ld of %ld additions for group %lld, result=%s", - processed, identifierCount, groupId, (ok) ? "true" : "false"); -#endif - } - if (!ok || localError) { - secerror("_SecRevocationDbUpdatePerIssuerData failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbCopyDateConstraints(SecRevocationDbConnectionRef dbc, - int64_t groupId, CFDateRef *notBeforeDate, CFDateRef *notAfterDate, CFErrorRef *error) { - /* return true if one or both date constraints exist for a given groupId. - the actual constraints are optionally returned in output CFDateRef parameters. - caller is responsible for releasing date and error parameters, if provided. - */ - __block bool ok = (dbc != NULL); - __block CFDateRef localNotBefore = NULL; - __block CFDateRef localNotAfter = NULL; - __block CFErrorRef localError = NULL; - - ok = ok && SecDbWithSQL(dbc->dbconn, selectDateRecordSQL, &localError, ^bool(sqlite3_stmt *selectDates) { - /* (groupid,notbefore,notafter) */ - ok &= SecDbBindInt64(selectDates, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, selectDates, &localError, ^(bool *stop) { - /* if column has no value, its type will be SQLITE_NULL */ - if (SQLITE_NULL != sqlite3_column_type(selectDates, 0)) { - CFAbsoluteTime nb = (CFAbsoluteTime)sqlite3_column_double(selectDates, 0); - localNotBefore = CFDateCreate(NULL, nb); - } - if (SQLITE_NULL != sqlite3_column_type(selectDates, 1)) { - CFAbsoluteTime na = (CFAbsoluteTime)sqlite3_column_double(selectDates, 1); - localNotAfter = CFDateCreate(NULL, na); - } - }); - return ok; - }); - /* must have at least one date constraint to return true. - since date constraints are optional, not finding any should not log an error. */ - ok = ok && !localError && (localNotBefore != NULL || localNotAfter != NULL); - if (localError) { - secerror("_SecRevocationDbCopyDateConstraints failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - if (!ok) { - CFReleaseNull(localNotBefore); - CFReleaseNull(localNotAfter); - } - if (notBeforeDate) { - *notBeforeDate = localNotBefore; - } else { - CFReleaseSafe(localNotBefore); - } - if (notAfterDate) { - *notAfterDate = localNotAfter; - } else { - CFReleaseSafe(localNotAfter); - } - - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbUpdateDateConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* Called only from _SecRevocationDbUpdateIssuerConstraints. - Function assumes that the caller has checked the input arguments. - */ - __block bool ok = true; - __block CFErrorRef localError = NULL; - __block CFAbsoluteTime notBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ - __block CFAbsoluteTime notAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ - - CFDateRef notBeforeDate = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-before")); - CFDateRef notAfterDate = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-after")); - - if (isDate(notBeforeDate)) { - notBefore = CFDateGetAbsoluteTime(notBeforeDate); - } else { - notBeforeDate = NULL; - } - if (isDate(notAfterDate)) { - notAfter = CFDateGetAbsoluteTime(notAfterDate); - } else { - notAfterDate = NULL; - } - if (!(notBeforeDate || notAfterDate)) { - return ok; /* no dates supplied, so we have nothing to update for this issuer */ - } - - if (!(notBeforeDate && notAfterDate) && !dbc->fullUpdate) { - /* only one date was supplied, so check for existing date constraints */ - CFDateRef curNotBeforeDate = NULL; - CFDateRef curNotAfterDate = NULL; - if (_SecRevocationDbCopyDateConstraints(dbc, groupId, &curNotBeforeDate, - &curNotAfterDate, &localError)) { - if (!notBeforeDate) { - notBeforeDate = curNotBeforeDate; - notBefore = CFDateGetAbsoluteTime(notBeforeDate); - } else { - CFReleaseSafe(curNotBeforeDate); - } - if (!notAfterDate) { - notAfterDate = curNotAfterDate; - notAfter = CFDateGetAbsoluteTime(notAfterDate); - } else { - CFReleaseSafe(curNotAfterDate); - } - } - } - ok = ok && SecDbWithSQL(dbc->dbconn, insertDateRecordSQL, &localError, ^bool(sqlite3_stmt *insertDate) { - /* (groupid,notbefore,notafter) */ - ok = ok && SecDbBindInt64(insertDate, 1, groupId, &localError); - ok = ok && SecDbBindDouble(insertDate, 2, notBefore, &localError); - ok = ok && SecDbBindDouble(insertDate, 3, notAfter, &localError); - ok = ok && SecDbStep(dbc->dbconn, insertDate, &localError, NULL); - return ok; - }); - - if (!ok || localError) { - secinfo("validupdate", "_SecRevocationDbUpdateDateConstraints failed (ok=%s, localError=%@)", - (ok) ? "1" : "0", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbUpdatePolicyConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* Called only from _SecRevocationDbUpdateIssuerConstraints. - Function assumes that the caller has checked the input arguments. - */ - __block bool ok = true; - __block CFErrorRef localError = NULL; - CFArrayRef policies = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies")); - if (!isArray(policies)) { - return ok; /* no policies supplied, so nothing to update for this issuer */ - } - - __block CFDataRef data = createPoliciesData(policies); - ok = data && SecDbWithSQL(dbc->dbconn, updateGroupPoliciesSQL, &localError, ^bool(sqlite3_stmt *updatePolicies) { - /* (policies,groupid) */ - ok = ok && SecDbBindBlob(updatePolicies, 1, - CFDataGetBytePtr(data), - CFDataGetLength(data), - SQLITE_TRANSIENT, &localError); - ok = ok && SecDbBindInt64(updatePolicies, 2, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, updatePolicies, &localError, NULL); - return ok; - }); - CFReleaseSafe(data); - - if (!ok || localError) { - secinfo("validupdate", "_SecRevocationDbUpdatePolicyConstraints failed (ok=%s, localError=%@)", - (ok) ? "1" : "0", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbUpdateNameConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* Called only from _SecRevocationDbUpdateIssuerConstraints. - Function assumes that the caller has checked the input arguments. - */ - - /* %%% (TBI:9254570) update name constraint entries here */ - return true; -} - -static bool _SecRevocationDbUpdateIssuerConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* check input arguments */ - if (!dbc || !dict || groupId < 0) { - return false; - } - bool ok = true; - ok = ok && _SecRevocationDbUpdateDateConstraints(dbc, groupId, dict, error); - ok = ok && _SecRevocationDbUpdateNameConstraints(dbc, groupId, dict, error); - ok = ok && _SecRevocationDbUpdatePolicyConstraints(dbc, groupId, dict, error); - return ok; -} - -static SecValidInfoFormat _SecRevocationDbGetGroupFormat(SecRevocationDbConnectionRef dbc, - int64_t groupId, SecValidInfoFlags *flags, CFDataRef *data, CFDataRef *policies, CFErrorRef *error) { - /* return group record fields for a given groupId. - on success, returns a non-zero format type, and other field values in optional output parameters. - caller is responsible for releasing data, policies, and error parameters, if provided. - */ - __block bool ok = (dbc != NULL); - __block SecValidInfoFormat format = 0; - __block CFErrorRef localError = NULL; - - /* Select the group record to determine flags and format. */ - ok = ok && SecDbWithSQL(dbc->dbconn, selectGroupRecordSQL, &localError, ^bool(sqlite3_stmt *selectGroup) { - ok = ok && SecDbBindInt64(selectGroup, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, selectGroup, &localError, ^(bool *stop) { - if (flags) { - *flags = (SecValidInfoFlags)sqlite3_column_int(selectGroup, 0); - } - format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); - if (data) { - //%%% stream the data from the db into a streamed decompression - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); - if (p != NULL && format == kSecValidInfoFormatNto1) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); - *data = CFDataCreate(kCFAllocatorDefault, p, length); - } - } - if (policies) { - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 3); - if (p != NULL) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 3); - *policies = CFDataCreate(kCFAllocatorDefault, p, length); - } - } - }); - return ok; - }); - if (!ok || localError) { - secdebug("validupdate", "GetGroupFormat for groupId %lu failed", (unsigned long)groupId); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - format = kSecValidInfoFormatUnknown; - } - (void) CFErrorPropagate(localError, error); - if (!(format > kSecValidInfoFormatUnknown)) { - secdebug("validupdate", "GetGroupFormat: got format %d for groupId %lld", format, (long long)groupId); - } - return format; -} - -static bool _SecRevocationDbUpdateFlags(CFDictionaryRef dict, CFStringRef key, SecValidInfoFlags mask, SecValidInfoFlags *flags) { - /* If a boolean value exists in the given dictionary for the given key, - or an explicit "1" or "0" is specified as the key string, - set or clear the corresponding bit(s) defined by the mask argument. - Function returns true if the flags value was changed, false otherwise. - */ - if (!isDictionary(dict) || !isString(key) || !flags) { - return false; - } - bool hasValue = false, newValue = false, result = false; - CFTypeRef value = (CFBooleanRef)CFDictionaryGetValue(dict, key); - if (isBoolean(value)) { - newValue = CFBooleanGetValue((CFBooleanRef)value); - hasValue = true; - } else if (BOOL_STRING_KEY_LENGTH == CFStringGetLength(key)) { - if (CFStringCompare(key, kBoolTrueKey, 0) == kCFCompareEqualTo) { - hasValue = newValue = true; - } else if (CFStringCompare(key, kBoolFalseKey, 0) == kCFCompareEqualTo) { - hasValue = true; - } - } - if (hasValue) { - SecValidInfoFlags oldFlags = *flags; - if (newValue) { - *flags |= mask; - } else { - *flags &= ~(mask); - } - result = (*flags != oldFlags); - } - return result; -} - -static bool _SecRevocationDbUpdateFilter(CFDictionaryRef dict, CFDataRef oldData, CFDataRef * __nonnull CF_RETURNS_RETAINED xmlData) { - /* If xor and/or params values exist in the given dictionary, create a new - property list containing the updated values, and return as a flattened - data blob in the xmlData output parameter (note: caller must release.) - Function returns true if there is new xmlData to save, false otherwise. - */ - bool result = false; - bool xorProvided = false; - bool paramsProvided = false; - bool missingData = false; - - if (!dict || !xmlData) { - return result; /* no-op if no dictionary is provided, or no way to update the data */ - } - *xmlData = NULL; - CFDataRef xorCurrent = NULL; - CFDataRef xorUpdate = (CFDataRef)CFDictionaryGetValue(dict, CFSTR("xor")); - if (isData(xorUpdate)) { - xorProvided = true; - } - CFArrayRef paramsCurrent = NULL; - CFArrayRef paramsUpdate = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("params")); - if (isArray(paramsUpdate)) { - paramsProvided = true; - } - if (!(xorProvided || paramsProvided)) { - return result; /* nothing to update, so we can bail out here. */ - } - - CFPropertyListRef nto1Current = NULL; - CFMutableDictionaryRef nto1Update = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!nto1Update) { - return result; - } - - /* turn old data into property list */ - CFDataRef data = (CFDataRef)CFRetainSafe(oldData); - CFDataRef inflatedData = copyInflatedData(data); - if (inflatedData) { - CFReleaseSafe(data); - data = inflatedData; - } - if (data) { - nto1Current = CFPropertyListCreateWithData(kCFAllocatorDefault, data, 0, NULL, NULL); - CFReleaseSafe(data); - } - if (nto1Current) { - xorCurrent = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("xor")); - paramsCurrent = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("params")); - } - - /* set current or updated xor data in new property list */ - if (xorProvided) { - CFDataRef xorNew = NULL; - if (xorCurrent) { - CFIndex xorUpdateLen = CFDataGetLength(xorUpdate); - CFMutableDataRef xor = CFDataCreateMutableCopy(NULL, 0, xorCurrent); - if (xor && xorUpdateLen > 0) { - /* truncate or zero-extend data to match update size */ - CFDataSetLength(xor, xorUpdateLen); - /* exclusive-or update bytes over the existing data */ - UInt8 *xorP = (UInt8 *)CFDataGetMutableBytePtr(xor); - UInt8 *updP = (UInt8 *)CFDataGetBytePtr(xorUpdate); - if (xorP && updP) { - for (int idx = 0; idx < xorUpdateLen; idx++) { - xorP[idx] = xorP[idx] ^ updP[idx]; - } - } - } - xorNew = (CFDataRef)xor; - } else { - xorNew = (CFDataRef)CFRetainSafe(xorUpdate); - } - if (xorNew) { - CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorNew); - CFReleaseSafe(xorNew); - } else { - secdebug("validupdate", "Failed to get updated filter data"); - missingData = true; - } - } else if (xorCurrent) { - /* not provided, so use existing xor value */ - CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorCurrent); - } else { - secdebug("validupdate", "Failed to get current filter data"); - missingData = true; - } - - /* set current or updated params in new property list */ - if (paramsProvided) { - CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsUpdate); - } else if (paramsCurrent) { - /* not provided, so use existing params value */ - CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsCurrent); - } else { - /* missing params: neither provided nor existing */ - secdebug("validupdate", "Failed to get current filter params"); - missingData = true; - } - - CFReleaseSafe(nto1Current); - if (!missingData) { - *xmlData = CFPropertyListCreateData(kCFAllocatorDefault, nto1Update, - kCFPropertyListXMLFormat_v1_0, - 0, NULL); - result = (*xmlData != NULL); - } - CFReleaseSafe(nto1Update); - - /* compress the xmlData blob, if possible */ - if (result) { - CFDataRef deflatedData = copyDeflatedData(*xmlData); - if (deflatedData) { - if (CFDataGetLength(deflatedData) < CFDataGetLength(*xmlData)) { - CFRelease(*xmlData); - *xmlData = deflatedData; - } else { - CFRelease(deflatedData); - } - } - } - return result; -} - - -static int64_t _SecRevocationDbUpdateGroup(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* insert group record for a given groupId. - if the specified groupId is < 0, a new group entry is created. - returns the groupId on success, or -1 on failure. - */ - if (!dict) { - return groupId; /* no-op if no dictionary is provided */ - } - - __block int64_t result = -1; - __block bool ok = (dbc != NULL); - __block bool isFormatChange = false; - __block CFErrorRef localError = NULL; - - __block SecValidInfoFlags flags = 0; - __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; - __block SecValidInfoFormat formatUpdate = kSecValidInfoFormatUnknown; - __block CFDataRef data = NULL; - __block CFDataRef policies = NULL; - - if (groupId >= 0) { - /* fetch the flags and data for an existing group record, in case some are being changed. */ - if (ok) { - format = _SecRevocationDbGetGroupFormat(dbc, groupId, &flags, &data, &policies, NULL); - } - if (format == kSecValidInfoFormatUnknown) { - secdebug("validupdate", "existing group %lld has unknown format %d, flags=0x%lx", - (long long)groupId, format, flags); - //%%% clean up by deleting all issuers with this groupId, then the group record, - // or just force a full update? note: we can get here if we fail to bind the - // format value in the prepared SQL statement below. - return -1; - } - } - CFTypeRef value = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("format")); - if (isString(value)) { - if (CFStringCompare((CFStringRef)value, CFSTR("serial"), 0) == kCFCompareEqualTo) { - formatUpdate = kSecValidInfoFormatSerial; - } else if (CFStringCompare((CFStringRef)value, CFSTR("sha256"), 0) == kCFCompareEqualTo) { - formatUpdate = kSecValidInfoFormatSHA256; - } else if (CFStringCompare((CFStringRef)value, CFSTR("nto1"), 0) == kCFCompareEqualTo) { - formatUpdate = kSecValidInfoFormatNto1; - } - } - /* if format value is explicitly supplied, then this is effectively a new group entry. */ - isFormatChange = (formatUpdate > kSecValidInfoFormatUnknown && - formatUpdate != format && - groupId >= 0); - - if (isFormatChange) { - secdebug("validupdate", "group %lld format change from %d to %d", - (long long)groupId, format, formatUpdate); - /* format of an existing group is changing; delete the group first. - this should ensure that all entries referencing the old groupid are deleted. - */ - ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { - ok = ok && SecDbBindInt64(deleteResponse, 1, groupId, &localError); - /* Execute the delete statement. */ - ok = ok && SecDbStep(dbc->dbconn, deleteResponse, &localError, NULL); - return ok; - }); - } - ok = ok && SecDbWithSQL(dbc->dbconn, insertGroupRecordSQL, &localError, ^bool(sqlite3_stmt *insertGroup) { - /* (groupid,flags,format,data,policies) */ - /* groups.groupid */ - if (ok && (!isFormatChange) && (groupId >= 0)) { - /* bind to existing groupId row if known, otherwise will insert and autoincrement */ - ok = SecDbBindInt64(insertGroup, 1, groupId, &localError); - if (!ok) { - secdebug("validupdate", "failed to set groupId %lld", (long long)groupId); - } - } - /* groups.flags */ - if (ok) { - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("complete"), kSecValidInfoComplete, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("check-ocsp"), kSecValidInfoCheckOCSP, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("known-intermediates-only"), kSecValidInfoKnownOnly, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("require-ct"), kSecValidInfoRequireCT, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("valid"), kSecValidInfoAllowlist, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("no-ca"), kSecValidInfoNoCACheck, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("no-ca-v2"), kSecValidInfoNoCAv2Check, &flags); - (void)_SecRevocationDbUpdateFlags(dict, CFSTR("overridable"), kSecValidInfoOverridable, &flags); - - /* date constraints exist if either "not-before" or "not-after" keys are found */ - CFTypeRef notBeforeValue = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-before")); - CFTypeRef notAfterValue = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-after")); - if (isDate(notBeforeValue) || isDate(notAfterValue)) { - (void)_SecRevocationDbUpdateFlags(dict, kBoolTrueKey, kSecValidInfoDateConstraints, &flags); - /* Note that the spec defines not-before and not-after dates as optional, such that - not providing one does not change the database contents. Therefore, we can never clear - this flag; either a new date entry will be supplied, or a format change will cause - the entire group entry to be deleted. */ - } - /* policy constraints exist if "policies" key is found */ - CFTypeRef policiesValue = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies")); - if (isArray(policiesValue)) { - (void)_SecRevocationDbUpdateFlags(dict, kBoolTrueKey, kSecValidInfoPolicyConstraints, &flags); - /* As above, not providing this value in an update does not change the existing state, - so we never need to clear this flag once it is set. */ - } - - /* %%% (TBI:9254570) name constraints don't exist yet */ - (void)_SecRevocationDbUpdateFlags(dict, kBoolFalseKey, kSecValidInfoNameConstraints, &flags); - - ok = SecDbBindInt(insertGroup, 2, (int)flags, &localError); - if (!ok) { - secdebug("validupdate", "failed to set flags (%lu) for groupId %lld", flags, (long long)groupId); - } - } - /* groups.format */ - if (ok) { - SecValidInfoFormat formatValue = format; - if (formatUpdate > kSecValidInfoFormatUnknown) { - formatValue = formatUpdate; - } - ok = SecDbBindInt(insertGroup, 3, (int)formatValue, &localError); - if (!ok) { - secdebug("validupdate", "failed to set format (%d) for groupId %lld", formatValue, (long long)groupId); - } - } - /* groups.data */ - CFDataRef xmlData = NULL; - if (ok) { - bool hasFilter = ((formatUpdate == kSecValidInfoFormatNto1) || - (formatUpdate == kSecValidInfoFormatUnknown && - format == kSecValidInfoFormatNto1)); - if (hasFilter) { - CFDataRef dataValue = data; /* use existing data */ - if (_SecRevocationDbUpdateFilter(dict, data, &xmlData)) { - dataValue = xmlData; /* use updated data */ - } - if (dataValue) { - ok = SecDbBindBlob(insertGroup, 4, - CFDataGetBytePtr(dataValue), - CFDataGetLength(dataValue), - SQLITE_TRANSIENT, &localError); - } - if (!ok) { - secdebug("validupdate", "failed to set data for groupId %lld", - (long long)groupId); - } - } - /* else there is no data, so NULL is implicitly bound to column 4 */ - } - /* groups.policies */ - CFDataRef newPoliciesData = NULL; - if (ok) { - CFDataRef policiesValue = policies; /* use existing policies */ - newPoliciesData = createPoliciesData((CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies"))); - if (newPoliciesData) { - policiesValue = newPoliciesData; /* use updated policies */ - } - if (policiesValue) { - ok = SecDbBindBlob(insertGroup, 5, - CFDataGetBytePtr(policiesValue), - CFDataGetLength(policiesValue), - SQLITE_TRANSIENT, &localError); - } - /* else there is no policy data, so NULL is implicitly bound to column 5 */ - if (!ok) { - secdebug("validupdate", "failed to set policies for groupId %lld", - (long long)groupId); - } - } - - /* Execute the insert statement for the group record. */ - if (ok) { - ok = SecDbStep(dbc->dbconn, insertGroup, &localError, NULL); - if (!ok) { - secdebug("validupdate", "failed to execute insertGroup statement for groupId %lld", - (long long)groupId); - } - result = (int64_t)sqlite3_last_insert_rowid(SecDbHandle(dbc->dbconn)); - } - if (!ok) { - secdebug("validupdate", "failed to insert group %lld", (long long)result); - } - /* Clean up temporary allocations made in this block. */ - CFReleaseSafe(xmlData); - CFReleaseSafe(newPoliciesData); - return ok; - }); - - CFReleaseSafe(data); - CFReleaseSafe(policies); - - if (!ok || localError) { - secerror("_SecRevocationDbUpdateGroup failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return result; -} - -static int64_t _SecRevocationDbGroupIdForIssuerHash(SecRevocationDbConnectionRef dbc, CFDataRef hash, CFErrorRef *error) { - /* look up issuer hash in issuers table to get groupid, if it exists */ - __block int64_t groupId = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - if (!hash) { - secdebug("validupdate", "failed to get hash (%@)", hash); - } - require(hash && dbc, errOut); - - /* This is the starting point for any lookup; find a group id for the given issuer hash. - Before we do that, need to verify the current db_version. We cannot use results from a - database created with a schema version older than the minimum supported version. - However, we may be able to use results from a newer version. At the next database - update interval, if the existing schema is old, we'll be removing and recreating - the database contents with the current schema version. - */ - int64_t db_version = _SecRevocationDbGetSchemaVersion(dbc->db, dbc, NULL); - if (db_version < kSecRevocationDbMinSchemaVersion) { - if (!dbc->db->unsupportedVersion) { - secdebug("validupdate", "unsupported db_version: %lld", (long long)db_version); - dbc->db->unsupportedVersion = true; /* only warn once for a given unsupported version */ - } - } - require_quiet(db_version >= kSecRevocationDbMinSchemaVersion, errOut); - - /* Look up provided issuer_hash in the issuers table. - */ - ok = ok && SecDbWithSQL(dbc->dbconn, selectGroupIdSQL, &localError, ^bool(sqlite3_stmt *selectGroupId) { - ok &= SecDbBindBlob(selectGroupId, 1, CFDataGetBytePtr(hash), CFDataGetLength(hash), SQLITE_TRANSIENT, &localError); - ok &= SecDbStep(dbc->dbconn, selectGroupId, &localError, ^(bool *stopGroupId) { - groupId = sqlite3_column_int64(selectGroupId, 0); - }); - return ok; - }); - -errOut: - if (!ok || localError) { - secerror("_SecRevocationDbGroupIdForIssuerHash failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return groupId; -} - -static bool _SecRevocationDbApplyGroupDelete(SecRevocationDbConnectionRef dbc, CFDataRef issuerHash, CFErrorRef *error) { - /* delete group associated with the given issuer; - schema trigger will delete associated issuers, serials, and hashes. */ - __block int64_t groupId = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - if (ok) { - groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, &localError); - } - if (groupId < 0) { - if (!localError) { - SecError(errSecParam, &localError, CFSTR("group not found for issuer")); - } - ok = false; - } - ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { - ok &= SecDbBindInt64(deleteResponse, 1, groupId, &localError); - /* Execute the delete statement. */ - ok = ok && SecDbStep(dbc->dbconn, deleteResponse, &localError, NULL); - return ok; - }); - if (!ok || localError) { - secerror("_SecRevocationDbApplyGroupDelete failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef dict, CFErrorRef *error) { - /* process one issuer group's update dictionary */ - __block int64_t groupId = -1; - __block bool ok = (dbc != NULL); - __block CFErrorRef localError = NULL; - - CFArrayRef issuers = (dict) ? (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("issuer-hash")) : NULL; - /* if this is not a full update, then look for existing group id */ - if (ok && isArray(issuers) && !dbc->fullUpdate) { - CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers); - /* while we have issuers and haven't found a matching group id */ - for (issuerIX=0; issuerIX= 0) { - /* according to the spec, we must replace all existing issuers with - the new issuers list, so delete all issuers in the group first. */ - ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupIssuersSQL, &localError, ^bool(sqlite3_stmt *deleteIssuers) { - ok = ok && SecDbBindInt64(deleteIssuers, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, deleteIssuers, &localError, NULL); - return ok; - }); - } - } - /* create or update the group entry */ - if (ok) { - groupId = _SecRevocationDbUpdateGroup(dbc, groupId, dict, &localError); - } - if (groupId < 0) { - secdebug("validupdate", "failed to get groupId"); - ok = false; - } else { - /* create or update issuer entries, now that we know the group id */ - ok = ok && _SecRevocationDbUpdateIssuers(dbc, groupId, issuers, &localError); - /* create or update entries in serials or hashes tables */ - ok = ok && _SecRevocationDbUpdateIssuerData(dbc, groupId, dict, &localError); - /* create or update entries in dates/names/policies tables */ - ok = ok && _SecRevocationDbUpdateIssuerConstraints(dbc, groupId, dict, &localError); - } - - (void) CFErrorPropagate(localError, error); - return ok; -} - -bool _SecRevocationDbApplyUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex version, CFErrorRef *error) { - /* process entire update dictionary */ - if (!dbc || !dbc->db || !update) { - secerror("_SecRevocationDbApplyUpdate failed: invalid args"); - SecError(errSecParam, error, CFSTR("_SecRevocationDbApplyUpdate: invalid db or update parameter")); - return false; - } - - CFDictionaryRef localUpdate = (CFDictionaryRef)CFRetainSafe(update); - CFErrorRef localError = NULL; - bool ok = true; - - CFTypeRef value = NULL; - CFIndex deleteCount = 0; - CFIndex updateCount = 0; - - dbc->db->updateInProgress = true; - - /* check whether this is a full update */ - value = (CFBooleanRef)CFDictionaryGetValue(update, CFSTR("full")); - if (isBoolean(value) && CFBooleanGetValue((CFBooleanRef)value)) { - /* clear the database before processing a full update */ - dbc->fullUpdate = true; - secdebug("validupdate", "update has \"full\" attribute; clearing database"); - ok = ok && _SecRevocationDbRemoveAllEntries(dbc, &localError); - } - - /* process 'delete' list */ - value = (CFArrayRef)CFDictionaryGetValue(localUpdate, CFSTR("delete")); - if (isArray(value)) { - deleteCount = CFArrayGetCount((CFArrayRef)value); - secdebug("validupdate", "processing %ld deletes", (long)deleteCount); - for (CFIndex deleteIX=0; deleteIXprecommitInterval) { - interval = (dbc->precommitInterval > 0) ? dbc->precommitInterval : kSecStdUpdateInterval; - ok = ok && _SecRevocationDbSetUpdateInterval(dbc, interval, &localError); - } - - /* set db_version if not already set */ - int64_t db_version = _SecRevocationDbGetSchemaVersion(dbc->db, dbc, NULL); - if (db_version <= 0) { - ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); - } - - /* set db_format if not already set */ - int64_t db_format = _SecRevocationDbGetUpdateFormat(dbc, NULL); - if (db_format <= 0) { - ok = ok && _SecRevocationDbSetUpdateFormat(dbc, kSecRevocationDbUpdateFormat, &localError); - } - - /* purge the in-memory cache */ - SecRevocationDbCachePurge(dbc->db); - - dbc->db->updateInProgress = false; - - (void) CFErrorPropagate(localError, error); - return ok; -} - -static bool _SecRevocationDbSerialInGroup(SecRevocationDbConnectionRef dbc, - CFDataRef serial, - int64_t groupId, - CFErrorRef *error) { - __block bool result = false; - __block bool ok = true; - __block CFErrorRef localError = NULL; - require(dbc && serial, errOut); - ok &= SecDbWithSQL(dbc->dbconn, selectSerialRecordSQL, &localError, ^bool(sqlite3_stmt *selectSerial) { - ok &= SecDbBindInt64(selectSerial, 1, groupId, &localError); - ok &= SecDbBindBlob(selectSerial, 2, CFDataGetBytePtr(serial), - CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); - ok &= SecDbStep(dbc->dbconn, selectSerial, &localError, ^(bool *stop) { - int64_t foundRowId = (int64_t)sqlite3_column_int64(selectSerial, 0); - result = (foundRowId > 0); - }); - return ok; - }); - -errOut: - if (!ok || localError) { - secerror("_SecRevocationDbSerialInGroup failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return result; -} - -static bool _SecRevocationDbCertHashInGroup(SecRevocationDbConnectionRef dbc, - CFDataRef certHash, - int64_t groupId, - CFErrorRef *error) { - __block bool result = false; - __block bool ok = true; - __block CFErrorRef localError = NULL; - require(dbc && certHash, errOut); - ok &= SecDbWithSQL(dbc->dbconn, selectHashRecordSQL, &localError, ^bool(sqlite3_stmt *selectHash) { - ok &= SecDbBindInt64(selectHash, 1, groupId, &localError); - ok = SecDbBindBlob(selectHash, 2, CFDataGetBytePtr(certHash), - CFDataGetLength(certHash), SQLITE_TRANSIENT, &localError); - ok &= SecDbStep(dbc->dbconn, selectHash, &localError, ^(bool *stop) { - int64_t foundRowId = (int64_t)sqlite3_column_int64(selectHash, 0); - result = (foundRowId > 0); - }); - return ok; - }); - -errOut: - if (!ok || localError) { - secerror("_SecRevocationDbCertHashInGroup failed: %@", localError); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, - localError ? CFErrorGetCode(localError) : errSecInternalComponent); - } - (void) CFErrorPropagate(localError, error); - return result; -} - -static bool _SecRevocationDbSerialInFilter(SecRevocationDbConnectionRef dbc, - CFDataRef serialData, - CFDataRef xmlData) { - /* N-To-1 filter implementation. - The 'xmlData' parameter is a flattened XML dictionary, - containing 'xor' and 'params' keys. First order of - business is to reconstitute the blob into components. - */ - bool result = false; - CFRetainSafe(xmlData); - CFDataRef propListData = xmlData; - /* Expand data blob if needed */ - CFDataRef inflatedData = copyInflatedData(propListData); - if (inflatedData) { - CFReleaseSafe(propListData); - propListData = inflatedData; - } - CFDataRef xor = NULL; - CFArrayRef params = NULL; - CFPropertyListRef nto1 = CFPropertyListCreateWithData(kCFAllocatorDefault, propListData, 0, NULL, NULL); - if (nto1) { - xor = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("xor")); - params = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("params")); - } - uint8_t *hash = (xor) ? (uint8_t*)CFDataGetBytePtr(xor) : NULL; - CFIndex hashLen = (hash) ? CFDataGetLength(xor) : 0; - uint8_t *serial = (serialData) ? (uint8_t*)CFDataGetBytePtr(serialData) : NULL; - CFIndex serialLen = (serial) ? CFDataGetLength(serialData) : 0; - - require(hash && serial && params, errOut); - - const uint32_t FNV_OFFSET_BASIS = 2166136261; - const uint32_t FNV_PRIME = 16777619; - bool notInHash = false; - CFIndex ix, count = CFArrayGetCount(params); - for (ix = 0; ix < count; ix++) { - int32_t param; - CFNumberRef cfnum = (CFNumberRef)CFArrayGetValueAtIndex(params, ix); - if (!isNumber(cfnum) || - !CFNumberGetValue(cfnum, kCFNumberSInt32Type, ¶m)) { - secinfo("validupdate", "error processing filter params at index %ld", (long)ix); - continue; - } - /* process one param */ - uint32_t hval = FNV_OFFSET_BASIS ^ param; - CFIndex i = serialLen; - while (i > 0) { - hval = ((hval ^ (serial[--i])) * FNV_PRIME) & 0xFFFFFFFF; - } - hval = hval % (hashLen * 8); - if ((hash[hval/8] & (1 << (hval % 8))) == 0) { - notInHash = true; /* definitely not in hash */ - break; - } - } - if (!notInHash) { - /* probabilistically might be in hash if we get here. */ - result = true; - } - -errOut: - CFReleaseSafe(nto1); - CFReleaseSafe(propListData); - return result; -} - -static SecValidInfoRef _SecRevocationDbValidInfoForCertificate(SecRevocationDbConnectionRef dbc, - SecCertificateRef certificate, - CFDataRef issuerHash, - CFErrorRef *error) { - __block CFErrorRef localError = NULL; - __block SecValidInfoFlags flags = 0; - __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; - __block CFDataRef data = NULL; - - bool matched = false; - bool isOnList = false; - int64_t groupId = 0; - CFDataRef serial = NULL; - CFDataRef certHash = NULL; - CFDateRef notBeforeDate = NULL; - CFDateRef notAfterDate = NULL; - CFDataRef names = NULL; - CFDataRef policies = NULL; - SecValidInfoRef result = NULL; - - require((serial = SecCertificateCopySerialNumberData(certificate, NULL)) != NULL, errOut); - require((certHash = SecCertificateCopySHA256Digest(certificate)) != NULL, errOut); - require_quiet((groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, &localError)) > 0, errOut); - - /* Look up the group record to determine flags and format. */ - format = _SecRevocationDbGetGroupFormat(dbc, groupId, &flags, &data, &policies, &localError); - - if (format == kSecValidInfoFormatUnknown) { - /* No group record found for this issuer. Don't return a SecValidInfoRef */ - goto errOut; - } - else if (format == kSecValidInfoFormatSerial) { - /* Look up certificate's serial number in the serials table. */ - matched = _SecRevocationDbSerialInGroup(dbc, serial, groupId, &localError); - } - else if (format == kSecValidInfoFormatSHA256) { - /* Look up certificate's SHA-256 hash in the hashes table. */ - matched = _SecRevocationDbCertHashInGroup(dbc, certHash, groupId, &localError); - } - else if (format == kSecValidInfoFormatNto1) { - /* Perform a Bloom filter match against the serial. If matched is false, - then the cert is definitely not in the list. But if matched is true, - we don't know for certain, so we would need to check OCSP. */ - matched = _SecRevocationDbSerialInFilter(dbc, serial, data); - } - - if (matched) { - /* Found a specific match for this certificate. */ - secdebug("validupdate", "Valid db matched certificate: %@, format=%d, flags=0x%lx", - certHash, format, flags); - isOnList = true; - } - - /* If supplemental constraints are present for this issuer, then we always match. */ - if ((flags & kSecValidInfoDateConstraints) && - (_SecRevocationDbCopyDateConstraints(dbc, groupId, ¬BeforeDate, ¬AfterDate, &localError))) { - secdebug("validupdate", "Valid db matched supplemental date constraints for groupId %lld: nb=%@, na=%@", - (long long)groupId, notBeforeDate, notAfterDate); - } - - - /* Return SecValidInfo for certificates for which an issuer entry is found. */ - result = SecValidInfoCreate(format, flags, isOnList, - certHash, issuerHash, /*anchorHash*/ NULL, - notBeforeDate, notAfterDate, - names, policies); - - if (result && SecIsAppleTrustAnchor(certificate, 0)) { - /* Prevent a catch-22. */ - secdebug("validupdate", "Valid db match for Apple trust anchor: %@, format=%d, flags=0x%lx", - certHash, format, flags); - CFReleaseNull(result); - } - -errOut: - (void) CFErrorPropagate(localError, error); - CFReleaseSafe(data); - CFReleaseSafe(certHash); - CFReleaseSafe(serial); - CFReleaseSafe(notBeforeDate); - CFReleaseSafe(notAfterDate); - CFReleaseSafe(names); - CFReleaseSafe(policies); - return result; -} - -static SecValidInfoRef _SecRevocationDbCopyMatching(SecRevocationDbConnectionRef dbc, - SecCertificateRef certificate, - SecCertificateRef issuer) { - SecValidInfoRef result = NULL; - CFErrorRef error = NULL; - CFDataRef issuerHash = NULL; - - require(dbc && certificate && issuer, errOut); - require(issuerHash = SecCertificateCopySHA256Digest(issuer), errOut); - - /* Check for the result in the cache. */ - result = SecRevocationDbCacheRead(dbc->db, certificate, issuerHash); - - /* Upon cache miss, get the result from the database and add it to the cache. */ - if (!result) { - result = _SecRevocationDbValidInfoForCertificate(dbc, certificate, issuerHash, &error); - SecRevocationDbCacheWrite(dbc->db, result); - } - -errOut: - CFReleaseSafe(issuerHash); - CFReleaseSafe(error); - return result; -} - -/* Return the update source as a retained CFStringRef. - If the value cannot be obtained, NULL is returned. -*/ -CFStringRef SecRevocationDbCopyUpdateSource(void) { - __block CFStringRef result = NULL; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - result = _SecRevocationDbCopyUpdateSource(dbc, blockError); - return (bool)result; - }); - }); - return result; -} - -/* Set the next update value for the revocation database. - (This function is expected to be called only by the database - maintainer, normally the system instance of trustd. If the - caller does not have write access, this is a no-op.) -*/ -bool SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate, CFErrorRef *error) { - __block bool ok = true; - __block CFErrorRef localError = NULL; - SecRevocationDbWith(^(SecRevocationDbRef rdb) { - ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - return _SecRevocationDbSetNextUpdateTime(dbc, nextUpdate, blockError); - }); - }); - (void) CFErrorPropagate(localError, error); - return ok; -} - -/* Return the next update value as a CFAbsoluteTime. - If the value cannot be obtained, -1 is returned. -*/ -CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void) { - __block CFAbsoluteTime result = -1; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - result = _SecRevocationDbGetNextUpdateTime(dbc, blockError); - return true; - }); - }); - return result; -} - -/* Return the serial background queue for database updates. - If the queue cannot be obtained, NULL is returned. -*/ -dispatch_queue_t SecRevocationDbGetUpdateQueue(void) { - __block dispatch_queue_t result = NULL; - SecRevocationDbWith(^(SecRevocationDbRef db) { - result = (db) ? db->update_queue : NULL; - }); - return result; -} - -/* Release all connections to the revocation database. -*/ -void SecRevocationDbReleaseAllConnections(void) { - SecRevocationDbWith(^(SecRevocationDbRef db) { - SecDbReleaseAllConnections((db) ? db->db : NULL); - }); -} - -/* === SecRevocationDb API === */ - -/* Given a certificate and its issuer, returns a SecValidInfoRef if the - valid database contains matching info; otherwise returns NULL. - Caller must release the returned SecValidInfoRef when finished. -*/ -SecValidInfoRef SecRevocationDbCopyMatching(SecCertificateRef certificate, - SecCertificateRef issuer) { - __block SecValidInfoRef result = NULL; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - result = _SecRevocationDbCopyMatching(dbc, certificate, issuer); - return (bool)result; - }); - }); - return result; -} - -/* Given an issuer, returns true if an entry for this issuer exists in - the database (i.e. a known CA). If the provided certificate is NULL, - or its entry is not found, the function returns false. -*/ -bool SecRevocationDbContainsIssuer(SecCertificateRef issuer) { - if (!issuer) { - return false; - } - __block bool result = false; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - CFDataRef issuerHash = SecCertificateCopySHA256Digest(issuer); - int64_t groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, blockError); - CFReleaseSafe(issuerHash); - result = (groupId > 0); - return result; - }); - }); - return result; -} - -/* Return the current version of the revocation database. - A version of 0 indicates an empty database which must be populated. - If the version cannot be obtained, -1 is returned. -*/ -CFIndex SecRevocationDbGetVersion(void) { - __block CFIndex result = -1; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - result = (CFIndex)_SecRevocationDbGetVersion(dbc, blockError); - return (result >= 0); - }); - }); - return result; -} - -/* Return the current schema version of the revocation database. - A version of 0 indicates an empty database which must be populated. - If the schema version cannot be obtained, -1 is returned. - */ -CFIndex SecRevocationDbGetSchemaVersion(void) { - __block CFIndex result = -1; - SecRevocationDbWith(^(SecRevocationDbRef db) { - result = (CFIndex)_SecRevocationDbGetSchemaVersion(db, NULL, NULL); - }); - return result; -} - -/* Return the current update format of the revocation database. - A version of 0 indicates the format was unknown. - If the update format cannot be obtained, -1 is returned. - */ -CFIndex SecRevocationDbGetUpdateFormat(void) { - __block CFIndex result = -1; - SecRevocationDbWith(^(SecRevocationDbRef db) { - (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { - result = (CFIndex)_SecRevocationDbGetUpdateFormat(dbc, blockError); - return (result >= 0); - }); - }); - return result; -} - -// MARK: - -// MARK: Digests -/* - ============================================================================== - Digest computation - ============================================================================== -*/ - -/* Returns array of SHA-256 hashes computed over the contents of a valid.sqlite3 - database, in the order specified by the valid-server-api documentation. The - resulting hashes can be compared against those in the update's 'hash' array. - - Hash 0: full database (all fields in initial Valid specification) - Hash 1: all issuer_hash arrays, plus not-after and not-before dates for each - Hash 2: subset of issuer_hash arrays where the no-ca-v2 flag is set -*/ -static CF_RETURNS_RETAINED CFArrayRef SecRevocationDbComputeFullContentDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - if (!dbc) { return NULL; } - __block bool ok = true; - __block CFErrorRef localError = NULL; - __block uint32_t N[4]={0,0,0,0}; - __block CC_SHA256_CTX hash0_ctx, hash1_ctx, hash2_ctx; - CC_SHA256_Init(&hash0_ctx); - CC_SHA256_Init(&hash1_ctx); - CC_SHA256_Init(&hash2_ctx); - - // Add version, check-again, and update (array count) fields as array of N. - // (Note: 'N' is defined as "unsigned 32-bit integer in network byte order") - int64_t version = _SecRevocationDbGetVersion(dbc, NULL); - N[0] = OSSwapInt32(version & 0xffffffff); - int64_t interval = _SecRevocationDbGetUpdateInterval(dbc, NULL); - if (interval < 0) { - interval = kSecStdUpdateInterval; // if we didn't store it, assume default - } - N[1] = OSSwapInt32(interval & 0xffffffff); - __block int64_t count = 0; - ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT count(*) FROM groups"), &localError, ^bool(sqlite3_stmt *selectGroupsCount) { - ok = ok && SecDbStep(dbc->dbconn, selectGroupsCount, &localError, ^void(bool *stop) { - count = sqlite3_column_int64(selectGroupsCount, 0); - *stop = true; - }); - return ok; - }); - N[2] = OSSwapInt32(count & 0xffffffff); - CC_SHA256_Update(&hash0_ctx, N, sizeof(uint32_t) * 3); - - // Sort the update array in order of minimum 'issuer-hash' entry. - // The issuer-hash array is first sorted to determine the lowest issuer-hash, - // and that value is used to sort the update entries. - // - // For our sqlite database, recreating the update array order means fetching - // the groupid column from the issuers table after sorting on issuer_hash, - // using DISTINCT to remove duplicates. Then, for each returned groupid, we - // obtain its list of issuers, its list of serials or hashes, and other data. - - ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT DISTINCT groupid FROM issuers ORDER BY issuer_hash ASC"), &localError, ^bool(sqlite3_stmt *selectGroups) { - ok = ok && SecDbForEach(dbc->dbconn, selectGroups, &localError, ^bool(int row_index) { - __block int64_t groupId = sqlite3_column_int64(selectGroups, 0); - ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT flags,format,data FROM groups WHERE groupid=?"), &localError, ^bool(sqlite3_stmt *selectGroup) { - ok = ok && SecDbBindInt64(selectGroup, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, selectGroup, &localError, ^(bool *stop) { - // per-group info is hashed in the following order: - // - issuer_hash array data (sorted) - // - flag bytes, in order listed below - // - format string [serial|sha256|nto1] - // - add array data (sorted), if [serial|sha256] - // - params (if present) - // - xor data (if present) - - int64_t flags = sqlite3_column_int64(selectGroup, 0); - bool noCAv2 = (flags & kSecValidInfoNoCAv2Check); - - // instead of recreating the issuer_hash array in memory, - // hash its length (item count) followed by the data of each issuer_hash. - ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT count(*) FROM issuers WHERE groupid=?"), &localError, ^bool(sqlite3_stmt *selectIssuersCount) { - ok = ok && SecDbBindInt64(selectIssuersCount, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, selectIssuersCount, &localError, ^void(bool *stop) { - count = sqlite3_column_int64(selectIssuersCount, 0); - *stop = true; - }); - return ok; - }); - uint32_t n = OSSwapInt32(count & 0xffffffff); - CC_SHA256_Update(&hash0_ctx, &n, sizeof(uint32_t)); - CC_SHA256_Update(&hash1_ctx, &n, sizeof(uint32_t)); - if (noCAv2) { - CC_SHA256_Update(&hash2_ctx, &n, sizeof(uint32_t)); - } - - // process issuer_hash entries for this group - ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT issuer_hash FROM issuers WHERE groupid=? ORDER BY issuer_hash ASC"), &localError, ^bool(sqlite3_stmt *selectIssuerHash) { - ok = ok && SecDbBindInt64(selectIssuerHash, 1, groupId, &localError); - ok = ok && SecDbForEach(dbc->dbconn, selectIssuerHash, &localError, ^bool(int row_index) { - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectIssuerHash, 0); - CFDataRef data = NULL; - if (p != NULL) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectIssuerHash, 0); - data = CFDataCreate(kCFAllocatorDefault, p, length); - } - if (data != NULL) { - hashData(data, &hash0_ctx); - hashData(data, &hash1_ctx); - if (noCAv2) { - hashData(data, &hash2_ctx); - } - CFRelease(data); - } else { - ok = false; - } - return ok; - }); - return ok; - }); - - // process flags, converting to array of unsigned 8-bit values, either 0 or 1: - // [ complete, check-ocsp, known-intermediates-only, no-ca, overridable, require-ct, valid ] - uint8_t C[8]={0,0,0,0,0,0,0,0}; - C[0] = (flags & kSecValidInfoComplete) ? 1 : 0; - C[1] = (flags & kSecValidInfoCheckOCSP) ? 1 : 0; - C[2] = (flags & kSecValidInfoKnownOnly) ? 1 : 0; - C[3] = (flags & kSecValidInfoNoCACheck) ? 1 : 0; - C[4] = (flags & kSecValidInfoOverridable) ? 1 : 0; - C[5] = (flags & kSecValidInfoRequireCT) ? 1 : 0; - C[6] = (flags & kSecValidInfoAllowlist) ? 1 : 0; - CC_SHA256_Update(&hash0_ctx, C, sizeof(uint8_t) * 7); - - // process format, converting integer to string value [serial|sha256|nto1] - SecValidInfoFormat format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); - switch (format) { - case kSecValidInfoFormatSerial: - hashString(CFSTR("serial"), &hash0_ctx); - break; - case kSecValidInfoFormatSHA256: - hashString(CFSTR("sha256"), &hash0_ctx); - break; - case kSecValidInfoFormatNto1: - hashString(CFSTR("nto1"), &hash0_ctx); - break; - case kSecValidInfoFormatUnknown: - default: - ok = false; // unexpected format values are not allowed - break; - } - // process 'add' array (serial or sha256 format). - // instead of recreating the 'add' array in memory, - // hash its length (item count) followed by the data of each entry. - CFStringRef arrayCountSql = NULL; - if (format == kSecValidInfoFormatSerial) { - arrayCountSql = CFSTR("SELECT count(*) FROM serials WHERE groupid=?"); - } else if (format == kSecValidInfoFormatSHA256) { - arrayCountSql = CFSTR("SELECT count(*) FROM hashes WHERE groupid=?"); - } - if (arrayCountSql) { - ok = ok && SecDbWithSQL(dbc->dbconn, arrayCountSql, &localError, ^bool(sqlite3_stmt *selectAddCount) { - ok = ok && SecDbBindInt64(selectAddCount, 1, groupId, &localError); - ok = ok && SecDbStep(dbc->dbconn, selectAddCount, &localError, ^void(bool *stop) { - count = sqlite3_column_int64(selectAddCount, 0); - *stop = true; - }); - return ok; - }); - n = OSSwapInt32(count & 0xffffffff); - CC_SHA256_Update(&hash0_ctx, &n, sizeof(uint32_t)); - } - // process data entries for this group - CFStringRef arrayDataSql = NULL; - if (format == kSecValidInfoFormatSerial) { - arrayDataSql = CFSTR("SELECT serial FROM serials WHERE groupid=? ORDER BY serial ASC"); - } else if (format == kSecValidInfoFormatSHA256) { - arrayDataSql = CFSTR("SELECT sha256 FROM hashes WHERE groupid=? ORDER by sha256 ASC"); - } - if (arrayDataSql) { - ok = ok && SecDbWithSQL(dbc->dbconn, arrayDataSql, &localError, ^bool(sqlite3_stmt *selectAddData) { - ok = ok && SecDbBindInt64(selectAddData, 1, groupId, &localError); - ok = ok && SecDbForEach(dbc->dbconn, selectAddData, &localError, ^bool(int row_index) { - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectAddData, 0); - CFDataRef data = NULL; - if (p != NULL) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectAddData, 0); - data = CFDataCreate(kCFAllocatorDefault, p, length); - } - if (data != NULL) { - hashData(data, &hash0_ctx); - CFRelease(data); - } else { - ok = false; - } - return ok; - }); - return ok; - }); - } - - // process params and xor data, if format is nto1 - if (format == kSecValidInfoFormatNto1) { - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); - CFDataRef data = NULL; - if (p != NULL) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); - data = CFDataCreate(kCFAllocatorDefault, p, length); - } - if (data != NULL) { - // unpack params and xor data - CFDataRef xor = NULL; - CFArrayRef params = NULL; - if (copyFilterComponents(data, &xor, ¶ms)) { - hashArray(params, &hash0_ctx); - hashData(xor, &hash0_ctx); - } else { - ok = false; - } - CFReleaseSafe(xor); - CFReleaseSafe(params); - } - CFReleaseSafe(data); - } - - // process date constraints [not-after, not-before] - CFAbsoluteTime notBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ - CFAbsoluteTime notAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ - CFDateRef notBeforeDate = NULL; - CFDateRef notAfterDate = NULL; - if (_SecRevocationDbCopyDateConstraints(dbc, groupId, ¬BeforeDate, ¬AfterDate, &localError)) { - if (notBeforeDate) { - notBefore = CFDateGetAbsoluteTime(notBeforeDate); - CFReleaseNull(notBeforeDate); - } - if (notAfterDate) { - notAfter = CFDateGetAbsoluteTime(notAfterDate); - CFReleaseNull(notAfterDate); - } - } - double nb = htond(notBefore); - double na = htond(notAfter); - CC_SHA256_Update(&hash1_ctx, &na, sizeof(double)); - CC_SHA256_Update(&hash1_ctx, &nb, sizeof(double)); - - *stop = true; - }); // per-group step - return ok; - }); // per-group select - return ok; - }); // for each group in list - return ok; - }); // select full group list - - CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (result) { - uint8_t digest[CC_SHA256_DIGEST_LENGTH]; - CFDataRef data = NULL; - CC_SHA256_Final(digest, &hash0_ctx); - if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { - CFArrayAppendValue(result, data); - CFReleaseNull(data); - } - CC_SHA256_Final(digest, &hash1_ctx); - if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { - CFArrayAppendValue(result, data); - CFReleaseNull(data); - } - CC_SHA256_Final(digest, &hash2_ctx); - if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { - CFArrayAppendValue(result, data); - CFReleaseNull(data); - } - } - (void) CFErrorPropagate(localError, error); - return result; -} - -static bool SecRevocationDbComputeDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { - secinfo("validupdate", "Started verifying db content"); - bool result = true; - CFArrayRef expectedList = _SecRevocationDbCopyHashes(dbc, error); - CFIndex expectedCount = (expectedList) ? CFArrayGetCount(expectedList) : 0; - if (expectedCount < 1) { - secinfo("validupdate", "Unable to read db_hash values"); - CFReleaseNull(expectedList); - return result; // %%%% this will happen on first update, when db_hash isn't there - } - CFArrayRef computedList = SecRevocationDbComputeFullContentDigests(dbc, error); - CFIndex computedCount = (computedList) ? CFArrayGetCount(computedList) : 0; - for (CFIndex idx = 0; idx < expectedCount; idx++) { - if (idx >= computedCount) { - continue; // server provided additional hash value that we don't yet compute - } - CFDataRef expectedHash = (CFDataRef)CFArrayGetValueAtIndex(expectedList, idx); - CFDataRef computedHash = (CFDataRef)CFArrayGetValueAtIndex(computedList, idx); - if (!CFEqualSafe(expectedHash, computedHash)) { - result = false; - break; - } - } - if (!result) { - secinfo("validupdate", "Expected: %@", expectedList); - secinfo("validupdate", "Computed: %@", computedList); - } - secinfo("validupdate", "Finished verifying db content; result=%s", - (result) ? "SUCCESS" : "FAIL"); - CFReleaseSafe(expectedList); - CFReleaseSafe(computedList); - return result; -} - diff --git a/OSX/sec/securityd/SecRevocationDb.h b/OSX/sec/securityd/SecRevocationDb.h deleted file mode 100644 index 8559cfb5..00000000 --- a/OSX/sec/securityd/SecRevocationDb.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -/*! - @header SecRevocationDb - The functions in SecRevocationDb.h provide an interface to look up - revocation information, and refresh that information periodically. - */ - -#ifndef _SECURITY_SECREVOCATIONDB_H_ -#define _SECURITY_SECREVOCATIONDB_H_ - -#include -#include -#include -#include -#include -#include -#include - -__BEGIN_DECLS - -/* issuer group data format */ -typedef CF_ENUM(uint32_t, SecValidInfoFormat) { - kSecValidInfoFormatUnknown = 0, - kSecValidInfoFormatSerial = 1, - kSecValidInfoFormatSHA256 = 2, - kSecValidInfoFormatNto1 = 3 -}; - -/* policy types */ -typedef CF_ENUM(int8_t, SecValidPolicy) { - kSecValidPolicyNone = -1, - kSecValidPolicyAny = 0, - kSecValidPolicyServerAuthentication = 1, - kSecValidPolicyClientAuthentication = 2, - kSecValidPolicyEmailProtection = 3, - kSecValidPolicyCodeSigning = 4, - kSecValidPolicyTimeStamping = 5, -}; - -/*! - @typedef SecValidInfoRef - @abstract CFType used to return valid info lookup results. - */ -typedef struct __SecValidInfo *SecValidInfoRef; - -struct __SecValidInfo { - CFRuntimeBase _base; - - SecValidInfoFormat format; // format of per-issuer validity data - CFDataRef certHash; // SHA-256 hash of cert to which the following info applies - CFDataRef issuerHash; // SHA-256 hash of issuing CA certificate - CFDataRef anchorHash; // SHA-256 hash of anchor certificate (optional) - bool isOnList; // true if this cert was found on allow list or block list - bool valid; // true if this is an allow list, false if a block list - bool complete; // true if list is complete (i.e. status is definitive) - bool checkOCSP; // true if complete is false and OCSP check is required - bool knownOnly; // true if intermediate CAs under issuer must be found in database - bool requireCT; // true if this cert must have CT proof - bool noCACheck; // true if an entry does not require an OCSP check to accept - bool overridable; // true if the trust status is recoverable and can be overridden - bool hasDateConstraints; // true if this issuer has supplemental date constraints - bool hasNameConstraints; // true if this issuer has supplemental name constraints - bool hasPolicyConstraints; // true if this issuer has policy constraints - CFDateRef notBeforeDate; // minimum notBefore for this certificate (if hasDateConstraints is true) - CFDateRef notAfterDate; // maximum notAfter for this certificate (if hasDateConstraints is true) - CFDataRef nameConstraints; // name constraints blob (if hasNameConstraints is true) - CFDataRef policyConstraints; // policy constraints blob (if policyConstraints is true) -}; - -/*! - @function SecValidInfoSetAnchor - @abstract Updates a SecValidInfo reference with info about the anchor certificate in a chain. - @param validInfo The SecValidInfo reference to be updated. - @param anchor The certificate which anchors the chain for the certificate in this SecValidInfo reference. - @discussion A SecValidInfo reference contains information about a single certificate and its issuer. In some cases, it may be necessary to additionally examine the anchor of the certificate chain to determine validity. - */ -void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor); - -/*! - @function SecRevocationDbCheckNextUpdate - @abstract Periodic hook to poll for updates. - */ -void SecRevocationDbCheckNextUpdate(void); - -/*! - @function SecRevocationDbCopyMatching - @abstract Returns a SecValidInfo reference if matching revocation (or allow list) info was found. - @param certificate The certificate whose validity status is being requested. - @param issuer The issuing CA certificate. If the cert is self-signed, the same reference should be passed in both certificate and issuer parameters. Omitting either cert parameter is an error and NULL will be returned. - @result A SecValidInfoRef if there was matching revocation info. Caller must release this reference when finished by calling CFRelease. NULL is returned if no matching info was found in the database. - */ -SecValidInfoRef SecRevocationDbCopyMatching(SecCertificateRef certificate, - SecCertificateRef issuer); - -/*! - @function SecRevocationDbContainsIssuer - @abstract Returns true if the database contains an entry for the specified CA certificate. - @param issuer The certificate being checked. - @result If a matching issuer group was found, returns true, otherwise false. -*/ -bool SecRevocationDbContainsIssuer(SecCertificateRef issuer); - -/*! - @function SecRevocationDbGetVersion - @abstract Returns a CFIndex containing the version number of the database. - @result On success, the returned version will be a value greater than or equal to zero. A version of 0 indicates an empty database which has yet to be populated. If the version cannot be obtained, -1 is returned. - */ -CFIndex SecRevocationDbGetVersion(void); - -/*! - @function SecRevocationDbGetSchemaVersion - @abstract Returns a CFIndex containing the schema version number of the database. - @result On success, the returned version will be a value greater than or equal to zero. A version of 0 indicates an empty database which has yet to be populated. If the version cannot be obtained, -1 is returned. - */ -CFIndex SecRevocationDbGetSchemaVersion(void); - -/*! - @function SecValidUpdateVerifyAndIngest - @abstract Callback for receiving update data. - @param updateData The decompressed update data. - @param updateServer The source server for this data. - @param fullUpdate If true, a full update was requested. - */ -void SecValidUpdateVerifyAndIngest(CFDataRef updateData, CFStringRef updateServer, bool fullUpdate); - -/*! - @function readValidFile - @abstract Reads data into a CFDataRef using mmap. - @param fileName The file to read. - @param bytes The data read from the file. - @result An integer indicating failure (non-zero) or success. - @discussion This function mmaps the file and then makes a no-copy CFData for use of that mmapped file. This data MUST be munmapped when the caller has finished with the data. - */ -int readValidFile(const char *fileName, CFDataRef *bytes); - -/*! - @function SecRevocationDbComputeAndSetNextUpdateTime - @abstract Callback to push forward next update. - */ -void SecRevocationDbComputeAndSetNextUpdateTime(void); - -/*! - @function SecRevocationDbInitialize - @abstract Initializes revocation database if it doesn't exist or needs to be replaced. This should only be called once at process startup, before any database connections are established. - */ -void SecRevocationDbInitialize(void); - -extern const CFStringRef kValidUpdateProdServer; -extern const CFStringRef kValidUpdateSeedServer; -extern const CFStringRef kValidUpdateCarryServer; - -/*! - @function SecRevocationDbCopyUpdateSource - @abstract Returns the server source for updates of the revocation database. - @result The base string of the server URI. - */ -CFStringRef SecRevocationDbCopyUpdateSource(void); - - -__END_DECLS - -#endif /* _SECURITY_SECREVOCATIONDB_H_ */ diff --git a/OSX/sec/securityd/SecRevocationNetworking.h b/OSX/sec/securityd/SecRevocationNetworking.h deleted file mode 100644 index 8c36345d..00000000 --- a/OSX/sec/securityd/SecRevocationNetworking.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -#ifndef _SECURITY_SECREVOCATIONNETWORKING_H_ -#define _SECURITY_SECREVOCATIONNETWORKING_H_ - -#import -#import - -bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version); -bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert); - -#endif /* _SECURITY_SECREVOCATIONNETWORKING_H_ */ diff --git a/OSX/sec/securityd/SecRevocationNetworking.m b/OSX/sec/securityd/SecRevocationNetworking.m deleted file mode 100644 index c1852066..00000000 --- a/OSX/sec/securityd/SecRevocationNetworking.m +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (c) 2017-2019 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -#include -#import -#import - -#include -#include -#include -#include -#include -#include "utilities/debugging.h" -#include "utilities/SecCFWrappers.h" -#include "utilities/SecPLWrappers.h" -#include "utilities/SecFileLocations.h" - -#include "SecRevocationDb.h" -#include "SecRevocationServer.h" -#include "SecTrustServer.h" -#include "SecOCSPRequest.h" -#include "SecOCSPResponse.h" - -#import "SecTrustLoggingServer.h" -#import "TrustURLSessionDelegate.h" - -#import "SecRevocationNetworking.h" - -/* MARK: Valid Update Networking */ -static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); -static CFStringRef kUpdateWiFiOnlyKey = CFSTR("ValidUpdateWiFiOnly"); -static CFStringRef kUpdateBackgroundKey = CFSTR("ValidUpdateBackground"); - -extern CFAbsoluteTime gUpdateStarted; -extern CFAbsoluteTime gNextUpdate; - -static int checkBasePath(const char *basePath) { - return mkpath_np((char*)basePath, 0755); -} - -static uint64_t systemUptimeInSeconds() { - struct timeval boottime; - size_t tv_size = sizeof(boottime); - time_t now, uptime = 0; - int mib[2]; - mib[0] = CTL_KERN; - mib[1] = KERN_BOOTTIME; - (void) time(&now); - if (sysctl(mib, 2, &boottime, &tv_size, NULL, 0) != -1 && - boottime.tv_sec != 0) { - uptime = now - boottime.tv_sec; - } - return (uint64_t)uptime; -} - -typedef void (^CompletionHandler)(void); - -@interface ValidDelegate : NSObject -@property CompletionHandler handler; -@property dispatch_queue_t revDbUpdateQueue; -@property os_transaction_t transaction; -@property NSString *currentUpdateServer; -@property NSFileHandle *currentUpdateFile; -@property NSURL *currentUpdateFileURL; -@property BOOL finishedDownloading; -@end - -@implementation ValidDelegate - -- (void)reschedule { - /* POWER LOG EVENT: operation canceled */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : (self->_finishedDownloading) ? @"updateCanceled" : @"downloadCanceled" - }); - secnotice("validupdate", "%s canceled at %f", - (self->_finishedDownloading) ? "update" : "download", - (double)CFAbsoluteTimeGetCurrent()); - - self->_handler(); - SecRevocationDbComputeAndSetNextUpdateTime(); - if (self->_transaction) { - self->_transaction = nil; - } -} - -- (void)updateDb:(NSUInteger)version { - __block NSURL *updateFileURL = self->_currentUpdateFileURL; - __block NSString *updateServer = self->_currentUpdateServer; - __block NSFileHandle *updateFile = self->_currentUpdateFile; - if (!updateFileURL || !updateFile) { - [self reschedule]; - return; - } - - /* Hold a transaction until we finish the update */ - __block os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.updateDb"); - dispatch_async(_revDbUpdateQueue, ^{ - /* POWER LOG EVENT: background update started */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : @"updateStarted" - }); - secnotice("validupdate", "update started at %f", (double)CFAbsoluteTimeGetCurrent()); - - CFDataRef updateData = NULL; - const char *updateFilePath = [updateFileURL fileSystemRepresentation]; - int rtn; - if ((rtn = readValidFile(updateFilePath, &updateData)) != 0) { - secerror("failed to read %@ with error %d", updateFileURL, rtn); - TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, rtn); - [self reschedule]; - transaction = nil; - return; - } - - secdebug("validupdate", "verifying and ingesting data from %@", updateFileURL); - SecValidUpdateVerifyAndIngest(updateData, (__bridge CFStringRef)updateServer, (0 == version)); - if ((rtn = munmap((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) != 0) { - secerror("unable to unmap current update %ld bytes at %p (error %d)", CFDataGetLength(updateData), CFDataGetBytePtr(updateData), rtn); - } - CFReleaseNull(updateData); - - /* We're done with this file */ - [updateFile closeFile]; - if (updateFilePath) { - (void)remove(updateFilePath); - } - self->_currentUpdateFile = nil; - self->_currentUpdateFileURL = nil; - self->_currentUpdateServer = nil; - - /* POWER LOG EVENT: background update finished */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : @"updateFinished" - }); - - /* Update is complete */ - secnotice("validupdate", "update finished at %f", (double)CFAbsoluteTimeGetCurrent()); - gUpdateStarted = 0; - - self->_handler(); - transaction = nil; // we're all done now - }); -} - -- (NSInteger)versionFromTask:(NSURLSessionTask *)task { - return atol([task.taskDescription cStringUsingEncoding:NSUTF8StringEncoding]); -} - -- (void)URLSession:(NSURLSession *)session - dataTask:(NSURLSessionDataTask *)dataTask -didReceiveResponse:(NSURLResponse *)response - completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { - /* nsurlsessiond started our download. Create a transaction since we're going to be working for a little bit */ - self->_transaction = os_transaction_create("com.apple.trustd.valid.download"); - secinfo("validupdate", "Session %@ data task %@ returned response %ld (%@), expecting %lld bytes", - session, dataTask, (long)[(NSHTTPURLResponse *)response statusCode], - [response MIMEType], [response expectedContentLength]); - - WithPathInRevocationInfoDirectory(NULL, ^(const char *utf8String) { - (void)checkBasePath(utf8String); - }); - CFURLRef updateFileURL = SecCopyURLForFileInRevocationInfoDirectory(CFSTR("update-current")); - self->_currentUpdateFileURL = (updateFileURL) ? CFBridgingRelease(updateFileURL) : nil; - const char *updateFilePath = [self->_currentUpdateFileURL fileSystemRepresentation]; - if (!updateFilePath) { - secnotice("validupdate", "failed to find revocation info directory. canceling task %@", dataTask); - completionHandler(NSURLSessionResponseCancel); - [self reschedule]; - return; - } - - /* Clean up any old files from previous tasks. */ - (void)remove(updateFilePath); - - int fd; - off_t off; - fd = open(updateFilePath, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (fd < 0 || (off = lseek(fd, 0, SEEK_SET)) < 0) { - secnotice("validupdate","unable to open %@ (errno %d)", self->_currentUpdateFileURL, errno); - } - if (fd >= 0) { - close(fd); - } - - /* POWER LOG EVENT: background download actually started */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : @"downloadStarted" - }); - secnotice("validupdate", "download started at %f", (double)CFAbsoluteTimeGetCurrent()); - - NSError *error = nil; - self->_currentUpdateFile = [NSFileHandle fileHandleForWritingToURL:self->_currentUpdateFileURL error:&error]; - if (!self->_currentUpdateFile) { - secnotice("validupdate", "failed to open %@: %@. canceling task %@", self->_currentUpdateFileURL, error, dataTask); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error]; -#endif // ENABLE_TRUSTD_ANALYTICS - completionHandler(NSURLSessionResponseCancel); - [self reschedule]; - return; - } - - completionHandler(NSURLSessionResponseAllow); -} - -- (void)URLSession:(NSURLSession *)session - dataTask:(NSURLSessionDataTask *)dataTask - didReceiveData:(NSData *)data { - secdebug("validupdate", "Session %@ data task %@ returned %lu bytes (%lld bytes so far) out of expected %lld bytes", - session, dataTask, (unsigned long)[data length], [dataTask countOfBytesReceived], [dataTask countOfBytesExpectedToReceive]); - - if (!self->_currentUpdateFile) { - secnotice("validupdate", "received data, but output file is not open"); - [dataTask cancel]; - [self reschedule]; - return; - } - - @try { - /* Writing can fail and throw an exception, e.g. if we run out of disk space. */ - [self->_currentUpdateFile writeData:data]; - } - @catch(NSException *exception) { - secnotice("validupdate", "%s", exception.description.UTF8String); - TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TARecoverableError, errSecDiskFull); - [dataTask cancel]; - [self reschedule]; - } -} - -- (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task -didCompleteWithError:(NSError *)error { - if (error) { - secnotice("validupdate", "Session %@ task %@ failed with error %@", session, task, error); -#if ENABLE_TRUSTD_ANALYTICS - [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error]; -#endif // ENABLE_TRUSTD_ANALYTICS - [self reschedule]; - /* close file before we leave */ - [self->_currentUpdateFile closeFile]; - self->_currentUpdateFile = nil; - self->_currentUpdateServer = nil; - self->_currentUpdateFileURL = nil; - } else { - /* POWER LOG EVENT: background download finished */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : @"downloadFinished" - }); - secnotice("validupdate", "download finished at %f", (double)CFAbsoluteTimeGetCurrent()); - secdebug("validupdate", "Session %@ task %@ succeeded", session, task); - self->_finishedDownloading = YES; - [self updateDb:[self versionFromTask:task]]; - } - if (self->_transaction) { - self->_transaction = nil; - } -} - -@end - -@interface ValidUpdateRequest : NSObject -@property NSTimeInterval updateScheduled; -@property NSURLSession *backgroundSession; -@end - -static ValidUpdateRequest *request = nil; - -@implementation ValidUpdateRequest - -- (NSURLSessionConfiguration *)validUpdateConfiguration { - /* preferences to override defaults */ - CFTypeRef value = NULL; - bool updateOnWiFiOnly = true; - value = CFPreferencesCopyValue(kUpdateWiFiOnlyKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isBoolean(value)) { - updateOnWiFiOnly = CFBooleanGetValue((CFBooleanRef)value); - } - CFReleaseNull(value); - bool updateInBackground = true; - value = CFPreferencesCopyValue(kUpdateBackgroundKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isBoolean(value)) { - updateInBackground = CFBooleanGetValue((CFBooleanRef)value); - } - CFReleaseNull(value); - - NSURLSessionConfiguration *config = nil; - if (updateInBackground) { - config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: @"com.apple.trustd.networking.background"]; - config.networkServiceType = NSURLNetworkServiceTypeBackground; - config.discretionary = YES; - config._requiresPowerPluggedIn = YES; - config.allowsCellularAccess = (!updateOnWiFiOnly) ? YES : NO; - } else { - config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; // no cookies or data storage - config.networkServiceType = NSURLNetworkServiceTypeDefault; - config.discretionary = NO; - } - - config.HTTPAdditionalHeaders = @{ @"User-Agent" : @"com.apple.trustd/2.0", - @"Accept" : @"*/*", - @"Accept-Encoding" : @"gzip,deflate,br"}; - - config.TLSMinimumSupportedProtocol = kTLSProtocol12; - - return config; -} - -- (void) createSession:(dispatch_queue_t)updateQueue forServer:(NSString *)updateServer { - NSURLSessionConfiguration *config = [self validUpdateConfiguration]; - ValidDelegate *delegate = [[ValidDelegate alloc] init]; - delegate.handler = ^(void) { - request.updateScheduled = 0.0; - secdebug("validupdate", "resetting scheduled time"); - }; - delegate.transaction = NULL; - delegate.revDbUpdateQueue = updateQueue; - delegate.finishedDownloading = NO; - delegate.currentUpdateServer = [updateServer copy]; - - /* Callbacks should be on a separate NSOperationQueue. - We'll then dispatch the work on updateQueue and return from the callback. */ - NSOperationQueue *queue = [[NSOperationQueue alloc] init]; - queue.maxConcurrentOperationCount = 1; - _backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; -} - -- (BOOL) scheduleUpdateFromServer:(NSString *)server forVersion:(NSUInteger)version withQueue:(dispatch_queue_t)updateQueue { - if (!server) { - secnotice("validupdate", "invalid update request"); - return NO; - } - - if (!updateQueue) { - secnotice("validupdate", "missing update queue, skipping update"); - return NO; - } - - /* nsurlsessiond waits for unlock to finish launching, so we can't block trust evaluations - * on scheduling this background task. Also, we want to wait a sufficient amount of time - * after system boot before trying to initiate network activity, to avoid the possibility - * of a performance regression in the boot path. */ - dispatch_async(updateQueue, ^{ - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - if (self.updateScheduled != 0.0) { - secdebug("validupdate", "update in progress (scheduled %f)", (double)self.updateScheduled); - return; - } else { - uint64_t uptime = systemUptimeInSeconds(); - const uint64_t minUptime = 180; - if (uptime < minUptime) { - gNextUpdate = now + (minUptime - uptime); - gUpdateStarted = 0; - secnotice("validupdate", "postponing update until %f", gNextUpdate); - return; - } else { - self.updateScheduled = now; - secnotice("validupdate", "scheduling update at %f", (double)self.updateScheduled); - } - } - - /* we have an update to schedule, so take a transaction while we work */ - os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.scheduleUpdate"); - - /* clear all old sessions and cleanup disk (for previous download tasks) */ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - @autoreleasepool { - [NSURLSession _obliterateAllBackgroundSessionsWithCompletionHandler:^{ - secnotice("validupdate", "removing all old sessions for trustd"); - }]; - } - }); - - if (!self.backgroundSession) { - [self createSession:updateQueue forServer:server]; - } else { - ValidDelegate *delegate = (ValidDelegate *)[self.backgroundSession delegate]; - delegate.currentUpdateServer = [server copy]; - } - - /* POWER LOG EVENT: scheduling our background download session now */ - SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ - @"timestamp" : @([[NSDate date] timeIntervalSince1970]), - @"event" : @"downloadScheduled", - @"version" : @(version) - }); - - NSURL *validUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/g3/v%ld", - server, (unsigned long)version]]; - NSURLSessionDataTask *dataTask = [self.backgroundSession dataTaskWithURL:validUrl]; - dataTask.taskDescription = [NSString stringWithFormat:@"%lu",(unsigned long)version]; - [dataTask resume]; - secnotice("validupdate", "scheduled background data task %@ at %f", dataTask, CFAbsoluteTimeGetCurrent()); - (void) transaction; // dead store - transaction = nil; // ARC releases the transaction - }); - - return YES; -} -@end - -bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - @autoreleasepool { - request = [[ValidUpdateRequest alloc] init]; - } - }); - @autoreleasepool { - return [request scheduleUpdateFromServer:(__bridge NSString*)server forVersion:version withQueue:queue]; - } -} - -/* MARK: - */ -/* MARK: OCSP Fetch Networking */ -#define OCSP_REQUEST_THRESHOLD 10 - -@interface OCSPFetchDelegate : TrustURLSessionDelegate -@end - -@implementation OCSPFetchDelegate -- (BOOL)fetchNext:(NSURLSession *)session { - SecORVCRef orvc = (SecORVCRef)self.context; - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); - - BOOL result = true; - if ((result = [super fetchNext:session])) { - /* no fetch scheduled */ - orvc->done = true; - } else { - if (self.URIix > 0) { - orvc->responder = (__bridge CFURLRef)self.URIs[self.URIix - 1]; - } else { - orvc->responder = (__bridge CFURLRef)self.URIs[0]; - } - if (analytics) { - analytics->ocsp_fetches++; - } - } - return result; -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - /* call the superclass's method to set expiration */ - [super URLSession:session task:task didCompleteWithError:error]; - - __block SecORVCRef orvc = (SecORVCRef)self.context; - if (!orvc || !orvc->builder) { - /* We already returned to the PathBuilder state machine. */ - return; - } - - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); - if (error) { - /* Log the error */ - secnotice("rvc", "Failed to download ocsp response %@, with error %@", task.originalRequest.URL, error); - if (analytics) { - analytics->ocsp_fetch_failed++; - } - } else { - SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate((__bridge CFDataRef)self.response); - if (ocspResponse) { - SecORVCConsumeOCSPResponse(orvc, ocspResponse, self.expiration, true, false); - if (analytics && !orvc->done) { - /* We got an OCSP response that didn't pass validation */ - analytics-> ocsp_validation_failed = true; - } - } else if (analytics) { - /* We got something that wasn't an OCSP response (e.g. captive portal) -- - * we consider that a fetch failure */ - analytics->ocsp_fetch_failed++; - } - } - - /* If we didn't get a valid OCSP response, try the next URI */ - if (!orvc->done) { - (void)[self fetchNext:session]; - } - - /* We got a valid OCSP response or couldn't schedule any more fetches. - * Close the session, update the PVCs, decrement the async count, and callback if we're all done. */ - if (orvc->done) { - secdebug("rvc", "builder %p, done with OCSP fetches for cert: %ld", orvc->builder, orvc->certIX); - self.context = nil; - [session invalidateAndCancel]; - SecORVCUpdatePVC(orvc); - if (0 == SecPathBuilderDecrementAsyncJobCount(orvc->builder)) { - /* We're the last async job to finish, jump back into the state machine */ - secdebug("rvc", "builder %p, done with all async jobs", orvc->builder); - dispatch_async(SecPathBuilderGetQueue(orvc->builder), ^{ - SecPathBuilderStep(orvc->builder); - }); - } - } -} - -- (NSURLRequest *)createNextRequest:(NSURL *)uri { - SecORVCRef orvc = (SecORVCRef)self.context; - CFDataRef ocspDER = CFRetainSafe(SecOCSPRequestGetDER(orvc->ocspRequest)); - NSData *nsOcspDER = CFBridgingRelease(ocspDER); - NSString *ocspBase64 = [nsOcspDER base64EncodedStringWithOptions:0]; - - /* Ensure that we percent-encode specific characters in the base64 path - which are defined as delimiters in RFC 3986 [2.2]. - */ - static NSMutableCharacterSet *allowedSet = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - allowedSet = [[NSCharacterSet URLPathAllowedCharacterSet] mutableCopy]; - [allowedSet removeCharactersInString:@":/?#[]@!$&'()*+,;="]; - }); - NSString *escapedRequest = [ocspBase64 stringByAddingPercentEncodingWithAllowedCharacters:allowedSet]; - NSURLRequest *request = nil; - - /* Interesting tidbit from rfc5019 - When sending requests that are less than or equal to 255 bytes in - total (after encoding) including the scheme and delimiters (http://), - server name and base64-encoded OCSPRequest structure, clients MUST - use the GET method (to enable OCSP response caching). OCSP requests - larger than 255 bytes SHOULD be submitted using the POST method. - */ - if (([[uri absoluteString] length] + 1 + [escapedRequest length]) < 256) { - /* Use a GET */ - NSString *requestString = [NSString stringWithFormat:@"%@/%@", [uri absoluteString], escapedRequest]; - NSURL *requestURL = [NSURL URLWithString:requestString]; - request = [NSURLRequest requestWithURL:requestURL]; - } else { - /* Use a POST */ - NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:uri]; - mutableRequest.HTTPMethod = @"POST"; - mutableRequest.HTTPBody = nsOcspDER; - request = mutableRequest; - } - - return request; -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)taskMetrics { - secdebug("rvc", "got metrics with task interval %f", taskMetrics.taskInterval.duration); - SecORVCRef orvc = (SecORVCRef)self.context; - if (orvc && orvc->builder) { - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); - if (analytics) { - analytics->ocsp_fetch_time += (uint64_t)(taskMetrics.taskInterval.duration * NSEC_PER_SEC); - } - } -} -@end - -bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert) { - @autoreleasepool { - CFArrayRef ocspResponders = CFRetainSafe(SecCertificateGetOCSPResponders(cert)); - NSArray *nsResponders = CFBridgingRelease(ocspResponders); - - NSInteger count = [nsResponders count]; - if (count > OCSP_REQUEST_THRESHOLD) { - secnotice("rvc", "too may OCSP responder entries (%ld)", (long)count); - orvc->done = true; - return true; - } - - NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; - config.timeoutIntervalForResource = TrustURLSessionGetResourceTimeout(); - config.HTTPAdditionalHeaders = @{@"User-Agent" : @"com.apple.trustd/2.0"}; - - NSData *auditToken = CFBridgingRelease(SecPathBuilderCopyClientAuditToken(orvc->builder)); - if (auditToken) { - config._sourceApplicationAuditTokenData = auditToken; - } - - OCSPFetchDelegate *delegate = [[OCSPFetchDelegate alloc] init]; - delegate.context = orvc; - delegate.URIs = nsResponders; - delegate.URIix = 0; - - NSOperationQueue *queue = [[NSOperationQueue alloc] init]; - - NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; - secdebug("rvc", "created URLSession for %@", cert); - - bool result = false; - if ((result = [delegate fetchNext:session])) { - /* no fetch scheduled, close the session */ - [session invalidateAndCancel]; - } - return result; - } -} diff --git a/OSX/sec/securityd/SecRevocationServer.c b/OSX/sec/securityd/SecRevocationServer.c deleted file mode 100644 index b81b047e..00000000 --- a/OSX/sec/securityd/SecRevocationServer.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * Copyright (c) 2008-2019 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecRevocationServer.c - Engine for evaluating certificate revocation. - */ - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// MARK: SecORVCRef -/******************************************************** - ****************** OCSP RVC Functions ****************** - ********************************************************/ -const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0; -const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0; -#define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC) - -static void SecORVCFinish(SecORVCRef orvc) { - secdebug("alloc", "finish orvc %p", orvc); - if (orvc->ocspRequest) { - SecOCSPRequestFinalize(orvc->ocspRequest); - orvc->ocspRequest = NULL; - } - if (orvc->ocspResponse) { - SecOCSPResponseFinalize(orvc->ocspResponse); - orvc->ocspResponse = NULL; - if (orvc->ocspSingleResponse) { - SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse); - orvc->ocspSingleResponse = NULL; - } - } - memset(orvc, 0, sizeof(struct OpaqueSecORVC)); -} - -/* Process a verified ocsp response for a given cert. Return true if the - certificate status was obtained. */ -static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this, - SecORVCRef rvc) { - bool processed; - switch (this->certStatus) { - case CS_Good: - secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX); - /* @@@ Mark cert as valid until a given date (nextUpdate if we have one) - in the info dictionary. */ - //cert.revokeCheckGood(true); - rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate; - processed = true; - break; - case CS_Revoked: - secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX); - /* @@@ Mark cert as revoked (with reason) at revocation date in - the info dictionary, or perhaps we should use a different key per - reason? That way a client using exceptions can ignore some but - not all reasons. */ - SInt32 reason = this->crlReason; - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); - if (path) { - SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); - } - CFRelease(cfreason); - processed = true; - break; - case CS_Unknown: - /* not an error, no per-cert status, nothing here */ - secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX); - processed = false; - break; - default: - secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex, - (int)this->certStatus, rvc->certIX); - processed = false; - break; - } - - return processed; -} - -void SecORVCUpdatePVC(SecORVCRef rvc) { - if (rvc->ocspSingleResponse) { - SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc); - } - if (rvc->ocspResponse) { - rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse); - } -} - -typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr); - -static void -SecOCSPEvaluateCompleted(const void *userData, - CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, - SecTrustResultType result) { - SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData; - evaluated(result); - Block_release(evaluated); - -} - -static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) { - __block bool evaluated = false; - bool trusted = false; - if (!signers || !issuers) { - return trusted; - } - - /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */ - const void *ocspSigner = SecPolicyCreateOCSPSigner(); - CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault, - &ocspSigner, 1, &kCFTypeArrayCallBacks); - CFRelease(ocspSigner); - - SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) { - if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) { - evaluated = true; - } - }); - - CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder); - SecPathBuilderRef oBuilder = SecPathBuilderCreate(NULL, clientAuditToken, - signers, issuers, true, false, - policies, NULL, NULL, NULL, - verifyTime, NULL, NULL, - SecOCSPEvaluateCompleted, completed); - /* disable network access to avoid recursion */ - SecPathBuilderSetCanAccessNetwork(oBuilder, false); - - /* Build the chain(s), evaluate them, call the completed block, free the block and builder */ - SecPathBuilderStep(oBuilder); - CFReleaseNull(clientAuditToken); - CFReleaseNull(policies); - - /* verify the public key of the issuer signed the OCSP signer */ - if (evaluated) { - SecCertificateRef issuer = NULL, signer = NULL; - SecKeyRef issuerPubKey = NULL; - - issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0); - signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0); - - if (issuer) { - issuerPubKey = SecCertificateCopyKey(issuer); - } - if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) { - trusted = true; - } else { - secnotice("ocsp", "ocsp signer cert not signed by issuer"); - } - CFReleaseNull(issuerPubKey); - } - - return trusted; -} - -static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) { - bool trusted; - SecCertificatePathVCRef issuers = SecCertificatePathVCCopyFromParent(SecPathBuilderGetPath(rvc->builder), rvc->certIX + 1); - SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathVCGetCertificateAtIndex(issuers, 0)) : NULL; - CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse); - SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer); - - if (signer && signers) { - if (issuer && CFEqual(signer, issuer)) { - /* We already know we trust issuer since it's the issuer of the - * cert we are verifying. */ - secinfo("ocsp", "ocsp responder: %@ response signed by issuer", - rvc->responder); - trusted = true; - } else { - secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer", - rvc->responder); - CFMutableArrayRef signerCerts = NULL; - CFArrayRef issuerCerts = NULL; - - /* Ensure the signer cert is the 0th cert for trust evaluation */ - signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(signerCerts, signer); - CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers))); - - if (issuers) { - issuerCerts = SecCertificatePathVCCopyCertificates(issuers); - } - - if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) { - secdebug("ocsp", "response satisfies ocspSigner policy (%@)", - rvc->responder); - trusted = true; - } else { - /* @@@ We don't trust the cert so don't use this response. */ - secnotice("ocsp", "ocsp response signed by certificate which " - "does not satisfy ocspSigner policy"); - trusted = false; - } - CFReleaseNull(signerCerts); - CFReleaseNull(issuerCerts); - } - } else { - /* @@@ No signer found for this ocsp response, discard it. */ - secnotice("ocsp", "ocsp responder: %@ no signer found for response", - rvc->responder); - trusted = false; - } - -#if DUMP_OCSPRESPONSES - char buf[40]; - snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der", - rvc->certIX, (trusted ? "t" : "u")); - secdumpdata(ocspResponse->data, buf); -#endif - CFReleaseNull(issuers); - CFReleaseNull(issuer); - CFReleaseNull(signers); - CFReleaseNull(signer); - return trusted; -} - -void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, - CFTimeInterval maxAge, bool updateCache, bool fromCache) { - SecOCSPSingleResponseRef sr = NULL; - require_quiet(ocspResponse, errOut); - SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse); - require_action_quiet(orStatus == kSecOCSPSuccess, errOut, - secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus)); - require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut, - secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder)); - // Check if this response is fresher than any (cached) response we might still have in the rvc. - require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut); - - CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent(); -#if TARGET_OS_IPHONE - /* Check the OCSP response signature and verify the response if not pulled from the cache. - * Performance optimization since we don't write invalid responses to the cache. */ - if (!fromCache) { - require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, - sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); - } -#else - /* Always check the OCSP response signature and verify the response (since the cache is user-modifiable). */ - require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, - sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); -#endif - - // If we get here, we have a properly signed ocsp response - // but we haven't checked dates yet. - - bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime); - if (sr->certStatus == CS_Good) { - // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime - require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut); - } else if (sr->certStatus == CS_Revoked) { - // Expire revoked responses when the subject certificate itself expires. - ocspResponse->expireTime = SecCertificateNotValidAfter(SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX)); - } - - // Ok we like the new response, let's toss the old one. - if (updateCache) - SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime); - - if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse); - rvc->ocspResponse = ocspResponse; - ocspResponse = NULL; - - if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse); - rvc->ocspSingleResponse = sr; - sr = NULL; - - rvc->done = sr_valid; - -errOut: - if (sr) SecOCSPSingleResponseDestroy(sr); - if (ocspResponse) SecOCSPResponseFinalize(ocspResponse); -} - -static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { - SecORVCRef orvc = NULL; - orvc = malloc(sizeof(struct OpaqueSecORVC)); - secdebug("alloc", "orvc %p", orvc); - if (orvc) { - memset(orvc, 0, sizeof(struct OpaqueSecORVC)); - orvc->builder = builder; - orvc->rvc = rvc; - orvc->certIX = certIX; - - SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(builder, certIX); - if (SecPathBuilderGetCertificateCount(builder) > (certIX + 1)) { - SecCertificateRef issuer = SecPathBuilderGetCertificateAtIndex(builder, certIX + 1); - orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer); - } - } - return orvc; -} - -static void SecORVCProcessStapledResponses(SecORVCRef rvc) { - /* Get stapled OCSP responses */ - CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->builder); - - if(ocspResponsesData) { - secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX); - CFArrayForEach(ocspResponsesData, ^(const void *value) { - SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); - SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false, false); - }); - CFRelease(ocspResponsesData); - } -} - -void SecRVCDelete(SecRVCRef rvc) { - secdebug("alloc", "delete rvc %p", rvc); - if (rvc->orvc) { - SecORVCFinish(rvc->orvc); - free(rvc->orvc); - rvc->orvc = NULL; - } - if (rvc->valid_info) { - CFReleaseNull(rvc->valid_info); - } -} - -// Forward declaration -static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc); - -static void SecRVCInit(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { - secdebug("alloc", "rvc %p", rvc); - rvc->builder = builder; - rvc->certIX = certIX; - rvc->orvc = SecORVCCreate(rvc, builder, certIX); - if (!rvc->orvc) { - SecRVCDelete(rvc); - SecRVCSetFinishedWithoutNetwork(rvc); - } else { - rvc->done = false; - } -} - -static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { - return true; -} - -static bool SecRVCPolicyConstraintsPermitPolicy(SecValidPolicy *constraints, CFIndex count, SecPolicyRef policy) { - if (!constraints || !policy) { - return true; /* nothing to constrain */ - } - SecValidPolicy policyType = kSecValidPolicyAny; - CFStringRef policyName = SecPolicyGetName(policy); - /* determine if the policy is a candidate for being constrained */ - if (CFEqualSafe(policyName, kSecPolicyNameSSLServer) || - CFEqualSafe(policyName, kSecPolicyNameEAPServer) || - CFEqualSafe(policyName, kSecPolicyNameIPSecServer)) { - policyType = kSecValidPolicyServerAuthentication; - } else if (CFEqualSafe(policyName, kSecPolicyNameSSLClient) || - CFEqualSafe(policyName, kSecPolicyNameEAPClient) || - CFEqualSafe(policyName, kSecPolicyNameIPSecClient)) { - policyType = kSecValidPolicyClientAuthentication; - } else if (CFEqualSafe(policyName, kSecPolicyNameSMIME)) { - policyType = kSecValidPolicyEmailProtection; - } else if (CFEqualSafe(policyName, kSecPolicyNameCodeSigning)) { - policyType = kSecValidPolicyCodeSigning; - } else if (CFEqualSafe(policyName, kSecPolicyNameTimeStamping)) { - policyType = kSecValidPolicyTimeStamping; - } - if (policyType == kSecValidPolicyAny) { - return true; /* policy not subject to constraint */ - } - /* policy is subject to constraint; do the constraints allow it? */ - bool result = false; - for (CFIndex ix = 0; ix < count; ix++) { - SecValidPolicy allowedPolicy = constraints[ix]; - if (allowedPolicy == kSecValidPolicyAny || - allowedPolicy == policyType) { - result = true; - break; - } - } - if (!result) { - secnotice("rvc", "%@ not allowed by policy constraints on issuing CA", policyName); - } - return result; -} - -static bool SecRVCGetPolicyConstraints(CFDataRef data, SecValidPolicy **constraints, CFIndex *count) { - /* Sanity-check the input policy constraints data, returning pointer and - * count values in output arguments. Function result is true if successful. - * - * The first byte of the policy constraints data contains the number of entries, - * followed by an array of 0..n policy constraint values of type SecValidPolicy. - * The maximum number of defined policies is not expected to approach 127, i.e. - * the largest value which can be expressed in a signed byte. - */ - bool result = false; - CFIndex length = 0; - SecValidPolicy *p = NULL; - if (data) { - length = CFDataGetLength(data); - p = (SecValidPolicy *)CFDataGetBytePtr(data); - } - /* Verify that count is 0 or greater, and equal to remaining number of bytes */ - CFIndex c = (length > 0) ? *p++ : -1; - if (c < 0 || c != (length - 1)) { - secerror("invalid policy constraints array"); - } else { - if (constraints) { - *constraints = p; - } - if (count) { - *count = c; - } - result = true; - } - return result; -} - -static void SecRVCProcessValidPolicyConstraints(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info || !rvc->builder) { - return; - } - if (!rvc->valid_info->hasPolicyConstraints) { - return; - } - CFIndex count = 0; - SecValidPolicy *constraints = NULL; - if (!SecRVCGetPolicyConstraints(rvc->valid_info->policyConstraints, &constraints, &count)) { - return; - } - secdebug("rvc", "found policy constraints for cert at index %ld", rvc->certIX); - - /* check that policies being verified are permitted by the policy constraints */ - bool policyDeniedByConstraints = false; - CFIndex ix, initialPVCCount = SecPathBuilderGetPVCCount(rvc->builder); - for (ix = 0; ix < initialPVCCount; ix++) { - SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, ix); - CFArrayRef policies = CFRetainSafe(pvc->policies); - CFIndex policyCount = (policies) ? CFArrayGetCount(policies) : 0; - for (CFIndex policyIX = 0; policyIX < policyCount; policyIX++) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); - if (!SecRVCPolicyConstraintsPermitPolicy(constraints, count, policy)) { - policyDeniedByConstraints = true; - SecPVCSetResultForced(pvc, kSecPolicyCheckIssuerPolicyConstraints, rvc->certIX, - kCFBooleanFalse, true); - pvc->result = kSecTrustResultRecoverableTrustFailure; - if (!rvc->valid_info->overridable) { - /* error for this check should be non-recoverable */ - pvc->result = kSecTrustResultFatalTrustFailure; - } - } - } - CFReleaseSafe(policies); - } - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); - if (analytics) { - TAValidStatus status = (policyDeniedByConstraints) ? TAValidPolicyConstrainedDenied : TAValidPolicyConstrainedOK; - analytics->valid_status |= status; - } -} - -static void SecRVCProcessValidDateConstraints(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info || !rvc->builder) { - return; - } - if (!rvc->valid_info->hasDateConstraints) { - return; - } - SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); - if (!certificate) { - return; - } - CFAbsoluteTime certIssued = SecCertificateNotValidBefore(certificate); - CFAbsoluteTime caNotBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ - CFAbsoluteTime caNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ - if (rvc->valid_info->notBeforeDate) { - caNotBefore = CFDateGetAbsoluteTime(rvc->valid_info->notBeforeDate); - } - if (rvc->valid_info->notAfterDate) { - caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate); - /* per the Valid specification, if this date is in the past, we need to check CT. */ - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - if (caNotAfter < now) { - rvc->valid_info->requireCT = true; - } - } - if ((certIssued < caNotBefore) && (rvc->certIX > 0)) { - /* not-before constraint is only applied to leaf certificate, for now. */ - return; - } - - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); - if ((certIssued < caNotBefore) || (certIssued > caNotAfter)) { - /* We are outside the constrained validity period. */ - secnotice("rvc", "certificate issuance date not within the allowed range for this CA%s", - (rvc->valid_info->overridable) ? "" : " (non-recoverable error)"); - if (analytics) { - analytics->valid_status |= TAValidDateConstrainedRevoked; - } - if (rvc->valid_info->overridable) { - /* error is recoverable, treat certificate as untrusted - (note this date check is different from kSecPolicyCheckTemporalValidity) */ - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedKey, rvc->certIX, - kCFBooleanFalse, true); - } else { - /* error is non-overridable, treat certificate as revoked */ - SInt32 reason = 0; /* unspecified reason code */ - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); - if (path) { - SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); - } - CFReleaseNull(cfreason); - } - } else if (analytics) { - analytics->valid_status |= TAValidDateConstrainedOK; - } -} - -bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info) { - return false; - } - SecValidInfoRef info = rvc->valid_info; - /* outcomes as defined in Valid server specification */ - if (info->format == kSecValidInfoFormatSerial || - info->format == kSecValidInfoFormatSHA256) { - if (info->noCACheck || info->complete || info->isOnList) { - return true; - } - } else { /* info->format == kSecValidInfoFormatNto1 */ - if (info->noCACheck || (info->complete && !info->isOnList)) { - return true; - } - } - return false; -} - -bool SecRVCHasRevokedValidInfo(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info) { - return false; - } - SecValidInfoRef info = rvc->valid_info; - /* either not present on an allowlist, or present on a blocklist */ - return (!info->isOnList && info->valid) || (info->isOnList && !info->valid); -} - -void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info || !rvc->builder) { - return; - } - if (rvc->valid_info->overridable) { - /* error is recoverable, treat certificate as untrusted */ - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedLeaf, rvc->certIX, - kCFBooleanFalse, true); - return; - } - /* error is fatal at this point */ - if (!SecRVCHasRevokedValidInfo(rvc) || rvc->valid_info->noCACheck) { - /* result key should indicate blocked instead of revoked, - * but result must be non-recoverable */ - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckBlackListedLeaf, rvc->certIX, - kCFBooleanFalse, true); - return; - } - SInt32 reason = 0; /* unspecified, since the Valid db doesn't tell us */ - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); - if (path) { - SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); - } - CFReleaseNull(cfreason); -} - -static void SecRVCProcessValidInfoResults(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info || !rvc->builder) { - return; - } - SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); - SecValidInfoRef info = rvc->valid_info; - - bool definitive = SecRVCHasDefinitiveValidInfo(rvc); - bool revoked = SecRVCHasRevokedValidInfo(rvc); - - /* set analytics */ - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); - if (analytics) { - if (revoked) { - analytics->valid_status |= definitive ? TAValidDefinitelyRevoked : TAValidProbablyRevoked; - } else { - analytics->valid_status |= definitive ? TAValidDefinitelyOK : TAValidProbablyOK; - } - analytics->valid_require_ct |= info->requireCT; - analytics->valid_known_intermediates_only |= info->knownOnly; - } - - /* Handle no-ca cases */ - if (info->noCACheck) { - bool allowed = (info->valid && info->complete && info->isOnList); - if (revoked) { - /* definitely revoked */ - SecRVCSetValidDeterminedErrorResult(rvc); - } else if (allowed) { - /* definitely not revoked (allowlisted) */ - SecCertificatePathVCSetIsAllowlisted(path, true); - } - /* no-ca is definitive; no need to check further. */ - secdebug("validupdate", "rvc: definitely %s cert %" PRIdCFIndex, - (allowed) ? "allowed" : "revoked", rvc->certIX); - rvc->done = true; - return; - } - - /* Handle policy constraints, if present. */ - SecRVCProcessValidPolicyConstraints(rvc); - - /* Handle date constraints, if present. - * Note: a not-after date may set the CT requirement, - * so check requireCT after this function is called. */ - SecRVCProcessValidDateConstraints(rvc); - - /* Set CT requirement on path, if present. */ - if (info->requireCT) { - SecPathCTPolicy ctp = kSecPathCTRequired; - if (info->overridable) { - ctp = kSecPathCTRequiredOverridable; - } - SecCertificatePathVCSetRequiresCT(path, ctp); - } - - /* Trigger OCSP for any non-definitive or revoked cases */ - if (!definitive || revoked) { - info->checkOCSP = true; - } - - if (info->checkOCSP) { - CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); - CFIndex issuerIX = rvc->certIX + 1; - if (issuerIX >= count) { - /* cannot perform a revocation check on the last cert in the - chain, since we don't have its issuer. */ - return; - } - secdebug("validupdate", "rvc: %s%s cert %" PRIdCFIndex " (will check OCSP)", - (info->complete) ? "" : "possibly ", (info->valid) ? "allowed" : "revoked", - rvc->certIX); - SecPathBuilderSetRevocationMethod(rvc->builder, kSecPolicyCheckRevocationAny); - if (analytics) { - /* Valid DB results caused us to do OCSP */ - analytics->valid_trigger_ocsp = true; - } - } -} - -static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) { - /* Skip checking for OCSP Signer verification */ - if (SecPathBuilderGetPVCCount(rvc->builder) == 1) { - SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, 0); - if (!pvc) { return false; } - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); - CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL; - if (policyName && CFEqual(policyName, CFSTR("OCSPSigner"))) { - return false; - } - } - - /* Make sure revocation db info is up-to-date. - * We don't care if the builder is allowed to access the network because - * the network fetching does not block the trust evaluation. */ - SecRevocationDbCheckNextUpdate(); - - /* Check whether we have valid db info for this cert, - given the cert and its issuer */ - SecValidInfoRef info = NULL; - CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); - if (count) { - bool isSelfSigned = false; - SecCertificateRef cert = NULL; - SecCertificateRef issuer = NULL; - CFIndex issuerIX = rvc->certIX + 1; - if (count > issuerIX) { - issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, issuerIX); - } else if (count == issuerIX) { - CFIndex rootIX = SecCertificatePathVCSelfSignedIndex(SecPathBuilderGetPath(rvc->builder)); - if (rootIX == rvc->certIX) { - issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, rootIX); - isSelfSigned = true; - } - } - cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); - if (!isSelfSigned) { - /* skip revocation db check for self-signed certificates [33137065] */ - info = SecRevocationDbCopyMatching(cert, issuer); - } - SecValidInfoSetAnchor(info, SecPathBuilderGetCertificateAtIndex(rvc->builder, count-1)); - } - if (info) { - SecValidInfoRef old_info = rvc->valid_info; - rvc->valid_info = info; - if (old_info) { - CFReleaseNull(old_info); - } - return true; - } - return false; -} - -static void SecRVCCheckRevocationCaches(SecRVCRef rvc) { - /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */ - if (SecRVCShouldCheckOCSP(rvc) && (rvc->orvc->ocspRequest)) { - secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX); - SecOCSPResponseRef response = NULL; - if (SecPathBuilderGetCheckRevocationOnline(rvc->builder)) { - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL); - } else { - response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL); - } - SecORVCConsumeOCSPResponse(rvc->orvc, response, NULL_TIME, false, true); - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); - if (rvc->orvc->done && analytics) { - /* We found a valid OCSP response in the cache */ - analytics->ocsp_cache_hit = true; - } - } -} - -static void SecRVCUpdatePVC(SecRVCRef rvc) { - SecRVCProcessValidInfoResults(rvc); /* restore the results we got from Valid */ - if (rvc->orvc) { SecORVCUpdatePVC(rvc->orvc); } -} - -static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc) { - rvc->done = true; - SecRVCUpdatePVC(rvc); - (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); -} - -static bool SecRVCFetchNext(SecRVCRef rvc) { - bool OCSP_fetch_finished = true; - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); - /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */ - if (SecRVCShouldCheckOCSP(rvc)) { - SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); - SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX); - OCSP_fetch_finished = SecORVCBeginFetches(rvc->orvc, cert); - if (analytics && !OCSP_fetch_finished) { - /* We did a network OCSP fetch, set report appropriately */ - analytics->ocsp_network = true; - } - } - if (OCSP_fetch_finished) { - /* we didn't start an OCSP background job for this cert */ - (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); - } - return OCSP_fetch_finished; -} - -/* The SecPathBuilder state machine calls SecPathBuilderCheckRevocation twice -- - * once in the ValidatePath state, and again in the ComputeDetails state. In the - * ValidatePath state we've not yet run the path checks, so for callers who set - * kSecRevocationCheckIfTrusted, we don't do any networking on that first call. - * Here, if we've already done revocation before (so we're in ComputeDetails now), - * we need to recheck (and enable networking) for trusted chains and - * kSecRevocationCheckIfTrusted. Otherwise, we skip the checks to save on the processing - * but update the PVCs with the revocation results from the last check. */ -static bool SecRevocationDidCheckRevocation(SecPathBuilderRef builder, bool *first_check_done) { - SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); - if (!SecCertificatePathVCIsRevocationDone(path)) { - return false; - } - if (first_check_done) { - *first_check_done = true; - } - - SecPVCRef resultPVC = SecPathBuilderGetResultPVC(builder); - bool recheck = false; - if (SecPathBuilderGetCheckRevocationIfTrusted(builder) && SecPVCIsOkResult(resultPVC)) { - recheck = true; - secdebug("rvc", "Rechecking revocation because network now allowed"); - } else { - secdebug("rvc", "Not rechecking revocation"); - } - - if (recheck) { - // reset the RVCs for the second pass - SecCertificatePathVCDeleteRVCs(path); - } else { - CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder); - for (certIX = 0; certIX < certCount; ++certIX) { - SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); - if (rvc) { - SecRVCUpdatePVC(rvc); - } - } - } - - return !recheck; -} - -static bool SecRevocationCanAccessNetwork(SecPathBuilderRef builder, bool first_check_done) { - /* CheckRevocationIfTrusted overrides NoNetworkAccess for revocation */ - if (SecPathBuilderGetCheckRevocationIfTrusted(builder)) { - if (first_check_done) { - /* We're on the second pass. We need to now allow networking for revocation. - * SecRevocationDidCheckRevocation takes care of not running a second pass - * if the chain isn't trusted. */ - return true; - } else { - /* We're on the first pass of the revocation checks, where we aren't - * supposed to do networking because we don't know if the chain - * is trusted yet. */ - return false; - } - } - return SecPathBuilderCanAccessNetwork(builder); -} - -void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder) { - SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); - if (!path) { - return; - } - /* only perform this check once per path! */ - CFIndex certIX = kCFNotFound; - if (SecCertificatePathVCCheckedIssuers(path)) { - certIX = SecCertificatePathVCUnknownCAIndex(path); - goto checkedIssuers; - } - /* check full path: start with anchor and decrement to leaf */ - bool parentConstrained = false; - CFIndex certCount = SecPathBuilderGetCertificateCount(builder); - for (certIX = certCount - 1; certIX >= 0; --certIX) { - SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); - if (!rvc) { - continue; - } - if (parentConstrained && !rvc->valid_info) { - /* Parent had the known-only constraint, but our issuer is unknown. - Bump index to point back at the issuer since it fails the constraint. */ - certIX++; - break; - } - parentConstrained = (rvc->valid_info && rvc->valid_info->knownOnly); - if (parentConstrained) { - secdebug("validupdate", "Valid db found a known-intermediate constraint on %@ (index=%ld)", - rvc->valid_info->issuerHash, certIX+1); - if (certIX == 0) { - /* check special case: unknown constrained CA in leaf position */ - SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, certIX); - if (cert && SecCertificateIsCA(cert) && !SecRevocationDbContainsIssuer(cert)) { - /* leaf is a CA which violates the constraint */ - break; - } - } - } - } - /* At this point, certIX will either be -1, indicating no CA was found - which failed a known-intermediates-only constraint on its parent, or it - will be the index of the first unknown CA which fails the constraint. */ - if (certIX >= 0) { - secnotice("validupdate", "CA at index %ld violates known-intermediate constraint", certIX); - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - if (analytics) { - analytics->valid_unknown_intermediate = true; - } - } - SecCertificatePathVCSetUnknownCAIndex(path, certIX); - SecCertificatePathVCSetCheckedIssuers(path, true); - -checkedIssuers: - if (certIX >= 0) { - /* Error is set on CA certificate which failed the constraint. */ - SecRVCSetValidDeterminedErrorResult(SecCertificatePathVCGetRVCAtIndex(path, certIX)); - } -} - -bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) { - secdebug("rvc", "checking revocation"); - CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder); - SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); - if (certCount <= 1) { - /* Can't verify without an issuer; we're done */ - return true; - } - - bool first_check_done = false; - if (SecRevocationDidCheckRevocation(builder, &first_check_done)) { - return true; - } - - /* Setup things so we check revocation status of all certs. */ - SecCertificatePathVCAllocateRVCs(path, certCount); - - /* Note that if we are multi threaded and a job completes after it - is started but before we return from this function, we don't want - a callback to decrement asyncJobCount to zero before we finish issuing - all the jobs. To avoid this we pretend we issued certCount async jobs, - and decrement pvc->asyncJobCount for each cert that we don't start a - background fetch for. We include the root, even though we'll never start - an async job for it so that we count all active threads for this eval. */ - SecPathBuilderSetAsyncJobCount(builder, (unsigned int)(certCount)); - - /* Loop though certificates again and issue an ocsp fetch if the - revocation status checking isn't done yet (and we have an issuer!) */ - for (certIX = 0; certIX < certCount; ++certIX) { - secdebug("rvc", "checking revocation for cert: %ld", certIX); - SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); - if (!rvc) { - continue; - } - - SecRVCInit(rvc, builder, certIX); - - /* RFC 6960: id-pkix-ocsp-nocheck extension says that we shouldn't check revocation. */ - if (SecCertificateHasOCSPNoCheckMarkerExtension(SecCertificatePathVCGetCertificateAtIndex(path, certIX))) - { - secdebug("rvc", "skipping revocation checks for no-check cert: %ld", certIX); - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); - if (analytics) { - /* This certificate has OCSP No-Check, so add to reporting analytics */ - analytics->ocsp_no_check = true; - } - SecRVCSetFinishedWithoutNetwork(rvc); - } - - if (rvc->done) { - continue; - } - -#if !TARGET_OS_BRIDGE - /* Check valid database first (separate from OCSP response cache) */ - if (SecRVCCheckValidInfoDatabase(rvc)) { - SecRVCProcessValidInfoResults(rvc); - } -#endif - /* Any other revocation method requires an issuer certificate to verify the response; - * skip the last cert in the chain since it doesn't have one. */ - if (certIX + 1 >= certCount) { - continue; - } - - /* Ignore stapled OCSP responses only if CRLs are enabled and the - * policy specifically requested CRLs only. */ - if (SecRVCShouldCheckOCSP(rvc)) { - /* If we have any OCSP stapled responses, check those first */ - SecORVCProcessStapledResponses(rvc->orvc); - } - -#if TARGET_OS_BRIDGE - /* The bridge has no writeable storage and no network. Nothing else we can - * do here. */ - SecRVCSetFinishedWithoutNetwork(rvc); - continue; -#else // !TARGET_OS_BRIDGE - /* Then check the caches for revocation results. */ - SecRVCCheckRevocationCaches(rvc); - - /* The check is done if we found cached responses from either method. */ - if (rvc->done || rvc->orvc->done) { - secdebug("rvc", "found cached response for cert: %ld", certIX); - SecRVCSetFinishedWithoutNetwork(rvc); - continue; - } - - /* If we got a cached response that is no longer valid (which can only be true for - * revoked responses), let's try to get a fresher response even if no one asked. - * This check resolves unrevocation events after the nextUpdate time. */ - bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse); - - /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an - async http request for this cert's revocation status, unless we already successfully checked - the revocation status of this cert based on the cache or stapled responses. */ - bool allow_fetch = SecRevocationCanAccessNetwork(builder, first_check_done) && - (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) || - SecPathBuilderGetRevocationMethod(builder) || old_cached_response); - if (rvc->done || !allow_fetch) { - /* We got a cache hit or we aren't allowed to access the network */ - SecRVCUpdatePVC(rvc); - /* We didn't really start any background jobs for this cert. */ - (void)SecPathBuilderDecrementAsyncJobCount(builder); - } else { - (void)SecRVCFetchNext(rvc); - } -#endif // !TARGET_OS_BRIDGE - } - - /* Return false if there are still async jobs running. */ - /* builder->asyncJobCount is atomic, so we know that if the job count is 0, all other - * threads are finished. If the job count is > 0, other threads will decrement the job - * count and SecPathBuilderStep to crank the state machine when the job count is 0. */ - return (SecPathBuilderDecrementAsyncJobCount(builder) == 0); -} - -CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) { - CFAbsoluteTime enu = NULL_TIME; - if (!rvc || !rvc->orvc) { return enu; } - enu = rvc->orvc->nextUpdate; - return enu; -} diff --git a/OSX/sec/securityd/SecRevocationServer.h b/OSX/sec/securityd/SecRevocationServer.h deleted file mode 100644 index d6400167..00000000 --- a/OSX/sec/securityd/SecRevocationServer.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecRevocationServer - The functions provided in SecRevocationServer.h provide an interface to - the trust evaluation engine for dealing with certificate revocation. - */ - -#ifndef _SECURITY_SECREVOCATIONSERVER_H_ -#define _SECURITY_SECREVOCATIONSERVER_H_ - -#include -#include -#include -#include - -typedef struct OpaqueSecORVC *SecORVCRef; - -/* Revocation verification context. */ -struct OpaqueSecRVC { - /* Pointer to the builder for this revocation check */ - SecPathBuilderRef builder; - - /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ - CFIndex certIX; - - /* The OCSP Revocation verification context */ - SecORVCRef orvc; - - /* Valid database info for this revocation check */ - SecValidInfoRef valid_info; - - bool done; -}; -typedef struct OpaqueSecRVC *SecRVCRef; - -/* OCSP Revocation verification context. */ -struct OpaqueSecORVC { - /* Pointer to the builder for this revocation check. */ - SecPathBuilderRef builder; - - /* Pointer to the generic rvc for this revocation check */ - SecRVCRef rvc; - - /* The ocsp request we send to each responder. */ - SecOCSPRequestRef ocspRequest; - - /* The freshest response we received so far, from stapling or cache or responder. */ - SecOCSPResponseRef ocspResponse; - - /* The best validated candidate single response we received so far, from stapling or cache or responder. */ - SecOCSPSingleResponseRef ocspSingleResponse; - - /* Index of cert in builder that this RVC is for 0 = leaf, etc. */ - CFIndex certIX; - - /* Date until which this revocation status is valid. */ - CFAbsoluteTime nextUpdate; - - /* URL of current responder. For logging purposes. */ - CFURLRef responder; - - bool done; -}; - -bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder); -void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder); -CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc); -void SecRVCDelete(SecRVCRef rvc); -bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc); -bool SecRVCHasRevokedValidInfo(SecRVCRef rvc); -void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc); - -/* OCSP verification callbacks */ -void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, - CFTimeInterval maxAge, bool updateCache, bool fromCache); -void SecORVCUpdatePVC(SecORVCRef rvc); - - -#endif /* _SECURITY_SECREVOCATIONSERVER_H_ */ diff --git a/OSX/sec/securityd/SecTrustExceptionResetCount.h b/OSX/sec/securityd/SecTrustExceptionResetCount.h deleted file mode 100644 index c9cd2dbb..00000000 --- a/OSX/sec/securityd/SecTrustExceptionResetCount.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// SecTrustExceptionResetCount.h -// Security -// - -#ifndef SecTrustExceptionResetCount_h -#define SecTrustExceptionResetCount_h - -#include - -bool SecTrustServerIncrementExceptionResetCount(CFErrorRef *error); -uint64_t SecTrustServerGetExceptionResetCount(CFErrorRef *error); - -#endif /* SecTrustExceptionResetCount_h */ diff --git a/OSX/sec/securityd/SecTrustExceptionResetCount.m b/OSX/sec/securityd/SecTrustExceptionResetCount.m deleted file mode 100644 index 4552f3ce..00000000 --- a/OSX/sec/securityd/SecTrustExceptionResetCount.m +++ /dev/null @@ -1,194 +0,0 @@ -// -// SecTrustExceptionResetCount.m -// Security_ios -// - -#import -#import "SecTrustExceptionResetCount.h" - -#import -#import - -static NSString *kExceptionResetCountKey = @"ExceptionResetCount"; -static NSString *exceptionResetCounterFile = @"com.apple.security.exception_reset_counter.plist"; - -/* Returns the path to the, existing or internally-created, 'exceptionResetCounterFile' file. */ -static NSString *SecPlistFileExistsInKeychainDirectory(CFErrorRef *error) { - NSString *status = NULL; - - NSString *path = [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)exceptionResetCounterFile) path]; - if (!path) { - secerror("Unable to address permanent storage for '%{public}@'.", exceptionResetCounterFile); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOENT, NULL); - } - return status; - } - secinfo("trust", "'%{public}@' is at '%{public}@'.", exceptionResetCounterFile, path); - - NSFileManager *fm = [NSFileManager defaultManager]; - if (!fm) { - secerror("Failed to initialize the file manager in '%{public}s'.", __func__); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOMEM, NULL); - } - return status; - } - - BOOL isDir = false; - bool fileExists = [fm fileExistsAtPath:path isDirectory:&isDir]; - if (isDir) { - secerror("'%{public}@' is a directory. (not a file)", path); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EISDIR, NULL); - } - return status; - } - if (fileExists) { - secdebug("trust", "'%{public}@' already exists.", path); - status = path; - return status; - } - - if (![fm createFileAtPath:path contents:nil attributes:nil]) { - secerror("Failed to create permanent storage at '%{public}@'.", path); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); - } - return status; - } - secinfo("trust", "'%{public}@' has been created.", path); - status = path; - - return status; -} - -static uint64_t SecReadPlistFromFileInKeychainDirectory(CFErrorRef *error) { - uint64_t value = 0; - - CFErrorRef localError = NULL; - NSString *path = SecPlistFileExistsInKeychainDirectory(&localError); - if (localError) { - if (error) { - *error = localError; - } - secerror("Permanent storage for the exceptions epoch is unavailable."); - return value; - } - if (!path) { - secinfo("trust", "Permanent storage for the exceptions epoch is missing. Defaulting to value %llu.", value); - return value; - } - - NSMutableDictionary *plDict = [NSMutableDictionary dictionaryWithContentsOfFile:path]; - if (!plDict) { - secerror("Failed to read from permanent storage at '%{public}@' or the data is bad. Defaulting to value %llu.", path, value); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENXIO, NULL); - } - return value; - } - - id valueObject = [plDict objectForKey:kExceptionResetCountKey]; - if (!valueObject) { - secinfo("trust", "Could not find key '%{public}@'. Defaulting to value %llu.", kExceptionResetCountKey, value); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENXIO, NULL); - } - return value; - } - if (![valueObject isKindOfClass:[NSNumber class]]) { - secerror("The value for key '%{public}@' is not a number.", kExceptionResetCountKey); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EDOM, NULL); - } - return value; - } - - value = [valueObject unsignedIntValue]; - - secinfo("trust", "'%{public}@' is %llu.", kExceptionResetCountKey, value); - return value; -} - -static bool SecWritePlistToFileInKeychainDirectory(uint64_t exceptionResetCount, CFErrorRef *error) { - bool status = false; - - CFErrorRef localError = NULL; - SecPlistFileExistsInKeychainDirectory(&localError); - if (localError) { - if (error) { - *error = localError; - } - secerror("Permanent storage for the exceptions epoch is unavailable."); - return status; - } - - NSString *path = [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)exceptionResetCounterFile) path]; - if (!path) { - secerror("Unable to address permanent storage for '%{public}@'.", exceptionResetCounterFile); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); - } - return status; - } - - NSMutableDictionary *dataToSave = [NSMutableDictionary new]; - if (!dataToSave) { - secerror("Failed to allocate memory for the exceptions epoch structure."); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOMEM, NULL); - } - return status; - } - dataToSave[@"Version"] = [NSNumber numberWithUnsignedInteger:1]; - dataToSave[kExceptionResetCountKey] = [NSNumber numberWithUnsignedInteger:exceptionResetCount]; - - status = [dataToSave writeToFile:path atomically:YES]; - if (!status) { - secerror("Failed to write to permanent storage at '%{public}@'.", path); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); - } - return status; - } - - secinfo("trust", "'%{public}@' has been committed to permanent storage at '%{public}@'.", kExceptionResetCountKey, path); - return status; -} - -uint64_t SecTrustServerGetExceptionResetCount(CFErrorRef *error) { - CFErrorRef localError = NULL; - uint64_t exceptionResetCount = SecReadPlistFromFileInKeychainDirectory(&localError); - /* Treat ENXIO as a transient error; I/O seems to be working but we have failed to read the current epoch. - * That's expected when epoch is still 0 and there is nothing to store in permanent storage. (and later read) - */ - if (localError && CFEqualSafe(CFErrorGetDomain(localError), kCFErrorDomainPOSIX) && CFErrorGetCode(localError) == ENXIO) { - CFRelease(localError); - localError = NULL; - } - if (error && localError) { - *error = localError; - } - secinfo("trust", "exceptionResetCount: %llu (%s)", exceptionResetCount, error ? (*error ? "Error" : "OK") : "N/A"); - return exceptionResetCount; -} - -bool SecTrustServerIncrementExceptionResetCount(CFErrorRef *error) { - bool status = false; - - uint64_t currentExceptionResetCount = SecTrustServerGetExceptionResetCount(error); - if (error && *error) { - secerror("Failed to increment the extensions epoch."); - return status; - } - if (currentExceptionResetCount >= INT64_MAX) { - secerror("Current exceptions epoch value is too large. (%llu) Won't increment.", currentExceptionResetCount); - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ERANGE, NULL); - } - return status; - } - - return SecWritePlistToFileInKeychainDirectory(currentExceptionResetCount + 1, error); -} diff --git a/OSX/sec/securityd/SecTrustLoggingServer.h b/OSX/sec/securityd/SecTrustLoggingServer.h deleted file mode 100644 index 5b15b9a4..00000000 --- a/OSX/sec/securityd/SecTrustLoggingServer.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecTrustLoggingServer.h - logging for certificate trust evaluation engine - * - */ - -#ifndef _SECURITY_SECTRUSTLOGGINGSERVER_H_ -#define _SECURITY_SECTRUSTLOGGINGSERVER_H_ - - -void DisableLocalization(void); - -#endif /* _SECURITY_SECTRUSTLOGGINGSERVER_H_ */ diff --git a/OSX/sec/securityd/SecTrustLoggingServer.m b/OSX/sec/securityd/SecTrustLoggingServer.m deleted file mode 100644 index e9dabba3..00000000 --- a/OSX/sec/securityd/SecTrustLoggingServer.m +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecTrustLoggingServer.c - logging for certificate trust evaluation engine - * - */ - -#include -#include "SecTrustLoggingServer.h" - diff --git a/OSX/sec/securityd/SecTrustServer.c b/OSX/sec/securityd/SecTrustServer.c deleted file mode 100644 index 476fc887..00000000 --- a/OSX/sec/securityd/SecTrustServer.c +++ /dev/null @@ -1,1402 +0,0 @@ -/* - * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecTrustServer.c - certificate trust evaluation engine - * - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecRSAKey.h" -#include -#include -#include -#include -#include -#include -#include "OTATrustUtilities.h" -#include "personalization.h" -#include -#include -#include - -#if TARGET_OS_OSX -#include -#endif - -#define MAX_CHAIN_LENGTH 15 -#define MAX_NUM_CHAINS 100 -#define ACCEPT_PATH_SCORE 10000000 - -/* Forward declaration for use in SecCertificateSource. */ -static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents); - -// MARK: - -// MARK: SecPathBuilder -/******************************************************** - *************** SecPathBuilder object ****************** - ********************************************************/ -struct SecPathBuilder { - dispatch_queue_t queue; - uint64_t startTime; - CFDataRef clientAuditToken; - SecCertificateSourceRef certificateSource; - SecCertificateSourceRef itemCertificateSource; - SecCertificateSourceRef anchorSource; - SecCertificateSourceRef appleAnchorSource; - CFMutableArrayRef anchorSources; - CFIndex nextParentSource; - CFMutableArrayRef parentSources; - CFArrayRef ocspResponses; // Stapled OCSP responses - CFArrayRef signedCertificateTimestamps; // Stapled SCTs - CFDictionaryRef trustedLogs; // Trusted CT logs - CFAbsoluteTime verifyTime; - CFArrayRef exceptions; - - /* Hashed set of all paths we've constructed so far, used to prevent - re-considering a path that was already constructed once before. - Note that this is the only container in which certificatePath - objects are retained. - Every certificatePath being considered is always in allPaths and in at - least one of partialPaths, rejectedPaths, or candidatePath, - all of which don't retain their values. */ - CFMutableSetRef allPaths; - - /* No trusted anchor, satisfies the linking to intermediates for all - policies (unless considerRejected is true). */ - CFMutableArrayRef partialPaths; - /* No trusted anchor, does not satisfy linking to intermediates for all - policies. */ - CFMutableArrayRef rejectedPaths; - /* Trusted anchor, satisfies the policies so far. */ - CFMutableArrayRef candidatePaths; - - CFIndex partialIX; - - bool considerRejected; - bool considerPartials; - bool canAccessNetwork; - - SecPVCRef * pvcs; - CFIndex pvcCount; - - SecCertificatePathVCRef path; - _Atomic unsigned int asyncJobCount; - bool online_revocation; - bool trusted_revocation; - CFStringRef revocation_check_method; - - SecCertificatePathVCRef bestPath; - CFMutableDictionaryRef info; - - CFIndex activations; - bool (*state)(SecPathBuilderRef); - SecPathBuilderCompleted completed; - const void *context; - TrustAnalyticsBuilder * analyticsData; -}; - -/* State functions. Return false if a async job was scheduled, return - true to execute the next state. */ -static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder); -static bool SecPathBuilderGetNext(SecPathBuilderRef builder); -static bool SecPathBuilderValidatePath(SecPathBuilderRef builder); -static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder); -static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder); -static bool SecPathBuilderReportResult(SecPathBuilderRef builder); - -/* Forward declarations. */ -static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, - SecCertificateRef certificate, SecCertificateSourceRef *foundInSource); -static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path); - -static void SecPathBuilderInit(SecPathBuilderRef builder, dispatch_queue_t builderQueue, - CFDataRef clientAuditToken, CFArrayRef certificates, - CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, - CFArrayRef policies, CFArrayRef ocspResponses, - CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, - SecPathBuilderCompleted completed, const void *context) { - secdebug("alloc", "builder %p", builder); - CFAllocatorRef allocator = kCFAllocatorDefault; - - builder->analyticsData = calloc(1, sizeof(TrustAnalyticsBuilder)); - builder->analyticsData->start_time = mach_absolute_time(); - - builder->clientAuditToken = (CFDataRef) - ((clientAuditToken) ? CFRetain(clientAuditToken) : NULL); - - if (!builderQueue) { - /* make our own queue if caller fails to provide one */ - builder->queue = dispatch_queue_create("com.apple.trustd.evaluation.builder", DISPATCH_QUEUE_SERIAL); - } else { - dispatch_retain_safe(builderQueue); - builder->queue = builderQueue; - } - - builder->nextParentSource = 1; -#if !TARGET_OS_WATCH - /* */ - builder->canAccessNetwork = true; -#endif - atomic_init(&builder->asyncJobCount, 0); - - builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL); - builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL); - - builder->allPaths = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); - builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. - builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. - builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. - - /* Init the policy verification context. */ - builder->pvcs = malloc(sizeof(SecPVCRef)); - builder->pvcs[0] = malloc(sizeof(struct OpaqueSecPVC)); - SecPVCInit(builder->pvcs[0], builder, policies); - builder->pvcCount = 1; - builder->verifyTime = verifyTime; - builder->exceptions = CFRetainSafe(exceptions); - - /* Let's create all the certificate sources we might want to use. */ - builder->certificateSource = - SecMemoryCertificateSourceCreate(certificates); - if (anchors) { - builder->anchorSource = SecMemoryCertificateSourceCreate(anchors); - } - - bool allowNonProduction = false; - builder->appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(allowNonProduction)); - - - /** Parent Sources - ** The order here avoids the most expensive methods if the cheaper methods - ** produce an acceptable chain: client-provided, keychains, network-fetched. - **/ -#if !TARGET_OS_BRIDGE - CFArrayAppendValue(builder->parentSources, builder->certificateSource); - builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups); - if (keychainsAllowed) { - CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource); - #if TARGET_OS_OSX - /* On OS X, need additional parent source to search legacy keychain files. */ - if (kSecLegacyCertificateSource->contains && kSecLegacyCertificateSource->copyParents) { - CFArrayAppendValue(builder->parentSources, kSecLegacyCertificateSource); - } - #endif - } - if (anchorsOnly) { - /* Add the Apple, system, and user anchor certificate db to the search list - if we don't explicitly trust them. */ - CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource); - CFArrayAppendValue(builder->parentSources, kSecSystemAnchorSource); - #if TARGET_OS_IPHONE - CFArrayAppendValue(builder->parentSources, kSecUserAnchorSource); - #endif - } - if (keychainsAllowed && builder->canAccessNetwork) { - CFArrayAppendValue(builder->parentSources, kSecCAIssuerSource); - } -#else /* TARGET_OS_BRIDGE */ - /* Bridge can only access memory sources. */ - CFArrayAppendValue(builder->parentSources, builder->certificateSource); - if (anchorsOnly) { - /* Add the Apple, system, and user anchor certificate db to the search list - if we don't explicitly trust them. */ - CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource); - } -#endif /* !TARGET_OS_BRIDGE */ - - /** Anchor Sources - ** The order here allows a client-provided anchor to overrule - ** a user or admin trust setting which can overrule the system anchors. - ** Apple's anchors cannot be overriden by a trust setting. - **/ -#if !TARGET_OS_BRIDGE - if (builder->anchorSource) { - CFArrayAppendValue(builder->anchorSources, builder->anchorSource); - } - if (!anchorsOnly) { - /* Only add the system and user anchor certificate db to the - anchorSources if we are supposed to trust them. */ - CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource); - if (keychainsAllowed) { -#if TARGET_OS_IPHONE - CFArrayAppendValue(builder->anchorSources, kSecUserAnchorSource); -#else /* TARGET_OS_OSX */ - if (kSecLegacyAnchorSource->contains && kSecLegacyAnchorSource->copyParents) { - CFArrayAppendValue(builder->anchorSources, kSecLegacyAnchorSource); - } -#endif - } - CFArrayAppendValue(builder->anchorSources, kSecSystemAnchorSource); - } -#else /* TARGET_OS_BRIDGE */ - /* Bridge can only access memory sources. */ - if (builder->anchorSource) { - CFArrayAppendValue(builder->anchorSources, builder->anchorSource); - } - if (!anchorsOnly) { - CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource); - } -#endif /* !TARGET_OS_BRIDGE */ - - builder->ocspResponses = CFRetainSafe(ocspResponses); - builder->signedCertificateTimestamps = CFRetainSafe(signedCertificateTimestamps); - - if(trustedLogs) { - builder->trustedLogs = SecOTAPKICreateTrustedCTLogsDictionaryFromArray(trustedLogs); - } - - /* Now let's get the leaf cert and turn it into a path. */ - SecCertificateRef leaf = - (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0); - SecCertificatePathVCRef path = SecCertificatePathVCCreate(NULL, leaf, NULL); - CFSetAddValue(builder->allPaths, path); - CFArrayAppendValue(builder->partialPaths, path); - - builder->path = CFRetainSafe(path); - SecPathBuilderSetPath(builder, path); - CFRelease(path); - - /* Next step is to process the leaf. We do that work on the builder queue - * to avoid blocking the main thread with database lookups. */ - builder->state = SecPathBuilderProcessLeaf; - builder->completed = completed; - builder->context = context; -} - -SecPathBuilderRef SecPathBuilderCreate(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, - CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, - bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponses, - CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, - SecPathBuilderCompleted completed, const void *context) { - SecPathBuilderRef builder = malloc(sizeof(*builder)); - memset(builder, 0, sizeof(*builder)); - SecPathBuilderInit(builder, builderQueue, clientAuditToken, certificates, - anchors, anchorsOnly, keychainsAllowed, policies, ocspResponses, - signedCertificateTimestamps, trustedLogs, verifyTime, - accessGroups, exceptions, completed, context); - return builder; -} - -/* Don't use this if you're going to modify the PVC array in the operation. */ -static void SecPathBuilderForEachPVC(SecPathBuilderRef builder,void (^operation)(SecPVCRef pvc, bool *stop)) { - if (!builder->pvcs) { return; } - bool stop = false; - CFIndex ix; - for (ix = 0; ix < builder->pvcCount; ix++) { - if (!builder->pvcs[ix]) { continue; } - operation(builder->pvcs[ix], &stop); - if (stop) { break; } - } -} - -static void SecPathBuilderDestroy(SecPathBuilderRef builder) { - secdebug("alloc", "destroy builder %p", builder); - dispatch_release_null(builder->queue); - if (builder->anchorSource) { - SecMemoryCertificateSourceDestroy(builder->anchorSource); - builder->anchorSource = NULL; - } - if (builder->certificateSource) { - SecMemoryCertificateSourceDestroy(builder->certificateSource); - builder->certificateSource = NULL; - } - if (builder->itemCertificateSource) { - SecItemCertificateSourceDestroy(builder->itemCertificateSource); - builder->itemCertificateSource = NULL; - } - if (builder->appleAnchorSource) { - SecMemoryCertificateSourceDestroy(builder->appleAnchorSource); - builder->appleAnchorSource = NULL; - } - CFReleaseNull(builder->clientAuditToken); - CFReleaseNull(builder->anchorSources); - CFReleaseNull(builder->parentSources); - CFReleaseNull(builder->allPaths); - CFReleaseNull(builder->partialPaths); - CFReleaseNull(builder->rejectedPaths); - CFReleaseNull(builder->candidatePaths); - CFReleaseNull(builder->ocspResponses); - CFReleaseNull(builder->signedCertificateTimestamps); - CFReleaseNull(builder->trustedLogs); - CFReleaseNull(builder->path); - CFReleaseNull(builder->revocation_check_method); - CFReleaseNull(builder->info); - CFReleaseNull(builder->exceptions); - - free(builder->analyticsData); - builder->analyticsData = NULL; - - if (builder->pvcs) { - CFIndex ix; - for (ix = 0; ix < builder->pvcCount; ix++) { - if (builder->pvcs[ix]) { - SecPVCDelete(builder->pvcs[ix]); - free(builder->pvcs[ix]); - } - } - free(builder->pvcs); - builder->pvcs = NULL; - } -} - -static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path) { - bool samePath = ((!path && !builder->path) || (path && builder->path && CFEqual(path, builder->path))); - if (!samePath) { - CFRetainAssign(builder->path, path); - } - CFReleaseNull(builder->info); - - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCSetPath(pvc, path); - }); -} - - -bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) { - return builder->canAccessNetwork; -} - -void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) { - if (builder->canAccessNetwork != allow) { - builder->canAccessNetwork = allow; - if (allow) { -#if !TARGET_OS_WATCH - secinfo("http", "network access re-enabled by policy"); - /* re-enabling network_access re-adds kSecCAIssuerSource as - a parent source. */ - CFArrayAppendValue(builder->parentSources, kSecCAIssuerSource); -#else - /* */ - secnotice("http", "network access not allowed on WatchOS"); - builder->canAccessNetwork = false; -#endif - } else { - secinfo("http", "network access disabled by policy"); - /* disabling network_access removes kSecCAIssuerSource from - the list of parent sources. */ - CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources, - CFRangeMake(0, CFArrayGetCount(builder->parentSources)), - kSecCAIssuerSource); - if (ix >= 0) - CFArrayRemoveValueAtIndex(builder->parentSources, ix); - } - } -} - -CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder) -{ - return CFRetainSafe(builder->ocspResponses); -} - -CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef builder) -{ - return CFRetainSafe(builder->signedCertificateTimestamps); -} - -CFDictionaryRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder) -{ - return CFRetainSafe(builder->trustedLogs); -} - -SecCertificateSourceRef SecPathBuilderGetAppAnchorSource(SecPathBuilderRef builder) -{ - return builder->anchorSource; -} - -CFSetRef SecPathBuilderGetAllPaths(SecPathBuilderRef builder) -{ - return builder->allPaths; -} - -TrustAnalyticsBuilder *SecPathBuilderGetAnalyticsData(SecPathBuilderRef builder) -{ - return builder->analyticsData; -} - -SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder) -{ - return builder->bestPath; -} - -SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder) { - return builder->path; -} - -CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder) { - return builder->verifyTime; -} - -bool SecPathBuilderHasTemporalParentChecks(SecPathBuilderRef builder) { - __block bool validIntermediates = false; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool *stop) { - CFArrayForEach(pvc->policies, ^(const void *value) { - SecPolicyRef policy = (SecPolicyRef)value; - if (CFDictionaryContainsKey(policy->_options, kSecPolicyCheckTemporalValidity)) { - validIntermediates = true; - *stop = true; - } - }); - }); - return validIntermediates; -} - -CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder) { - return SecCertificatePathVCGetCount(builder->path); -} - -SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix) { - return SecCertificatePathVCGetCertificateAtIndex(builder->path, ix); -} - -bool SecPathBuilderIsAnchored(SecPathBuilderRef builder) { - return SecCertificatePathVCIsAnchored(builder->path); -} - -unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder) { - unsigned int result = atomic_fetch_sub(&builder->asyncJobCount, 1); - secdebug("rvc", "%p: decrement asyncJobCount from %d", builder, result); - /* atomic_fetch_sub returns the original value, but we want this function to return the - * value after the operation. */ - return --result; -} - -void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount) { - atomic_store(&builder->asyncJobCount, jobCount); - secdebug("rvc", "%p: set asyncJobCount to %d", builder, jobCount); -} - -unsigned int SecPathBuilderGetAsyncJobCount(SecPathBuilderRef builder) { - unsigned int count = atomic_load(&builder->asyncJobCount); - secdebug("rvc", "%p: current asyncJobCount is %d", builder, count); - return count; -} - -CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder) { - return builder->info; -} - -CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder) { - return builder->revocation_check_method; -} - -void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method) { - CFRetainAssign(builder->revocation_check_method, method); - secdebug("rvc", "deferred revocation checking enabled using %@ method", method); -} - -bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder) { - return builder->online_revocation; -} - -void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder) { - builder->online_revocation = true; - secdebug("rvc", "revocation force online check"); -} - -bool SecPathBuilderGetCheckRevocationIfTrusted(SecPathBuilderRef builder) { - return builder->trusted_revocation; -} - -void SecPathBuilderSetCheckRevocationIfTrusted(SecPathBuilderRef builder) { - builder->trusted_revocation = true; - secdebug("rvc", "revocation check only if trusted"); -} - -CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder) { - return builder->exceptions; -} - -CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder) { - return builder->pvcCount; -} - -SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix) { - if (ix > (builder->pvcCount - 1)) { - return NULL; - } - return builder->pvcs[ix]; -} - -void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, - CFIndex ix, CFTypeRef result, bool force) { - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCSetResultForced(pvc, key, ix, result, force); - }); -} - -static bool SecPathBuilderIsOkResult(SecPathBuilderRef builder) { - /* If any of the PVCs passed, we accept the path. */ - __block bool acceptPath = false; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - acceptPath |= SecPVCIsOkResult(pvc); - }); - return acceptPath; -} - -SecPVCRef SecPathBuilderGetResultPVC(SecPathBuilderRef builder) { - /* Return the first PVC that passed */ - __block SecPVCRef resultPVC = NULL; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool *stop) { - if (SecPVCIsOkResult(pvc)) { - resultPVC = pvc; - *stop = true; - } - }); - if (resultPVC) { return resultPVC; } - - /* If we didn't return a passing PVC, return the first PVC. */ - return builder->pvcs[0]; -} - -/* This function assumes that the input source is an anchor source */ -static bool SecPathBuilderIsAnchorPerConstraints(SecPathBuilderRef builder, SecCertificateSourceRef source, - SecCertificateRef certificate) { - - /* Get the trust settings result for the PVCs. Only one PVC need match to - * trigger the anchor behavior -- policy validation will handle whether the - * path is truly anchored for that PVC. */ - __block bool result = false; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - if (SecPVCIsAnchorPerConstraints(pvc, source, certificate)) { - result = true; - *stop = true; - } - }); - - return result; -} - -/* Source returned in foundInSource has the same lifetime as the builder. */ -static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, - SecCertificateRef certificate, SecCertificateSourceRef *foundInSource) { - /* We look through the anchor sources in order. They are ordered in - SecPathBuilderInit so that process anchors override user anchors which - override system anchors. */ - CFIndex count = CFArrayGetCount(builder->anchorSources); - CFIndex ix; - for (ix = 0; ix < count; ++ix) { - SecCertificateSourceRef source = (SecCertificateSourceRef) - CFArrayGetValueAtIndex(builder->anchorSources, ix); - if (SecCertificateSourceContains(source, certificate)) { - if (foundInSource) - *foundInSource = source; - if (SecPathBuilderIsAnchorPerConstraints(builder, source, certificate)) { - return true; - } - } - } - return false; -} - -bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source) { - CFIndex anchorCount = CFArrayGetCount(builder->anchorSources); - return CFArrayContainsValue(builder->anchorSources, CFRangeMake(0,anchorCount), source); -} - -/* Return false if path is not a partial, if path was a valid candidate it - will have been added to builder->candidatePaths, if path was rejected - by the parent certificate checks (because it's expired or some other - static chaining check failed) it will have been added to rejectedPaths. - Return true path if path is a partial. */ -static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, - SecCertificatePathVCRef path) { - SecPathBuilderSetPath(builder, path); - __block bool parentChecksFail = true; - - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - /* The parent checks aren't actually PVC-dependent, so theoretically, - * we only need to run this once per path, but we want to set the - * results in all PVCs. */ - parentChecksFail &= !SecPVCParentCertificateChecks(pvc, - SecCertificatePathVCGetCount(path) - 1); - }); - - if (!builder->considerRejected && parentChecksFail) { - secdebug("trust", "Found rejected path %@", path); - CFArrayAppendValue(builder->rejectedPaths, path); - return false; - } - - SecPathVerifyStatus vstatus = SecCertificatePathVCVerify(path); - /* Candidate paths with failed signatures are discarded. */ - if (vstatus == kSecPathVerifyFailed) { - secdebug("trust", "Verify failed for path %@", path); - return false; - } - - if (vstatus == kSecPathVerifySuccess) { - /* The signature chain verified successfully, now let's find - out if we have an anchor for path. */ - if (SecCertificatePathVCIsAnchored(path)) { - secdebug("trust", "Adding candidate %@", path); - CFArrayAppendValue(builder->candidatePaths, path); - } - /* The path is not partial if the last cert is self-signed. - * The path is also not partial if the issuer of the last cert was the subject - * of a previous cert in the chain, indicating a cycle in the graph. See . */ - if (((SecCertificatePathVCSelfSignedIndex(path) >= 0) && - (SecCertificatePathVCSelfSignedIndex(path) == SecCertificatePathVCGetCount(path)-1)) || - SecCertificatePathVCIsCycleInGraph(path)) { - if (!builder->considerRejected) { - secdebug("trust", "Adding non-partial non-anchored reject %@", path); - CFArrayAppendValue(builder->rejectedPaths, path); - } else { - /* This path was previously rejected as unanchored non-partial, but now that - * we're considering rejected paths, this is a candidate. */ - secdebug("trust", "Adding non-partial non-anchored candidate %@", path); - CFArrayAppendValue(builder->candidatePaths, path); - } - return false; - } - } - - return true; -} - -static void addOptionsToPolicy(SecPolicyRef policy, CFDictionaryRef newOptions) { - __block CFMutableDictionaryRef oldOptions = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options); - CFDictionaryForEach(newOptions, ^(const void *key, const void *value) { - CFDictionaryAddValue(oldOptions, key, value); - }); - CFAssignRetained(policy->_options, oldOptions); -} - -static void SecPathBuilderAddPinningPolicies(SecPathBuilderRef builder) { - CFIndex ix, initialPVCCount = builder->pvcCount; - for (ix = 0; ix < initialPVCCount; ix++) { - CFArrayRef policies = CFRetainSafe(builder->pvcs[ix]->policies); - CFIndex policyIX; - for (policyIX = 0; policyIX < CFArrayGetCount(policies); policyIX++) { - SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); - CFStringRef policyName = SecPolicyGetName(policy); - CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); - if (!hostname) { continue; } //No hostname to look up; probably not an SSL policy, skip - - /* Query the pinning database for this policy */ - CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(query, kSecPinningDbKeyPolicyName, policyName); - CFDictionaryAddValue(query, kSecPinningDbKeyHostname, hostname); - CFDictionaryRef results = SecPinningDbCopyMatching(query); - CFReleaseNull(query); - if (!results) { continue; } //No rules for this hostname or policyName - - /* Found pinning policies. Apply them to the path builder. */ - CFArrayRef newRules = CFDictionaryGetValue(results, kSecPinningDbKeyRules); - CFStringRef dbPolicyName = CFDictionaryGetValue(results, kSecPinningDbKeyPolicyName); - secinfo("SecPinningDb", "found pinning %lu %@ policies for hostname %@, policyName %@", - (unsigned long)CFArrayGetCount(newRules), dbPolicyName, hostname, policyName); - CFIndex newRulesIX; - for (newRulesIX = 0; newRulesIX < CFArrayGetCount(newRules); newRulesIX++) { - if (!isDictionary(CFArrayGetValueAtIndex(newRules, newRulesIX))) { - continue; - } - - /* Create the new policies with pinning rules (preserving other ANDed policies). */ - CFDictionaryRef newOptions = (CFDictionaryRef)CFArrayGetValueAtIndex(newRules, newRulesIX); - SecPolicyRef newPolicy = SecPolicyCreateSSL(true, hostname); - if (!newPolicy) { continue; } - addOptionsToPolicy(newPolicy, newOptions); - SecPolicySetName(newPolicy, dbPolicyName); - CFMutableArrayRef newPolicies = CFArrayCreateMutableCopy(NULL, 0, policies); - if (!newPolicies) { CFReleaseNull(newPolicy); continue; } - CFArrayReplaceValues(newPolicies, CFRangeMake(policyIX, 1), (const void **)&newPolicy, 1); - - if (newRulesIX == 0) { - /* For the first set of pinning rules, replace this PVC's policies */ - CFRetainAssign(builder->pvcs[ix]->policies, newPolicies); - } else { - /* If there were two or more dictionaries of rules, we need to treat them as an "OR". - * Create another PVC for this dicitionary. */ - builder->pvcs = realloc(builder->pvcs, (builder->pvcCount + 1) * sizeof(SecPVCRef)); - builder->pvcs[builder->pvcCount] = malloc(sizeof(struct OpaqueSecPVC)); - SecPVCInit(builder->pvcs[builder->pvcCount], builder, newPolicies); - builder->pvcCount++; - } - CFReleaseNull(newPolicy); - CFReleaseNull(newPolicies); - } - CFReleaseNull(results); - } - CFReleaseNull(policies); - } -} - -static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder) { - SecPathBuilderAddPinningPolicies(builder); - - /* We need to find and set constraints on the leaf-only path */ - SecCertificatePathVCRef path = builder->path; - SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0); - - SecCertificateSourceRef source = NULL; - bool isAnchor = false; - CFArrayRef constraints = NULL; - if (SecPathBuilderIsAnchor(builder, leaf, &source)) { - isAnchor = true; - } - if (source) { - constraints = SecCertificateSourceCopyUsageConstraints(source, leaf); - } - SecCertificatePathVCSetUsageConstraintsAtIndex(path, constraints, 0); - CFReleaseSafe(constraints); - if (isAnchor) { - SecCertificatePathVCSetIsAnchored(path); - CFArrayAppendValue(builder->candidatePaths, path); - } - - __block bool leafChecksFail = true; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCLeafChecks(pvc); - leafChecksFail &= !SecPVCIsOkResult(pvc); - }); - builder->considerRejected = leafChecksFail; - - builder->state = SecPathBuilderGetNext; - return true; -} - -/* Given the builder, a partial chain partial and the parents array, construct - a SecCertificatePath for each parent. After discarding previously - considered paths and paths with cycles, sort out which array each path - should go in, if any. */ -static void SecPathBuilderProcessParents(SecPathBuilderRef builder, - SecCertificatePathVCRef partial, CFArrayRef parents) { - CFIndex rootIX = SecCertificatePathVCGetCount(partial) - 1; - CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0; - CFIndex parentIX; - for (parentIX = 0; parentIX < num_parents; ++parentIX) { - SecCertificateRef parent = (SecCertificateRef) - CFArrayGetValueAtIndex(parents, parentIX); - CFIndex ixOfParent = SecCertificatePathVCGetIndexOfCertificate(partial, - parent); - if (ixOfParent != kCFNotFound) { - /* partial already contains parent. Let's not add the same - certificate again. */ - if (ixOfParent == rootIX) { - /* parent is equal to the root of the partial, so partial - looks to be self issued. */ - SecCertificatePathVCSetSelfIssued(partial); - } - continue; - } - - /* FIXME Add more sanity checks to see that parent really can be - a parent of partial_root. subjectKeyID == authorityKeyID, - signature algorithm matches public key algorithm, etc. */ - SecCertificateSourceRef source = NULL; - bool is_anchor = SecPathBuilderIsAnchor(builder, parent, &source); - CFArrayRef constraints = (source) ? SecCertificateSourceCopyUsageConstraints(source, parent) : NULL; - SecCertificatePathVCRef path = SecCertificatePathVCCreate(partial, parent, constraints); - CFReleaseSafe(constraints); - if (!path) - continue; - if (!CFSetContainsValue(builder->allPaths, path)) { - CFSetAddValue(builder->allPaths, path); - if (is_anchor) - SecCertificatePathVCSetIsAnchored(path); - if (SecPathBuilderIsPartial(builder, path)) { - /* Insert path right at the current position since it's a new - candiate partial. */ - CFArrayInsertValueAtIndex(builder->partialPaths, - ++builder->partialIX, path); - secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@", - parentIX + 1, num_parents, path); - } - secdebug("trust", "found new path %@", path); - } - CFRelease(path); - } -} - -/* Callback for the SecPathBuilderGetNext() functions call to - SecCertificateSourceCopyParents(). */ -static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) { - SecPathBuilderRef builder = (SecPathBuilderRef)context; - SecCertificatePathVCRef partial = (SecCertificatePathVCRef) - CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); - secdebug("async", "%@ parents %@", partial, parents); - SecPathBuilderProcessParents(builder, partial, parents); - - builder->state = SecPathBuilderGetNext; - SecPathBuilderStep(builder); -} - -static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { - /* If we have any candidates left to go return those first. */ - if (CFArrayGetCount(builder->candidatePaths)) { - SecCertificatePathVCRef path = (SecCertificatePathVCRef) - CFArrayGetValueAtIndex(builder->candidatePaths, 0); - CFArrayRemoveValueAtIndex(builder->candidatePaths, 0); - secdebug("trust", "SecPathBuilderGetNext returning candidate %@", - path); - SecPathBuilderSetPath(builder, path); - builder->state = SecPathBuilderValidatePath; - return true; - } - - /* If we are considering rejected chains we check each rejected path - with SecPathBuilderIsPartial() which checks the signature chain and - either drops the path if it's not properly signed, add it as a - candidate if it has a trusted anchor, or adds it as a partial - to be considered once we finish considering all the rejects. */ - if (builder->considerRejected) { - CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths); - if (rejectedIX) { - rejectedIX--; - SecCertificatePathVCRef path = (SecCertificatePathVCRef) - CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX); - if (SecPathBuilderIsPartial(builder, path)) { - CFArrayInsertValueAtIndex(builder->partialPaths, - ++builder->partialIX, path); - } - CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX); - - /* Keep going until we have moved all rejected partials into - the regular partials or candidates array. */ - return true; - } - } - - /* If builder->partialIX is < 0 we have considered all partial chains - this block must ensure partialIX >= 0 if execution continues past - it's end. */ - if (builder->partialIX < 0) { - CFIndex num_sources = CFArrayGetCount(builder->parentSources); - if (builder->nextParentSource < num_sources) { - builder->nextParentSource++; - secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources", - builder->nextParentSource, num_sources); - } else { - /* We've run out of new sources to consider so let's look at - rejected chains and after that even consider partials - directly. - FIXME we might not want to consider partial paths that - are subsets of other partial paths, or not consider them - at all if we already have an (unpreferred) accept or anchored reject */ - if (!builder->considerRejected) { - builder->considerRejected = true; - secdebug("trust", "considering rejected paths"); - } else if (!builder->considerPartials) { - builder->considerPartials = true; - secdebug("trust", "considering partials"); - } else { - /* We're all out of options, so we can't produce any more - candidates. Let's calculate details and return the best - path we found. */ - builder->state = SecPathBuilderComputeDetails; - return true; - } - } - builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1; - secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1); - return true; - } - - /* We know builder->partialIX >= 0 if we get here. */ - SecCertificatePathVCRef partial = (SecCertificatePathVCRef) - CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); - /* Don't try to extend partials anymore once we are in the considerPartials - state, since at this point every partial has been extended with every - possible parentSource already. */ - if (builder->considerPartials) { - --builder->partialIX; - SecPathBuilderSetPath(builder, partial); - builder->state = SecPathBuilderValidatePath; - return true; - } - - /* Don't try to extend partials anymore if we already have too many chains. */ - if (CFSetGetCount(builder->allPaths) > MAX_NUM_CHAINS) { - secnotice("trust", "not building any more paths, already have %" PRIdCFIndex, - CFSetGetCount(builder->allPaths)); - builder->partialIX = -1; - return true; - } - - /* Attempt to extend this partial path with another certificate. This - should give us a list of potential parents to consider. */ - secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@", - builder->partialIX + 1, CFArrayGetCount(builder->partialPaths), - partial); - - /* Attempt to extend partial, leaving all possible extended versions - of partial in builder->extendedPaths. */ - CFIndex sourceIX = SecCertificatePathVCGetNextSourceIndex(partial); - CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources); - if (sourceIX < num_anchor_sources + builder->nextParentSource) { - SecCertificateSourceRef source; - if (sourceIX < num_anchor_sources) { - source = (SecCertificateSourceRef) - CFArrayGetValueAtIndex(builder->anchorSources, sourceIX); - secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1, - num_anchor_sources); - } else { - CFIndex parentIX = sourceIX - num_anchor_sources; - source = (SecCertificateSourceRef) - CFArrayGetValueAtIndex(builder->parentSources, parentIX); - secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1, - builder->nextParentSource); - } - SecCertificatePathVCSetNextSourceIndex(partial, sourceIX + 1); - SecCertificateRef root = SecCertificatePathVCGetRoot(partial); - return SecCertificateSourceCopyParents(source, root, - builder, SecPathBuilderExtendPaths); - } else { - --builder->partialIX; - } - - return true; -} - -/* One or more of the policies did not accept the candidate path. */ -static void SecPathBuilderReject(SecPathBuilderRef builder) { - check(builder); - - builder->state = SecPathBuilderGetNext; - - bool bestPathIsEV = SecCertificatePathVCIsEV(builder->bestPath); - bool isEV = SecCertificatePathVCIsEV(builder->path); - - if (bestPathIsEV && !isEV) { - /* We never replace an ev reject with a non ev reject. */ - return; - } - - CFIndex bestPathScore = SecCertificatePathVCGetScore(builder->bestPath); - CFIndex score = SecCertificatePathVCScore(builder->path, builder->verifyTime); - SecCertificatePathVCSetScore(builder->path, score); - - /* The current chain is valid for EV, but revocation checking failed. We - replace any previously accepted or rejected non EV chains with the - current one. */ - if (isEV && !bestPathIsEV) { - bestPathScore = 0; - } - if (!builder->bestPath || score > bestPathScore) { - if (builder->bestPath) { - secinfo("reject", - "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", - (bestPathIsEV ? "" : "non "), - (bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), - bestPathScore, - (isEV ? "" : "non "), (long)score, builder->path); - } else { - secinfo("reject", "%sev score: %" PRIdCFIndex " %@", - (isEV ? "" : "non "), score, builder->path); - } - - builder->bestPath = builder->path; - } else { - secinfo("reject", "%sev score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@", - (isEV ? "" : "non "), score, bestPathScore, builder->path); - } -} - -/* All policies accepted the candidate path. */ -static void SecPathBuilderAccept(SecPathBuilderRef builder) { - if (!builder) { return; } - bool isSHA2 = !SecCertificatePathVCHasWeakHash(builder->path); - bool isOptionallySHA2 = !SecCertificateIsWeakHash(SecPathBuilderGetCertificateAtIndex(builder, 0)); - bool isEV = SecCertificatePathVCIsEV(builder->path); - bool isOptionallyEV = SecCertificatePathVCIsOptionallyEV(builder->path); - CFIndex bestScore = SecCertificatePathVCGetScore(builder->bestPath); - /* Score this path. Note that all points awarded or deducted in - * SecCertificatePathScore are < 100,000 */ - CFIndex currScore = (SecCertificatePathVCScore(builder->path, builder->verifyTime) + - ACCEPT_PATH_SCORE + // 10,000,000 points for accepting - (isEV ? 1000000 : 0)); //1,000,000 points for EV - SecCertificatePathVCSetScore(builder->path, currScore); - if (currScore > bestScore) { - // current path is better than existing best path - secinfo("accept", "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", - (SecCertificatePathVCIsEV(builder->bestPath) ? "" : "non "), - (bestScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), - bestScore, - (isEV ? "" : "non "), (long)currScore, builder->path); - - builder->bestPath = builder->path; - } - - /* If we found the best accept we can, we want to switch directly to the - SecPathBuilderComputeDetails state here, since we're done. */ - if ((isEV || !isOptionallyEV) && (isSHA2 || !isOptionallySHA2)) - builder->state = SecPathBuilderComputeDetails; - else - builder->state = SecPathBuilderGetNext; -} - -/* Return true iff a given path satisfies all the specified policies at - verifyTime. */ -static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) { - - if (builder->considerRejected) { - SecPathBuilderReject(builder); - return true; - } - - builder->state = SecPathBuilderDidValidatePath; - - /* Revocation checking is now done before path checks, to ensure that - we have OCSP responses for CT checking and that isAllowlisted is - appropriately set for other checks. */ - bool completed = SecPathBuilderCheckRevocation(builder); - - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCPathChecks(pvc); - }); - - return completed; -} - -static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) { - /* We perform the revocation required policy checks here because - * this is the state we call back into once all the asynchronous - * revocation check calls are done. */ - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCPathCheckRevocationResponsesReceived(pvc); - }); - - if (SecPathBuilderIsOkResult(builder)) { - SecPathBuilderAccept(builder); - } else { - SecPathBuilderReject(builder); - } - assert(builder->state != SecPathBuilderDidValidatePath); - return true; -} - -static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) { - /* We have to re-do all the checks so that the results get set in the - * PVC for the best path, as the last path checked may not have been the best. */ - SecPathBuilderSetPath(builder, builder->bestPath); - __block CFIndex ix, pathLength = SecCertificatePathVCGetCount(builder->bestPath); - - __block bool completed = true; - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCComputeDetails(pvc, builder->bestPath); - completed &= SecPathBuilderCheckRevocation(builder); - for (ix = 1; ix < pathLength; ++ix) { - SecPVCParentCertificateChecks(pvc, ix); - } - SecPVCPathChecks(pvc); - }); - - builder->state = SecPathBuilderReportResult; - - /* Check revocation responses. */ - SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { - SecPVCPathCheckRevocationResponsesReceived(pvc); - }); - - /* Reject the certificate if it was accepted before but we failed it now. (Should not happen anymore.) */ - if (SecCertificatePathVCGetScore(builder->bestPath) > ACCEPT_PATH_SCORE && !SecPathBuilderIsOkResult(builder)) { - SecCertificatePathVCResetScore(builder->bestPath); - secwarning("In ComputeDetails, we got a reject after an accept in DidValidatePath."); - } - - return completed; -} - -static bool SecPathBuilderReportResult(SecPathBuilderRef builder) { - builder->info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - - /* isEV is not set unless also CT verified. Here, we need to check that we - * got a revocation response as well. */ - if (builder->info && SecCertificatePathVCIsEV(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { -#if !TARGET_OS_WATCH - if (SecCertificatePathVCIsRevocationDone(builder->bestPath)) { - CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); - if (nextUpdate != 0) { -#else - /* We don't do networking on watchOS, so we can't require OCSP for EV */ - { - { -#endif - /* Successful revocation check, so this cert is EV */ - CFDictionarySetValue(builder->info, kSecTrustInfoExtendedValidationKey, - kCFBooleanTrue); /* iOS key */ - CFDictionarySetValue(builder->info, kSecTrustExtendedValidation, - kCFBooleanTrue); /* unified API key */ - SecCertificateRef leaf = SecPathBuilderGetCertificateAtIndex(builder, 0); - CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf); - if (leafCompanyName) { - CFDictionarySetValue(builder->info, kSecTrustInfoCompanyNameKey, - leafCompanyName); /* iOS key */ - CFDictionarySetValue(builder->info, kSecTrustOrganizationName, - leafCompanyName); /* unified API key */ - CFRelease(leafCompanyName); - } - } - } - } - - if (builder->info && SecPathBuilderIsOkResult(builder) && SecCertificatePathVCIsRevocationDone(builder->bestPath)) { - CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); - if (nextUpdate != 0) { - /* always populate revocation info for successful revocation check */ - CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate); - CFDictionarySetValue(builder->info, kSecTrustInfoRevocationValidUntilKey, - validUntil); /* iOS key */ - CFDictionarySetValue(builder->info, kSecTrustRevocationValidUntilDate, - validUntil); /* unified API key */ - CFRelease(validUntil); - CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, - kCFBooleanTrue); /* iOS key */ - CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, - kCFBooleanTrue); /* unified API key */ - } else if (SecCertificatePathVCIsEV(builder->bestPath)) { - /* populate revocation info for failed revocation check with EV */ - CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, - kCFBooleanFalse); /* iOS key */ - CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, - kCFBooleanFalse); /* unified API key */ - } - } - - /* If revoked, set the revocation reason */ - if (builder->info && !SecPathBuilderIsOkResult(builder) && SecCertificatePathVCIsRevocationDone(builder->bestPath) - && SecCertificatePathVCGetRevocationReason(builder->bestPath)) { - CFNumberRef reason = SecCertificatePathVCGetRevocationReason(builder->bestPath); - CFDictionarySetValue(builder->info, kSecTrustRevocationReason, reason); - } - - /* Set CT marker in the info */ - if (builder->info && SecCertificatePathVCIsCT(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { - CFDictionarySetValue(builder->info, kSecTrustInfoCertificateTransparencyKey, - kCFBooleanTrue); - } - - - /* This will trigger the outer step function to call the completion - function. */ - builder->state = NULL; - return false; -} - -/* @function SecPathBuilderStep - @summary This is the core of the async engine. - @description Return false iff job is complete, true if a network request - is pending. - builder->state is a function pointer which is to be invoked. - If you call this function from within a builder->state invocation it - immediately returns true. - Otherwise the following steps are repeated endlessly (unless a step returns) - builder->state is invoked. If it returns true and builder->state is still - non NULL this proccess is repeated. - If a state returns false, SecPathBuilder will return true - if builder->state is non NULL. - If builder->state is NULL then regardless of what the state function returns - the completion callback will be invoked and the builder will be deallocated. - */ -bool SecPathBuilderStep(SecPathBuilderRef builder) { - secdebug("async", "step builder %p", builder); - if (builder->activations) { - secdebug("async", "activations: %lu returning true", - builder->activations); - return true; - } - - secdebug("async", "activations: %lu", builder->activations); - builder->activations++; - while (builder->state && builder->state(builder)); - --builder->activations; - - if (builder->state) { - secdebug("async", "waiting for async reply, exiting"); - /* A state returned false, it's waiting for network traffic. Let's - return. */ - return true; - } - - if (builder->activations) { - /* There is still at least one other running instance of this builder - somewhere on the stack, we let that instance take care of sending - the client a response. */ - return false; - } - - SecPVCRef pvc = SecPathBuilderGetResultPVC(builder); - SecTrustResultType result = pvc->result; - - if (builder->exceptions && pvc->result == kSecTrustResultUnspecified) { - result = kSecTrustResultProceed; - } - - secinfo("trust", "completed: %@ details: %@ result: %d", - builder->bestPath, pvc->details, result); - - if (builder->completed) { - /* We want to retain just the data we need to return to our caller - * and free the rest of the builder before doing the callback. - * Since the callback may end an XPC transaction that made us active, we - * want to retain as little residual memory as possible. */ - CFArrayRef resultPath = SecCertificatePathVCCopyCertificates(builder->bestPath); - CFDictionaryRef info = CFRetainSafe(builder->info); - CFArrayRef details = CFRetainSafe(pvc->details); - const void *context = builder->context; - SecPathBuilderCompleted completed = builder->completed; - - secdebug("async", "free builder"); - SecPathBuilderDestroy(builder); - free(builder); - - secdebug("async", "returning to caller"); - completed(context, resultPath, details, info, result); - CFReleaseNull(resultPath); - CFReleaseNull(info); - CFReleaseNull(details); - } else { - SecPathBuilderDestroy(builder); - free(builder); - } - - return false; -} - -dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) { - return (builder) ? builder->queue : NULL; -} - -CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder) { - return (builder) ? (CFDataRef)CFRetainSafe(builder->clientAuditToken) : NULL; -} - -// MARK: - -// MARK: SecTrustServer -/******************************************************** - ****************** SecTrustServer ********************** - ********************************************************/ - -typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error); - -static void -SecTrustServerEvaluateCompleted(const void *userData, - CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, - SecTrustResultType result) { - SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData; - TrustdHealthAnalyticsLogEvaluationCompleted(); - evaluated(result, details, info, chain, NULL); - Block_release(evaluated); -} - -void -SecTrustServerEvaluateBlock(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error)) { - /* We need an array containing at least one certificate to proceed. */ - if (!isArray(certificates) || !(CFArrayGetCount(certificates) > 0)) { - CFErrorRef certError = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL); - evaluated(kSecTrustResultInvalid, NULL, NULL, NULL, certError); - CFReleaseSafe(certError); - return; - } - SecTrustServerEvaluationCompleted userData = Block_copy(evaluated); - /* Call the actual evaluator function. */ - SecPathBuilderRef builder = SecPathBuilderCreate(builderQueue, clientAuditToken, - certificates, anchors, - anchorsOnly, keychainsAllowed, policies, - responses, SCTs, trustedLogs, - verifyTime, accessGroups, exceptions, - SecTrustServerEvaluateCompleted, userData); - SecPathBuilderStep(builder); -} - - -// NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly -SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *pdetails, CFDictionaryRef *pinfo, CFArrayRef *pchain, CFErrorRef *perror) { - dispatch_semaphore_t done = dispatch_semaphore_create(0); - __block SecTrustResultType result = kSecTrustResultInvalid; - __block dispatch_queue_t queue = dispatch_queue_create("com.apple.trustd.evaluation.recursive", DISPATCH_QUEUE_SERIAL); - - /* We need to use the async call with the semaphore here instead of a synchronous call because we may return from - * SecPathBuilderStep while waiting for an asynchronous network call in order to complete the evaluation. That return - * is necessary in the XPC interface in order to free up the workloop for other trust evaluations while we wait for - * the networking to complete, but here, we need to make sure we wait for the network call (which will async back - * onto our queue) to complete and signal us before we return to the "inline" caller. */ - dispatch_async(queue, ^{ - SecTrustServerEvaluateBlock(queue, NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, exceptions, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error) { - result = tr; - if (tr == kSecTrustResultInvalid) { - if (perror) { - *perror = error; - CFRetainSafe(error); - } - } else { - if (pdetails) { - *pdetails = details; - CFRetainSafe(details); - } - if (pinfo) { - *pinfo = info; - CFRetainSafe(info); - } - if (pchain) { - *pchain = chain; - CFRetainSafe(chain); - } - } - dispatch_semaphore_signal(done); - }); - }); - dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER); - dispatch_release(done); - dispatch_release_null(queue); - - return result; -} diff --git a/OSX/sec/securityd/SecTrustServer.h b/OSX/sec/securityd/SecTrustServer.h deleted file mode 100644 index 02983bae..00000000 --- a/OSX/sec/securityd/SecTrustServer.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2008-2009,2012-2014,2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecTrustServer.h - certificate trust evaluation engine - * - * - */ - -#ifndef _SECURITY_SECTRUSTSERVER_H_ -#define _SECURITY_SECTRUSTSERVER_H_ - -#include - -#include -#include /* For errSecWaitForCallback. */ -#include "securityd/SecCertificateServer.h" -#include "securityd/SecCertificateSource.h" -#include - -__BEGIN_DECLS - -typedef struct SecPathBuilder *SecPathBuilderRef; - -typedef struct OpaqueSecPVC *SecPVCRef; - -struct OpaqueSecPVC { - SecPathBuilderRef builder; - CFArrayRef policies; - CFDictionaryRef callbacks; - CFIndex policyIX; - bool require_revocation_response; - - CFArrayRef leafDetails; - SecTrustResultType leafResult; - - CFArrayRef details; - SecTrustResultType result; -}; - -/* Completion callback. */ -typedef void(*SecPathBuilderCompleted)(const void *userData, - CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, - SecTrustResultType result); - -/* Returns a new trust path builder and policy evaluation engine instance. */ -SecPathBuilderRef SecPathBuilderCreate(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, - CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, - bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponse, - CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, - SecPathBuilderCompleted completed, const void *userData); - -/* Returns true if it's ok to perform network operations for this builder. */ -bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder); - -/* Disable or enable network access for this builder if allow is false - network access will be disabled. */ -void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow); - -/* Get the stapled SCTs */ -CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef builder); -CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder); -CFDictionaryRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder); - -CFSetRef SecPathBuilderGetAllPaths(SecPathBuilderRef builder); -SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder); -SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder); -CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder); -CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder); -SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix); -CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder); -bool SecPathBuilderHasTemporalParentChecks(SecPathBuilderRef builder); - -/* Returns the isAnchored status of the path. The path builder sets isAnchored - * based solely on whether the terminating cert has some sort of trust setting - * on it. This check does NOT reflect whether that anchor is actually trusted, - * as trust in an anchor is contextual to the policy being validated. */ -bool SecPathBuilderIsAnchored(SecPathBuilderRef builder); -bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source); -SecCertificateSourceRef SecPathBuilderGetAppAnchorSource(SecPathBuilderRef builder); - -CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder); -SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix); - -/* Returns the first PVC that passed */ -SecPVCRef SecPathBuilderGetResultPVC(SecPathBuilderRef builder); - -void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, - CFIndex ix, CFTypeRef result, bool force); - -/* This is an atomic pre-decrement operation */ -unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder); -void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount); -unsigned int SecPathBuilderGetAsyncJobCount(SecPathBuilderRef builder); - -CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder); - -/* Enable revocation checking if the rest of the policy checks succeed. */ -CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder); -void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method); - -/* Require a online revocation response for the chain. */ -bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder); -void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder); - -/* Only do networking for revocation if the chain is trusted */ -bool SecPathBuilderGetCheckRevocationIfTrusted(SecPathBuilderRef builder); -void SecPathBuilderSetCheckRevocationIfTrusted(SecPathBuilderRef builder); - -/* Core of the trust evaluation engine, this will invoke the completed - callback and return false if the evaluation completed, or return true if - the evaluation is still waiting for some external event (usually the - network). */ -bool SecPathBuilderStep(SecPathBuilderRef builder); - -/* Return the dispatch queue to be used by this builder. */ -dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder); - -/* Return the client audit token associated with this path builder, - which caller must release, or NULL if there is no external client. */ -CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder); - -/* Evaluate trust and call evaluated when done. */ -void SecTrustServerEvaluateBlock(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error)); - -/* Synchronously invoke SecTrustServerEvaluateBlock. */ -SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *details, CFDictionaryRef *info, CFArrayRef *chain, CFErrorRef *error); - -/* TrustAnalytics builder types */ -typedef CF_OPTIONS(uint8_t, TA_SCTSource) { - TA_SCTEmbedded = 1 << 0, - TA_SCT_OCSP = 1 << 1, - TA_SCT_TLS = 1 << 2, -}; - -typedef CF_ENUM(uint8_t, TA_CTFailureReason) { - TA_CTNoFailure = 0, - TA_CTNoSCTs = 1, - TA_CTMissingLogs = 2, - TA_CTNoCurrentSCTsUnknownLog = 3, - TA_CTNoCurrentSCTsDisqualifiedLog = 4, - TA_CTPresentedNotEnoughUnknown = 5, - TA_CTPresentedNotEnoughDisqualified = 6, - TA_CTPresentedNotEnough = 7, - TA_CTEmbeddedNotEnoughUnknown = 8, - TA_CTEmbeddedNotEnoughDisqualified = 9, - TA_CTEmbeddedNotEnough = 10, -}; - -typedef CF_OPTIONS(uint8_t, TAValidStatus) { - TAValidDefinitelyOK = 1 << 0, - TAValidProbablyOK = 1 << 1, - TAValidProbablyRevoked = 1 << 2, - TAValidDefinitelyRevoked = 1 << 3, - TAValidDateConstrainedOK = 1 << 4, - TAValidDateConstrainedRevoked = 1 << 5, - TAValidPolicyConstrainedOK = 1 << 6, - TAValidPolicyConstrainedDenied = 1 << 7, -}; - -typedef struct { - uint64_t start_time; - // Certificate Transparency - TA_SCTSource sct_sources; - uint32_t number_scts; - uint32_t number_trusted_scts; - TA_CTFailureReason ct_failure_reason; - bool ct_one_current; - // CAIssuer - bool ca_issuer_cache_hit; - bool ca_issuer_network; - uint32_t ca_issuer_fetches; - uint64_t ca_issuer_fetch_time; - uint32_t ca_issuer_fetch_failed; - bool ca_issuer_unsupported_data; - bool ca_issuer_multiple_certs; - // OCSP - bool ocsp_no_check; - bool ocsp_cache_hit; - bool ocsp_network; - uint32_t ocsp_fetches; - uint64_t ocsp_fetch_time; - uint32_t ocsp_fetch_failed; - bool ocsp_validation_failed; - // Valid - TAValidStatus valid_status; - bool valid_trigger_ocsp; - bool valid_require_ct; - bool valid_known_intermediates_only; - bool valid_unknown_intermediate; -} TrustAnalyticsBuilder; - -TrustAnalyticsBuilder *SecPathBuilderGetAnalyticsData(SecPathBuilderRef builder); - -__END_DECLS - -#endif /* !_SECURITY_SECTRUSTSERVER_H_ */ diff --git a/OSX/sec/securityd/SecTrustStoreServer.c b/OSX/sec/securityd/SecTrustStoreServer.c deleted file mode 100644 index aaa6bf0b..00000000 --- a/OSX/sec/securityd/SecTrustStoreServer.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright (c) 2007-2010,2012-2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecTrustStoreServer.c - CertificateSource API to a system root certificate store - */ -#include "SecTrustStoreServer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "utilities/sqlutils.h" -#include "utilities/SecDb.h" -#include -#include "utilities/SecFileLocations.h" -#include -#include -#include -#include -#include -#include - -/* uid of the _securityd user. */ -#define SECURTYD_UID 64 - -static dispatch_once_t kSecTrustStoreUserOnce; -static SecTrustStoreRef kSecTrustStoreUser = NULL; - -static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?"; -static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?"; -static const char insertSQL[] = "INSERT OR REPLACE INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)"; -static const char deleteSQL[] = "DELETE FROM tsettings WHERE sha1=?"; -static const char deleteAllSQL[] = "BEGIN EXCLUSIVE TRANSACTION; DELETE from tsettings; COMMIT TRANSACTION; VACUUM;"; -static const char copyAllSQL[] = "SELECT data,tset FROM tsettings ORDER BY sha1"; -static const char countAllSQL[] = "SELECT COUNT(*) FROM tsettings"; - -#define kSecTrustStoreName CFSTR("TrustStore") -#define kSecTrustStoreDbExtension CFSTR("sqlite3") - -#define kTrustStoreFileName CFSTR("TrustStore.sqlite3") - - -struct __SecTrustStore { - dispatch_queue_t queue; - sqlite3 *s3h; - sqlite3_stmt *copyParents; - sqlite3_stmt *contains; - bool readOnly; - bool containsSettings; // For optimization of high-use calls. -}; - -// MARK: - -// MARK: Corporate Root functions - -// MARK: - -// MARK: Trust store functions - -static int sec_create_path(const char *path) -{ - char pathbuf[PATH_MAX]; - size_t pos, len = strlen(path); - if (len == 0 || len > PATH_MAX) - return SQLITE_CANTOPEN; - memcpy(pathbuf, path, len); - for (pos = len-1; pos > 0; --pos) - { - /* Search backwards for trailing '/'. */ - if (pathbuf[pos] == '/') - { - pathbuf[pos] = '\0'; - /* Attempt to create parent directories of the database. */ - if (!mkdir(pathbuf, 0777)) - break; - else - { - int err = errno; - if (err == EEXIST) - return 0; - if (err == ENOTDIR) - return SQLITE_CANTOPEN; - if (err == EROFS) - return SQLITE_READONLY; - if (err == EACCES) - return SQLITE_PERM; - if (err == ENOSPC || err == EDQUOT) - return SQLITE_FULL; - if (err == EIO) - return SQLITE_IOERR; - - /* EFAULT || ELOOP | ENAMETOOLONG || something else */ - return SQLITE_INTERNAL; - } - } - } - return SQLITE_OK; -} - -static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h, - bool create_path) -{ - int s3e; - s3e = sqlite3_open(db_name, s3h); - if (s3e == SQLITE_CANTOPEN && create_path) { - /* Make sure the path to db_name exists and is writable, then - try again. */ - s3e = sec_create_path(db_name); - if (!s3e) - s3e = sqlite3_open(db_name, s3h); - } - - return s3e; -} - -static int64_t SecTrustStoreCountAll(SecTrustStoreRef ts) { - __block int64_t result = -1; - require_quiet(ts, errOutNotLocked); - dispatch_sync(ts->queue, ^{ - sqlite3_stmt *countAllStmt = NULL; - int s3e = sqlite3_prepare_v2(ts->s3h, countAllSQL, sizeof(countAllSQL), - &countAllStmt, NULL); - if (s3e == SQLITE_OK) { - s3e = sqlite3_step(countAllStmt); - if (s3e == SQLITE_ROW) { - result = sqlite3_column_int64(countAllStmt, 0); - } - } - - if (countAllStmt) { - verify_noerr(sqlite3_finalize(countAllStmt)); - } - }); - -errOutNotLocked: - return result; -} - -static SecTrustStoreRef SecTrustStoreCreate(const char *db_name, - bool create) { - SecTrustStoreRef ts; - int s3e = SQLITE_OK; - - require(ts = (SecTrustStoreRef)malloc(sizeof(struct __SecTrustStore)), errOut); - ts->queue = dispatch_queue_create("truststore", DISPATCH_QUEUE_SERIAL); - require_noerr(s3e = sec_sqlite3_open(db_name, &ts->s3h, create), errOut); - - s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), - SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL); - if (create && s3e == SQLITE_ERROR) { - /* sqlite3_prepare returns SQLITE_ERROR if the table we are - compiling this statement for doesn't exist. */ - char *errmsg = NULL; - s3e = sqlite3_exec(ts->s3h, - "CREATE TABLE tsettings(" - "sha1 BLOB NOT NULL DEFAULT ''," - "subj BLOB NOT NULL DEFAULT ''," - "tset BLOB," - "data BLOB," - "PRIMARY KEY(sha1)" - ");" - "CREATE INDEX isubj ON tsettings(subj);" - , NULL, NULL, &errmsg); - if (errmsg) { - secwarning("CREATE TABLE cert: %s", errmsg); - sqlite3_free(errmsg); - } - require_noerr(s3e, errOut); - s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), - SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL); - } - require_noerr(s3e, errOut); - require_noerr(s3e = sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT, - &ts->contains, NULL), errOut); - - if (SecTrustStoreCountAll(ts) == 0) { - ts->containsSettings = false; - } else { - /* In the error case where SecTrustStoreCountAll returns a negative result, - * we'll pretend there are contents in the trust store so that we still do - * DB operations */ - ts->containsSettings = true; - } - - - return ts; - -errOut: - if (ts) { - sqlite3_close(ts->s3h); - dispatch_release_safe(ts->queue); - free(ts); - } - secerror("Failed to create trust store database: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationCreate, TAFatalError, s3e); - - return NULL; -} - -static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file, UInt8 *buffer, CFIndex maxBufLen) -{ - bool translated = false; - CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(file); - - if (fileURL && CFURLGetFileSystemRepresentation(fileURL, false, buffer, maxBufLen)) - translated = true; - CFReleaseSafe(fileURL); - - return translated; -} - -static void SecTrustStoreInitUser(void) { - const char path[MAXPATHLEN]; - - if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName, (UInt8*) path, (CFIndex) sizeof(path))) - { - kSecTrustStoreUser = SecTrustStoreCreate(path, true); - if (kSecTrustStoreUser) - kSecTrustStoreUser->readOnly = false; - } -} - -/* AUDIT[securityd](done): - domainName (ok) is a caller provided string of any length (might be 0), only - its cf type has been checked. - */ -SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) { - if (CFEqual(CFSTR("user"), domainName)) { - dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); }); - return kSecTrustStoreUser; - } else { - SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName); - return NULL; - } -} - -/* AUDIT[securityd](done): - ts (ok) might be NULL. - certificate (ok) is a valid SecCertificateRef. - trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either - NULL, a dictionary or an array, but its contents have not been checked. - */ -bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, - SecCertificateRef certificate, - CFTypeRef tsdoa, CFErrorRef *error) { - __block bool ok; - require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("truststore is NULL"))); - require_action_quiet(!ts->readOnly, errOutNotLocked, ok = SecError(errSecReadOnly, error, CFSTR("truststore is readOnly"))); - dispatch_sync(ts->queue, ^{ - CFTypeRef trustSettingsDictOrArray = tsdoa; - sqlite3_stmt *insert = NULL; - CFDataRef xmlData = NULL; - CFArrayRef array = NULL; - - CFDataRef subject; - require_action_quiet(subject = SecCertificateGetNormalizedSubjectContent(certificate), - errOut, ok = SecError(errSecParam, error, CFSTR("get normalized subject failed"))); - CFDataRef digest; - require_action_quiet(digest = SecCertificateGetSHA1Digest(certificate), errOut, ok = SecError(errSecParam, error, CFSTR("get sha1 digest failed"))); - - /* Do some basic checks on the trust settings passed in. */ - if (trustSettingsDictOrArray == NULL) { - require_action_quiet(array = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), errOut, ok = SecError(errSecAllocate, error, CFSTR("CFArrayCreate failed"))); - trustSettingsDictOrArray = array; - } - else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) { - /* array-ize it */ - array = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1, - &kCFTypeArrayCallBacks); - trustSettingsDictOrArray = array; - } - else { - require_action_quiet(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID(), errOut, ok = SecError(errSecParam, error, CFSTR("trustSettingsDictOrArray neither dict nor array"))); - } - - require_action_quiet(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault, - trustSettingsDictOrArray), errOut, ok = SecError(errSecParam, error, CFSTR("xml encode failed"))); - - int s3e = sqlite3_exec(ts->s3h, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL); - require_action_quiet(s3e == SQLITE_OK, errOut, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - - /* Parameter order is sha1,subj,tset,data. */ - require_noerr_action_quiet(s3e = sqlite3_prepare_v2(ts->s3h, insertSQL, sizeof(insertSQL), - &insert, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 1, - CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), - errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 2, - CFDataGetBytePtr(subject), CFDataGetLength(subject), - SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 3, - CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), - SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 4, - SecCertificateGetBytePtr(certificate), - SecCertificateGetLength(certificate), SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - s3e = sqlite3_step(insert); - if (s3e == SQLITE_DONE) { - /* Great the insert worked. */ - ok = true; - ts->containsSettings = true; - } else { - require_noerr_action_quiet(s3e, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); - ok = true; - } - - errOutSql: - if (insert) { - s3e = sqlite3_finalize(insert); - } - - if (ok && s3e == SQLITE_OK) { - s3e = sqlite3_exec(ts->s3h, "COMMIT TRANSACTION", NULL, NULL, NULL); - } - - if (!ok || s3e != SQLITE_OK) { - secerror("Failed to update trust store: (%d) %@", s3e, error ? *error : NULL); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); - sqlite3_exec(ts->s3h, "ROLLBACK TRANSACTION", NULL, NULL, NULL); - if (ok) { - ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e); - } - } - - errOut: - CFReleaseSafe(xmlData); - CFReleaseSafe(array); - }); -errOutNotLocked: - return ok; -} - -/* AUDIT[securityd](done): - ts (ok) might be NULL. - digest (ok) is a data of any length (might be 0). - */ -bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts, - CFDataRef digest, CFErrorRef *error) { - require_quiet(ts, errOutNotLocked); - require(!ts->readOnly, errOutNotLocked); - dispatch_sync(ts->queue, ^{ - int s3e = SQLITE_OK; - sqlite3_stmt *deleteStmt = NULL; - - require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, deleteSQL, sizeof(deleteSQL), - &deleteStmt, NULL), errOut); - require_noerr(s3e = sqlite3_bind_blob_wrapper(deleteStmt, 1, - CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), - errOut); - s3e = sqlite3_step(deleteStmt); - - errOut: - if (deleteStmt) { - verify_noerr(sqlite3_finalize(deleteStmt)); - } - if (s3e != SQLITE_OK && s3e != SQLITE_DONE) { - secerror("Removal of certificate from trust store failed: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); - } - }); -errOutNotLocked: - return true; -} - -bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error) -{ - __block bool removed_all = false; - require(ts, errOutNotLocked); - require(!ts->readOnly, errOutNotLocked); - dispatch_sync(ts->queue, ^{ - int s3e =sqlite3_exec(ts->s3h, deleteAllSQL, NULL, NULL, NULL); - if (s3e == SQLITE_OK) { - removed_all = true; - ts->containsSettings = false; - } else { - secerror("Clearing of trust store failed: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); - } - - /* prepared statements become unusable after deleteAllSQL, reset them */ - if (ts->copyParents) - sqlite3_finalize(ts->copyParents); - sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), SQLITE_PREPARE_PERSISTENT, - &ts->copyParents, NULL); - if (ts->contains) - sqlite3_finalize(ts->contains); - sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT, - &ts->contains, NULL); - }); -errOutNotLocked: - return removed_all; -} - -CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts, - SecCertificateRef certificate, CFErrorRef *error) { - __block CFMutableArrayRef parents = NULL; - require(ts, errOutNotLocked); - dispatch_sync(ts->queue, ^{ - int s3e = SQLITE_OK; - CFDataRef issuer = NULL; - require(issuer = SecCertificateGetNormalizedIssuerContent(certificate), - errOut); - require_quiet(ts->containsSettings, ok); - /* @@@ Might have to use SQLITE_TRANSIENT */ - require_noerr(s3e = sqlite3_bind_blob_wrapper(ts->copyParents, 1, - CFDataGetBytePtr(issuer), CFDataGetLength(issuer), - SQLITE_STATIC), errOut); - - require(parents = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks), errOut); - for (;;) { - s3e = sqlite3_step(ts->copyParents); - if (s3e == SQLITE_ROW) { - SecCertificateRef cert; - require(cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, - sqlite3_column_blob(ts->copyParents, 0), - sqlite3_column_bytes(ts->copyParents, 0)), errOut); - CFArrayAppendValue(parents, cert); - CFRelease(cert); - } else { - require(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut); - break; - } - } - - goto ok; - errOut: - secerror("Failed to read parents from trust store: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); - if (parents) { - CFRelease(parents); - parents = NULL; - } - ok: - verify_noerr(sqlite3_reset(ts->copyParents)); - verify_noerr(sqlite3_clear_bindings(ts->copyParents)); - }); -errOutNotLocked: - return parents; -} - -static bool SecTrustStoreQueryCertificateWithDigest(SecTrustStoreRef ts, - CFDataRef digest, bool *contains, CFArrayRef *usageConstraints, CFErrorRef *error) { - if (contains) - *contains = false; - __block bool ok = true; - require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL"))); - dispatch_sync(ts->queue, ^{ - CFDataRef xmlData = NULL; - CFPropertyListRef trustSettings = NULL; - int s3e = SQLITE_OK; - require_action_quiet(ts->containsSettings, errOut, ok = true); - require_noerr_action(s3e = sqlite3_bind_blob_wrapper(ts->contains, 1, - CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), - errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_bind_blob failed"))); - s3e = sqlite3_step(ts->contains); - if (s3e == SQLITE_ROW) { - if (contains) - *contains = true; - if (usageConstraints) { - require_action(xmlData = CFDataCreate(NULL, - sqlite3_column_blob(ts->contains, 0), - sqlite3_column_bytes(ts->contains, 0)), errOut, ok = false); - require_action(trustSettings = CFPropertyListCreateWithData(NULL, - xmlData, - kCFPropertyListImmutable, - NULL, error), errOut, ok = false); - require_action(CFGetTypeID(trustSettings) == CFArrayGetTypeID(), errOut, ok = false); - *usageConstraints = CFRetain(trustSettings); - } - } else { - require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut, - ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_step failed"))); - } - - errOut: - if (!ok) { - secerror("Failed to query for cert in trust store: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); - } - verify_noerr(sqlite3_reset(ts->contains)); - verify_noerr(sqlite3_clear_bindings(ts->contains)); - CFReleaseNull(xmlData); - CFReleaseNull(trustSettings); - }); -errOutNotLocked: - return ok; -} - -bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts, - CFDataRef digest, bool *contains, CFErrorRef *error) { - return SecTrustStoreQueryCertificateWithDigest(ts, digest, contains, NULL, error); -} - -bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, - CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error) { - return SecTrustStoreQueryCertificateWithDigest(ts, digest, NULL, usageConstraints, error); -} - -bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error) { - __block bool ok = true; - __block CFMutableArrayRef CertsAndSettings = NULL; - require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL"))); - require_action_quiet(trustStoreContents, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("trustStoreContents is NULL"))); - dispatch_sync(ts->queue, ^{ - sqlite3_stmt *copyAllStmt = NULL; - CFDataRef cert = NULL; - CFDataRef xmlData = NULL; - CFPropertyListRef trustSettings = NULL; - CFArrayRef certSettingsPair = NULL; - int s3e = SQLITE_OK; - require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, copyAllSQL, sizeof(copyAllSQL), - ©AllStmt, NULL), errOut); - require(CertsAndSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut); - for(;;) { - s3e = sqlite3_step(copyAllStmt); - if (s3e == SQLITE_ROW) { - require(cert = CFDataCreate(kCFAllocatorDefault, - sqlite3_column_blob(copyAllStmt, 0), - sqlite3_column_bytes(copyAllStmt, 0)), errOut); - require(xmlData = CFDataCreate(NULL, - sqlite3_column_blob(copyAllStmt, 1), - sqlite3_column_bytes(copyAllStmt, 1)), errOut); - require(trustSettings = CFPropertyListCreateWithData(NULL, - xmlData, - kCFPropertyListImmutable, - NULL, error), errOut); - const void *pair[] = { cert , trustSettings }; - require(certSettingsPair = CFArrayCreate(NULL, pair, 2, &kCFTypeArrayCallBacks), errOut); - CFArrayAppendValue(CertsAndSettings, certSettingsPair); - - CFReleaseNull(cert); - CFReleaseNull(xmlData); - CFReleaseNull(trustSettings); - CFReleaseNull(certSettingsPair); - } else { - require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut, ok = SecDbErrorWithStmt(s3e, copyAllStmt, error, CFSTR("sqlite3_step failed"))); - break; - } - } - goto ok; - - errOut: - secerror("Failed to query for all certs in trust store: %d", s3e); - TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); - CFReleaseNull(cert); - CFReleaseNull(xmlData); - CFReleaseNull(trustSettings); - CFReleaseNull(certSettingsPair); - ok: - if (copyAllStmt) { - verify_noerr(sqlite3_finalize(copyAllStmt)); - } - if (CertsAndSettings) { - *trustStoreContents = CertsAndSettings; - } - }); -errOutNotLocked: - return ok; -} diff --git a/OSX/sec/securityd/SecTrustStoreServer.h b/OSX/sec/securityd/SecTrustStoreServer.h deleted file mode 100644 index 41444de1..00000000 --- a/OSX/sec/securityd/SecTrustStoreServer.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecTrustStoreServer - CertificateSource API to a system root certificate store -*/ - -#ifndef _SECURITY_SECTRUSTSTORESERVER_H_ -#define _SECURITY_SECTRUSTSTORESERVER_H_ - -#include "Security/SecTrustStore.h" -#include -#include - -__BEGIN_DECLS - -SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error); - -bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, - SecCertificateRef certificate, - CFTypeRef trustSettingsDictOrArray, CFErrorRef *error); - -bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts, CFDataRef digest, CFErrorRef *error); - -bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error); - -CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts, - SecCertificateRef certificate, CFErrorRef *error); - -bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef source, CFDataRef digest, bool *contains, CFErrorRef *error); - -bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error); - -bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error); - -bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error); -CF_RETURNS_RETAINED CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error); - -__END_DECLS - -#endif /* !_SECURITY_SECTRUSTSTORESERVER_H_ */ diff --git a/OSX/sec/securityd/SecTrustStoreServer.m b/OSX/sec/securityd/SecTrustStoreServer.m deleted file mode 100644 index acb0fb48..00000000 --- a/OSX/sec/securityd/SecTrustStoreServer.m +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include -#import -#include -#include -#include -#include -#include -#include -#include -#import "OTATrustUtilities.h" -#include "SecTrustStoreServer.h" - -typedef bool(*exceptionsArrayValueChecker)(id _Nonnull obj); - -static bool checkDomainsValuesCompliance(id _Nonnull obj) { - if (![obj isKindOfClass:[NSString class]]) { - return false; - } - if (SecDNSIsTLD((__bridge CFStringRef)obj)) { - return false; - } - return true; -} - -static bool checkCAsValuesCompliance(id _Nonnull obj) { - if (![obj isKindOfClass:[NSDictionary class]]) { - return false; - } - if (2 != [(NSDictionary*)obj count]) { - return false; - } - if (nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] || - nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]) { - return false; - } - if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isKindOfClass:[NSString class]] || - ![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey] isKindOfClass:[NSData class]]) { - return false; - } - if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isEqualToString:@"sha256"]) { - return false; - } - return true; -} - -static bool checkExceptionsValues(NSString *key, id value, exceptionsArrayValueChecker checker, CFErrorRef *error) { - if (![value isKindOfClass:[NSArray class]]) { - return SecError(errSecParam, error, CFSTR("value for %@ is not an array in exceptions dictionary"), key); - } - - __block bool result = true; - [(NSArray*)value enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if (!checker(obj)) { - result = SecError(errSecParam, error, CFSTR("value %lu for %@ is not the expected type"), (unsigned long)idx, key); - *stop = true; - } - }]; - return result; -} - -static bool checkInputExceptionsAndSetAppExceptions(NSDictionary *inExceptions, NSMutableDictionary *appExceptions, CFErrorRef *error) { - __block bool result = true; - [inExceptions enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsDomainsKey]) { - if (!checkExceptionsValues(key, obj, checkDomainsValuesCompliance, error)) { - *stop = YES; - result = false; - return; - } - } else if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsCAsKey]) { - if (!checkExceptionsValues(key, obj, checkCAsValuesCompliance, error)) { - *stop = YES; - result = false; - return; - } - } else { - result = SecError(errSecParam, error, CFSTR("unknown key (%@) in exceptions dictionary"), key); - *stop = YES; - result = false; - return; - } - if ([(NSArray*)obj count] == 0) { - [appExceptions removeObjectForKey:key]; - } else { - appExceptions[key] = obj; - } - }]; - return result; -} - -static _Atomic bool gHasCTExceptions = false; -#define kSecCTExceptionsChanged "com.apple.trustd.ct.exceptions-changed" - -static NSURL *CTExceptionsFileURL() { - return CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(CFSTR("CTExceptions.plist"))); -} - -static NSDictionary *readExceptionsFromDisk(NSError **error) { - secdebug("ct", "reading CT exceptions from disk"); - NSDictionary *allExceptions = [NSDictionary dictionaryWithContentsOfURL:CTExceptionsFileURL() - error:error]; - return allExceptions; -} - -bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error) { - if (!SecOTAPKIIsSystemTrustd()) { - secerror("Unable to write CT exceptions from user agent"); - return SecError(errSecWrPerm, error, CFSTR("Unable to write CT exceptions from user agent")); - } - - if (!appID) { - secerror("application-identifier required to set exceptions"); - return SecError(errSecParam, error, CFSTR("application-identifier required to set exceptions")); - } - - @autoreleasepool { - NSError *nserror = nil; - NSMutableDictionary *allExceptions = [readExceptionsFromDisk(&nserror) mutableCopy]; - NSMutableDictionary *appExceptions = NULL; - if (allExceptions && allExceptions[(__bridge NSString*)appID]) { - appExceptions = [allExceptions[(__bridge NSString*)appID] mutableCopy]; - } else { - appExceptions = [NSMutableDictionary dictionary]; - if (!allExceptions) { - allExceptions = [NSMutableDictionary dictionary]; - } - } - - if (exceptions && (CFDictionaryGetCount(exceptions) > 0)) { - NSDictionary *inExceptions = (__bridge NSDictionary*)exceptions; - if (!checkInputExceptionsAndSetAppExceptions(inExceptions, appExceptions, error)) { - secerror("input exceptions have error: %@", error ? *error : nil); - return false; - } - } - - if (!exceptions || [appExceptions count] == 0) { - [allExceptions removeObjectForKey:(__bridge NSString*)appID]; - } else { - allExceptions[(__bridge NSString*)appID] = appExceptions; - } - - if (![allExceptions writeToURL:CTExceptionsFileURL() error:&nserror]) { - secerror("failed to write CT exceptions: %@", nserror); - if (error) { - *error = CFRetainSafe((__bridge CFErrorRef)nserror); - } - return false; - } - secnotice("ct", "wrote %lu CT exceptions", (unsigned long)[allExceptions count]); - atomic_store(&gHasCTExceptions, [allExceptions count] != 0); - notify_post(kSecCTExceptionsChanged); - return true; - } -} - -CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error) { - @autoreleasepool { - /* Set us up for not reading the disk when there are never exceptions */ - static int notify_token = 0; - int check = 0; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - /* initialize gHashCTExceptions cache */ - NSError *read_error = nil; - NSDictionary *allExceptions = readExceptionsFromDisk(&read_error); - if (!allExceptions || [allExceptions count] == 0) { - secnotice("ct", "skipping further reads. no CT exceptions found: %@", read_error); - atomic_store(&gHasCTExceptions, false); - } else { - secnotice("ct", "have CT exceptions. will need to read."); - atomic_store(&gHasCTExceptions, true); - } - - /* read-only trustds register for notfications from the read-write trustd */ - if (!SecOTAPKIIsSystemTrustd()) { - uint32_t status = notify_register_check(kSecCTExceptionsChanged, ¬ify_token); - if (status == NOTIFY_STATUS_OK) { - status = notify_check(notify_token, NULL); - } - if (status != NOTIFY_STATUS_OK) { - secerror("failed to establish notification for CT exceptions: %ud", status); - notify_cancel(notify_token); - notify_token = 0; - } - } - }); - - /* Read the negative cached value as to whether there are any exceptions to read */ - if (!SecOTAPKIIsSystemTrustd()) { - /* Check whether we got a notification. If we didn't, and there are no exceptions set, return NULL. - * Otherwise, we need to read from disk */ - uint32_t check_status = notify_check(notify_token, &check); - if (check_status == NOTIFY_STATUS_OK && check == 0 && !atomic_load(&gHasCTExceptions)) { - return NULL; - } - } else if (!atomic_load(&gHasCTExceptions)) { - return NULL; - } - - /* We need to read the exceptions from disk */ - NSError *read_error = nil; - NSDictionary *allExceptions = readExceptionsFromDisk(&read_error); - if (!allExceptions || [allExceptions count] == 0) { - secnotice("ct", "skipping further reads. no CT exceptions found: %@", read_error); - atomic_store(&gHasCTExceptions, false); - return NULL; - } - - /* If the caller specified an appID, return only the exceptions for that appID */ - if (appID) { - return CFBridgingRetain(allExceptions[(__bridge NSString*)appID]); - } - - /* Otherwise, combine all the exceptions into one array */ - NSMutableArray *domainExceptions = [NSMutableArray array]; - NSMutableArray *caExceptions = [NSMutableArray array]; - [allExceptions enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull __unused key, NSDictionary * _Nonnull appExceptions, - BOOL * _Nonnull __unused stop) { - if (appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] && - checkExceptionsValues((__bridge NSString*)kSecCTExceptionsDomainsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey], - checkDomainsValuesCompliance, error)) { - [domainExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey]]; - } - if (appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] && - checkExceptionsValues((__bridge NSString*)kSecCTExceptionsCAsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey], - checkCAsValuesCompliance, error)) { - [caExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey]]; - } - }]; - NSMutableDictionary *exceptions = [NSMutableDictionary dictionaryWithCapacity:2]; - if ([domainExceptions count] > 0) { - exceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] = domainExceptions; - } - if ([caExceptions count] > 0) { - exceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] = caExceptions; - } - if ([exceptions count] > 0) { - secdebug("ct", "found %lu CT exceptions on disk", (unsigned long)[exceptions count]); - atomic_store(&gHasCTExceptions, true); - return CFBridgingRetain(exceptions); - } - return NULL; - } -} diff --git a/OSX/sec/securityd/TrustURLSessionDelegate.h b/OSX/sec/securityd/TrustURLSessionDelegate.h deleted file mode 100644 index ff9d4a02..00000000 --- a/OSX/sec/securityd/TrustURLSessionDelegate.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -#ifndef _SECURITY_TRUSTURLSESSIONDELEGATE_H_ -#define _SECURITY_TRUSTURLSESSIONDELEGATE_H_ - -#if __OBJC__ -#include - -NS_ASSUME_NONNULL_BEGIN -/* This is our abstract NSURLSessionDelegate that handles the elements common to - * fetching data over the network during a trust evaluation */ -@interface TrustURLSessionDelegate : NSObject -@property (assign, nullable) void *context; -@property NSArray *URIs; -@property NSUInteger URIix; -@property (nullable) NSMutableData *response; -@property NSTimeInterval expiration; -@property NSUInteger numTasks; - -- (BOOL)fetchNext:(NSURLSession *)session; -- (NSURLRequest *)createNextRequest:(NSURL *)uri; -@end - -NSTimeInterval TrustURLSessionGetResourceTimeout(void); - -NS_ASSUME_NONNULL_END -#endif // __OBJC__ - -#endif /* _SECURITY_TRUSTURLSESSIONDELEGATE_H_ */ diff --git a/OSX/sec/securityd/TrustURLSessionDelegate.m b/OSX/sec/securityd/TrustURLSessionDelegate.m deleted file mode 100644 index 6698130a..00000000 --- a/OSX/sec/securityd/TrustURLSessionDelegate.m +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -#import -#import -#include -#include -#include -#include "TrustURLSessionDelegate.h" - -#define MAX_TASKS 3 - -/* There has got to be an easier way to do this. For now we based this code - on CFNetwork/Connection/URLResponse.cpp. */ -static CFStringRef copyParseMaxAge(CFStringRef cacheControlHeader) { - if (!cacheControlHeader) { return NULL; } - - /* The format of the cache control header is a comma-separated list, but - each list element could be a key-value pair, with the value quoted and - possibly containing a comma. */ - CFStringInlineBuffer inlineBuf = {}; - CFRange componentRange; - CFIndex length = CFStringGetLength(cacheControlHeader); - bool done = false; - CFCharacterSetRef whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace); - CFStringRef maxAgeValue = NULL; - - CFStringInitInlineBuffer(cacheControlHeader, &inlineBuf, CFRangeMake(0, length)); - componentRange.location = 0; - - while (!done) { - bool inQuotes = false; - bool foundComponentStart = false; - CFIndex charIndex = componentRange.location; - CFIndex componentEnd = -1; - CFRange maxAgeRg; - componentRange.length = 0; - - while (charIndex < length) { - UniChar ch = CFStringGetCharacterFromInlineBuffer(&inlineBuf, charIndex); - if (!inQuotes && ch == ',') { - componentRange.length = charIndex - componentRange.location; - break; - } - if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { - if (!foundComponentStart) { - foundComponentStart = true; - componentRange.location = charIndex; - } else { - componentEnd = charIndex; - } - if (ch == '\"') { - inQuotes = (inQuotes == false); - } - } - charIndex ++; - } - - if (componentEnd == -1) { - componentRange.length = charIndex - componentRange.location; - } else { - componentRange.length = componentEnd - componentRange.location + 1; - } - - if (charIndex == length) { - /* Fell off the end; this is the last component. */ - done = true; - } - - /* componentRange should now contain the range of the current - component; trimmed of any whitespace. */ - - /* We want to look for a max-age value. */ - if (!maxAgeValue && CFStringFindWithOptions(cacheControlHeader, CFSTR("max-age"), componentRange, kCFCompareCaseInsensitive | kCFCompareAnchored, &maxAgeRg)) { - CFIndex equalIdx; - CFIndex maxCompRg = componentRange.location + componentRange.length; - for (equalIdx = maxAgeRg.location + maxAgeRg.length; equalIdx < maxCompRg; equalIdx ++) { - UniChar equalCh = CFStringGetCharacterFromInlineBuffer(&inlineBuf, equalIdx); - if (equalCh == '=') { - // Parse out max-age value - equalIdx ++; - while (equalIdx < maxCompRg && CFCharacterSetIsCharacterMember(whitespaceSet, CFStringGetCharacterAtIndex(cacheControlHeader, equalIdx))) { - equalIdx ++; - } - if (equalIdx < maxCompRg) { - CFReleaseNull(maxAgeValue); - maxAgeValue = CFStringCreateWithSubstring(kCFAllocatorDefault, cacheControlHeader, CFRangeMake(equalIdx, maxCompRg-equalIdx)); - } - } else if (!CFCharacterSetIsCharacterMember(whitespaceSet, equalCh)) { - // Not a valid max-age header; break out doing nothing - break; - } - } - } - - if (!done && maxAgeValue) { - done = true; - } - if (!done) { - /* Advance to the next component; + 1 to get past the comma. */ - componentRange.location = charIndex + 1; - } - } - - return maxAgeValue; -} - -@implementation TrustURLSessionDelegate -- (id)init { - /* Protect future developers from themselves */ - if ([self class] == [TrustURLSessionDelegate class]) { - NSException *e = [NSException exceptionWithName:@"AbstractClassException" - reason:@"This is an abstract class. To use it, please subclass." - userInfo:nil]; - @throw e; - } else { - return [super init]; - } -} - -- (NSURLRequest *)createNextRequest:(NSURL *)uri { - return [NSURLRequest requestWithURL:uri]; -} - -- (BOOL)fetchNext:(NSURLSession *)session { - if (self.numTasks >= MAX_TASKS) { - secnotice("http", "Too many fetch %@ requests for this cert", [self class]); - return true; - } - - for (NSUInteger ix = self.URIix; ix < [self.URIs count]; ix++) { - NSURL *uri = self.URIs[ix]; - if ([[uri scheme] isEqualToString:@"http"]) { - self.URIix = ix + 1; // Next time we'll start with the next index - self.numTasks++; - NSURLSessionTask *task = [session dataTaskWithRequest:[self createNextRequest:uri]]; - [task resume]; - secinfo("http", "request for uri: %@", uri); - return false; // we scheduled a job - } else { - secnotice("http", "skipping unsupported scheme %@", [uri scheme]); - } - } - - /* No more issuers left to try, we're done. Report that no async jobs were started. */ - secdebug("http", "no request issued"); - return true; -} - -- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { - /* Append the data to the response data*/ - if (!_response) { - _response = [NSMutableData data]; - } - [_response appendData:data]; -} - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - /* Protect future developers from themselves */ - if ([self class] == [TrustURLSessionDelegate class]) { - NSException *e = [NSException exceptionWithName:@"AbstractClassException" - reason:@"This is an abstract class. To use it, please subclass and override didCompleteWithError." - userInfo:nil]; - @throw e; - } else { - _expiration = 60.0 * 60.0 * 24.0 * 7; /* Default is 7 days */ - if ([_response length] > 0 && [[task response] isKindOfClass:[NSHTTPURLResponse class]]) { - NSString *cacheControl = [[(NSHTTPURLResponse *)[task response] allHeaderFields] objectForKey:@"cache-control"]; - NSString *maxAge = CFBridgingRelease(copyParseMaxAge((__bridge CFStringRef)cacheControl)); - if (maxAge && [maxAge doubleValue] > _expiration) { - _expiration = [maxAge doubleValue]; - } - } - } -} - -- (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task -willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse - newRequest:(NSURLRequest *)request - completionHandler:(void (^)(NSURLRequest *))completionHandler { - /* The old code didn't allow re-direction, so we won't either. */ - secnotice("http", "failed redirection for %@", task.originalRequest.URL); - [task cancel]; -} -@end - -NSTimeInterval TrustURLSessionGetResourceTimeout(void) { - return (NSTimeInterval)3.0; -} diff --git a/OSX/sec/securityd/com.apple.secd.sb b/OSX/sec/securityd/com.apple.secd.sb deleted file mode 100644 index fd9e6476..00000000 --- a/OSX/sec/securityd/com.apple.secd.sb +++ /dev/null @@ -1,86 +0,0 @@ -(version 1) - -(deny default) - -(import "system.sb") - -(allow file-read* file-write* - (subpath "/private/var/db/mds") - (regex #"^/private/var/folders/[^/]+/[^/]+/T(/|$)") - (regex (string-append "^" (regex-quote (param "_HOME")) #"/Library/Keychains(/|$)"))) - -(allow file-read* - (literal (string-append (param "_HOME") "/Library/Preferences/com.apple.imessage.bag.plist")) - (literal (string-append (param "_HOME") "/Library/Preferences/com.apple.facetime.bag.plist"))) - - -;;;;;; will be fully fixed in 29465717 -(allow file-read* (subpath "/")) - -(allow user-preference-read - (preference-domain ".GlobalPreferences")) -(allow user-preference-read - (preference-domain "com.apple.security")) -(allow user-preference-read - (preference-domain "com.apple.imessage.bag")) -(allow user-preference-read - (preference-domain "com.apple.facetime.bag")) -(allow user-preference-read user-preference-write - (preference-domain "com.apple.security.sosaccount")) - -(allow distributed-notification-post) - -(allow iokit-open - (iokit-user-client-class "AppleKeyStoreUserClient") - (iokit-user-client-class "AppleAPFSUserClient") - (iokit-user-client-class "RootDomainUserClient")) - - -(allow file-read* - (literal "/usr/libexec/secd") - (literal "/Library/Preferences/com.apple.security.plist") - (literal "/Library/Preferences/.GlobalPreferences.plist") - (literal "/AppleInternal") - (literal "/usr/libexec")) - -(allow mach-lookup - (global-name "com.apple.system.opendirectoryd.api") - (global-name "com.apple.SystemConfiguration.configd") - (global-name "com.apple.security.cloudkeychainproxy3") - (global-name "com.apple.accountsd.accountmanager") - (global-name "com.apple.CoreServices.coreservicesd") - (global-name "com.apple.distributed_notifications@Uv3") - (global-name "com.apple.ak.auth.xpc") - (global-name "com.apple.cdp.daemon") - (global-name "com.apple.cloudd") - (global-name "com.apple.apsd") - (global-name "com.apple.analyticsd") - (global-name "com.apple.ak.anisette.xpc") - (global-name "com.apple.corefollowup.agent") - (global-name "com.apple.windowserver.active") - (global-name "com.apple.powerlog.plxpclogger.xpc") - (global-name "com.apple.SecureBackupDaemon") -) - -;; Used to send logs for MoiC. -(allow mach-lookup - (global-name "com.apple.imagent.desktop.auth")) - -(allow iokit-get-properties (iokit-registry-entry-class "IOPlatformExpertDevice")) - -(allow ipc-posix-shm - (ipc-posix-name "com.apple.AppleDatabaseChanged")) - -(allow network-outbound) -(allow system-socket) - -;; to be deleted once SecTrustEvaluate and SecTrustCopyKey can avoid touching legacy cert and keychain stack -(allow file-read* file-write* - (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsDirectory\.db$") - (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsObject\.db$") - (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mds\.lock$")) -(allow mach-lookup - (global-name "com.apple.SecurityServer")) - -(allow system-fsctl (fsctl-command afpfsByteRangeLock2FSCTL)) - diff --git a/OSX/sec/securityd/entitlements.plist b/OSX/sec/securityd/entitlements.plist deleted file mode 100644 index 5f8eecff..00000000 --- a/OSX/sec/securityd/entitlements.plist +++ /dev/null @@ -1,94 +0,0 @@ - - - - - com.apple.private.dark-wake-push - - com.apple.private.accounts.allaccounts - - com.apple.private.aps-connection-initiate - - aps-connection-initiate - - com.apple.developer.aps-environment - serverPreferred - aps-environment - serverPreferred - com.apple.aps-environment - serverPreferred - com.apple.private.cloudkit.setEnvironment - - com.apple.developer.icloud-container-identifiers - - iCloud.com.apple.security.keychain - - com.apple.developer.icloud-services - - CloudKit - - com.apple.developer.icloud-container-environment - Production - com.apple.private.cloudkit.systemService - - com.apple.private.cloudkit.buddyAccess - - com.apple.private.cloudkit.allowUnverifiedAccount - - com.apple.private.cloudkit.supportservice - - com.apple.private.appleaccount.app-hidden-from-icloud-settings - - com.apple.private.tcc.allow - - kTCCServiceLiverpool - - com.apple.application-identifier - com.apple.securityd - application-identifier - com.apple.securityd - com.apple.keystore.access-keychain-keys - - com.apple.keystore.lockassertion - - com.apple.private.associated-domains - - com.apple.private.necp.match - - com.apple.private.network.socket-delegate - - com.apple.mkb.usersession.info - - com.apple.private.applecredentialmanager.allow - - com.apple.private.imcore.imagent - - com.apple.private.MobileGestalt.AllowedProtectedKeys - - SerialNumber - - seatbelt-profiles - - securityd - - com.apple.private.sqlite.sqlite-encryption - - com.apple.accounts.appleaccount.fullaccess - - com.apple.authkit.client.private - - com.apple.private.trustedpeershelper.client - - com.apple.private.imcore.imremoteurlconnection - - com.apple.private.ids.remoteurlconnection - - com.apple.private.imcore.remoteurlconnection - - com.apple.securebackupd.access - - com.apple.CloudKeychainProxy.client - - com.apple.security.network.client - - - diff --git a/OSX/sec/securityd/iCloudTrace.c b/OSX/sec/securityd/iCloudTrace.c deleted file mode 100644 index 6ac75cfd..00000000 --- a/OSX/sec/securityd/iCloudTrace.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "iCloudTrace.h" -#include -#include -#include -#include -#include -#include -#include -#if TARGET_OS_OSX -#include -#endif -#include -#include - diff --git a/OSX/sec/securityd/iCloudTrace.h b/OSX/sec/securityd/iCloudTrace.h deleted file mode 100644 index 594a5b87..00000000 --- a/OSX/sec/securityd/iCloudTrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef sec_iCloudTrace_h -#define sec_iCloudTrace_h -#include - -#endif diff --git a/OSX/sec/securityd/nameconstraints.c b/OSX/sec/securityd/nameconstraints.c deleted file mode 100644 index e025fd64..00000000 --- a/OSX/sec/securityd/nameconstraints.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * nameconstraints.c - rfc5280 section 4.2.1.10 and later name constraints implementation. - */ - -#include "nameconstraints.h" -#include -#include -#include -#include -#include -#include - -/* RFC 5280 Section 4.2.1.10: - DNS name restrictions are expressed as host.example.com. Any DNS - name that can be constructed by simply adding zero or more labels to - the left-hand side of the name satisfies the name constraint. For - example, www.host.example.com would satisfy the constraint but - host1.example.com would not. -*/ -static bool SecDNSNameConstraintsMatch(CFStringRef DNSName, CFStringRef constraint) { - CFIndex clength = CFStringGetLength(constraint); - CFIndex dlength = CFStringGetLength(DNSName); - - if (dlength < clength) return false; - - /* Ensure that character to the left of the constraint in the DNSName is a '.' - so that badexample.com does not match example.com, but good.example.com does. - */ - if ((dlength != clength) && ('.' != CFStringGetCharacterAtIndex(constraint, 0)) && - ('.' != CFStringGetCharacterAtIndex(DNSName, dlength - clength -1))) { - return false; - } - - CFRange compareRange = { dlength - clength, clength}; - - if (!CFStringCompareWithOptions(DNSName, constraint, compareRange, kCFCompareCaseInsensitive)) { - return true; - } - - return false; -} - -/* RFC 5280 Section 4.2.1.10: - For URIs, the constraint applies to the host part of the name. The - constraint MUST be specified as a fully qualified domain name and MAY - specify a host or a domain. Examples would be "host.example.com" and - ".example.com". When the constraint begins with a period, it MAY be - expanded with one or more labels. That is, the constraint - ".example.com" is satisfied by both host.example.com and - my.host.example.com. However, the constraint ".example.com" is not - satisfied by "example.com". When the constraint does not begin with - a period, it specifies a host. - */ -static bool SecURIMatch(CFStringRef URI, CFStringRef hostname) { - bool result = false; - CFStringRef URI_hostname = NULL; - CFCharacterSetRef port_or_path_separator = NULL; - /* URI must have scheme specified */ - CFRange URI_scheme = CFStringFind(URI, CFSTR("://"), 0); - require_quiet(URI_scheme.location != kCFNotFound, out); - - /* Remove scheme prefix and port or resource path suffix */ - CFRange URI_hostname_range = { URI_scheme.location + URI_scheme.length, - CFStringGetLength(URI) - URI_scheme.location - URI_scheme.length }; - port_or_path_separator = CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault, CFSTR(":/")); - CFRange separator = {kCFNotFound, 0}; - if(CFStringFindCharacterFromSet(URI, port_or_path_separator, URI_hostname_range, 0, &separator)) { - URI_hostname_range.length -= (CFStringGetLength(URI) - separator.location); - } - URI_hostname = CFStringCreateWithSubstring(kCFAllocatorDefault, URI, URI_hostname_range); - - /* Hostname in URI must not begin with '.' */ - require_quiet('.' != CFStringGetCharacterAtIndex(URI_hostname, 0), out); - - CFIndex ulength = CFStringGetLength(URI_hostname); - CFIndex hlength = CFStringGetLength(hostname); - require_quiet(ulength >= hlength, out); - CFRange compare_range = { 0, hlength }; - - /* Allow one or more preceding labels */ - if ('.' == CFStringGetCharacterAtIndex(hostname, 0)) { - compare_range.location = ulength - hlength; - } - - if(kCFCompareEqualTo == CFStringCompareWithOptions(URI_hostname, - hostname, - compare_range, - kCFCompareCaseInsensitive)) { - result = true; - } - -out: - CFReleaseNull(port_or_path_separator); - CFReleaseNull(URI_hostname); - return result; -} - -/* RFC 5280 Section 4.2.1.10: - A name constraint for Internet mail addresses MAY specify a - particular mailbox, all addresses at a particular host, or all - mailboxes in a domain. To indicate a particular mailbox, the - constraint is the complete mail address. For example, - "root@example.com" indicates the root mailbox on the host - "example.com". To indicate all Internet mail addresses on a - particular host, the constraint is specified as the host name. For - example, the constraint "example.com" is satisfied by any mail - address at the host "example.com". To specify any address within a - domain, the constraint is specified with a leading period (as with - URIs). - */ -static bool SecRFC822NameMatch(CFStringRef emailAddress, CFStringRef constraint) { - CFRange mailbox_range = CFStringFind(constraint,CFSTR("@"),0); - - /* Constraint specifies a particular mailbox. Perform full comparison. */ - if (mailbox_range.location != kCFNotFound) { - if (!CFStringCompare(emailAddress, constraint, kCFCompareCaseInsensitive)) { - return true; - } - else return false; - } - - mailbox_range = CFStringFind(emailAddress, CFSTR("@"), 0); - require_quiet(mailbox_range.location != kCFNotFound, out); - CFRange hostname_range = {mailbox_range.location + 1, - CFStringGetLength(emailAddress) - mailbox_range.location - 1 }; - - /* Constraint specificies a particular host. Compare hostname of address. */ - if ('.' != CFStringGetCharacterAtIndex(constraint, 0)) { - if (!CFStringCompareWithOptions(emailAddress, constraint, hostname_range, kCFCompareCaseInsensitive)) { - return true; - } - else return false; - } - - /* Constraint specificies a domain. Match hostname of address to domain name. */ - require_quiet('.' != CFStringGetCharacterAtIndex(emailAddress, mailbox_range.location +1), out); - if (CFStringHasSuffix(emailAddress, constraint)) { - return true; - } - -out: - return false; -} - -static bool nc_compare_directoryNames(const DERItem *certName, const DERItem *subtreeName) { - /* Get content of certificate name and subtree name */ - DERDecodedInfo certName_content; - require_noerr_quiet(DERDecodeItem(certName, &certName_content), out); - - DERDecodedInfo subtreeName_content; - require_noerr_quiet(DERDecodeItem(subtreeName, &subtreeName_content), out); - - if (certName->length > subtreeName->length) { - if(0 == memcmp(certName_content.content.data, - subtreeName_content.content.data, - subtreeName_content.content.length)) { - return true; - } - } - -out: - return false; -} - -static bool nc_compare_DNSNames(const DERItem *certName, const DERItem *subtreeName) { - bool result = false; - CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - certName->data, certName->length, - kCFStringEncodingUTF8, FALSE); - CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - subtreeName->data, subtreeName->length, - kCFStringEncodingUTF8, FALSE); - require_quiet(certName_str, out); - require_quiet(subtreeName_str, out); - - if (SecDNSNameConstraintsMatch(certName_str, subtreeName_str)) { - result = true; - } - -out: - CFReleaseNull(certName_str) ; - CFReleaseNull(subtreeName_str); - return result; -} - -static bool nc_compare_URIs(const DERItem *certName, const DERItem *subtreeName) { - bool result = false; - CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - certName->data, certName->length, - kCFStringEncodingUTF8, FALSE); - CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - subtreeName->data, subtreeName->length, - kCFStringEncodingUTF8, FALSE); - require_quiet(certName_str, out); - require_quiet(subtreeName_str, out); - - if (SecURIMatch(certName_str, subtreeName_str)) { - result = true; - } - -out: - CFReleaseNull(certName_str); - CFReleaseNull(subtreeName_str); - return result; -} - -static bool nc_compare_RFC822Names(const DERItem *certName, const DERItem *subtreeName) { - bool result = false; - CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - certName->data, certName->length, - kCFStringEncodingUTF8, FALSE); - CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, - subtreeName->data, subtreeName->length, - kCFStringEncodingUTF8, FALSE); - require_quiet(certName_str, out); - require_quiet(subtreeName_str, out); - - if (SecRFC822NameMatch(certName_str, subtreeName_str)) { - result = true; - } - -out: - CFReleaseNull(certName_str); - CFReleaseNull(subtreeName_str); - return result; -} - -static bool nc_compare_IPAddresses(const DERItem *certAddr, const DERItem *subtreeAddr) { - bool result = false; - - /* Verify Subtree Address has correct number of bytes for IP and mask */ - require_quiet((subtreeAddr->length == 8) || (subtreeAddr->length == 32), out); - /* Verify Cert Address has correct number of bytes for IP */ - require_quiet((certAddr->length == 4) || (certAddr->length ==16), out); - /* Verify Subtree Address and Cert Address are the same version */ - require_quiet(subtreeAddr->length == 2*certAddr->length, out); - - DERByte * mask = subtreeAddr->data + certAddr->length; - for (DERSize i = 0; i < certAddr->length; i++) { - if((subtreeAddr->data[i] & mask[i]) != (certAddr->data[i] & mask[i])) { - return false; - } - } - return true; - -out: - return result; -} - -typedef struct { - bool present; - bool isMatch; -} match_t; - -typedef struct { - const SecCEGeneralNameType gnType; - const DERItem *cert_item; - match_t *match; -} nc_match_context_t; - -typedef struct { - const CFArrayRef subtrees; - match_t *match; - bool permit; -} nc_san_match_context_t; - -static OSStatus nc_compare_subtree(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { - nc_match_context_t *item_context = context; - if (item_context && gnType == item_context->gnType - && item_context->match && item_context->cert_item) { - - item_context->match->present = true; - /* - * We set isMatch such that if there are multiple subtrees of the same type, matching to any one - * of them is considered a match. - */ - switch (gnType) { - case GNT_DirectoryName: { - item_context->match->isMatch |= nc_compare_directoryNames(item_context->cert_item, generalName); - return errSecSuccess; - } - case GNT_DNSName: { - item_context->match->isMatch |= nc_compare_DNSNames(item_context->cert_item, generalName); - return errSecSuccess; - } - case GNT_URI: { - item_context->match->isMatch |= nc_compare_URIs(item_context->cert_item, generalName); - return errSecSuccess; - } - case GNT_RFC822Name: { - item_context->match->isMatch |= nc_compare_RFC822Names(item_context->cert_item, generalName); - return errSecSuccess; - } - case GNT_IPAddress: { - item_context->match->isMatch |= nc_compare_IPAddresses(item_context->cert_item, generalName); - return errSecSuccess; - } - default: { - /* If the name form is not supported, reject the certificate. */ - return errSecInvalidCertificate; - } - } - } - - return errSecInvalidCertificate; -} - -static void nc_decode_and_compare_subtree(const void *value, void *context) { - CFDataRef subtree = value; - nc_match_context_t *match_context = context; - if (subtree) { - /* convert subtree to DERItem */ - const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) }; - DERDecodedInfo general_name_content; - require_noerr_quiet(DERDecodeItem(&general_name, &general_name_content),out); - - OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, - &general_name_content.content, - match_context, - nc_compare_subtree); - if (status == errSecInvalidCertificate) { - secnotice("policy","can't parse general name or not a type we support"); - } - } -out: - return; -} - -static bool isEmptySubject(CFDataRef subject) { - const DERItem subject_der = { (unsigned char *)CFDataGetBytePtr(subject), CFDataGetLength(subject) }; - - /* Get content of certificate name */ - DERDecodedInfo subject_content; - require_noerr_quiet(DERDecodeItem(&subject_der, &subject_content), out); - if (subject_content.content.length) return false; - -out: - return true; -} - -/* - * We update match structs as follows: - * 'present' is true if there's any subtree of the same type as any Subject/SAN - * 'match' is false if the subtree(s) and Subject(s)/SAN(s) don't match. - * Note: the state of 'match' is meaningless without 'present' also being true. - */ -static void update_match(bool permit, match_t *input_match, match_t *output_match) { - if (!input_match || !output_match) { - return; - } - if (input_match->present) { - output_match->present = true; - if (permit) { - output_match->isMatch &= input_match->isMatch; - } else { - output_match->isMatch |= input_match->isMatch; - } - } -} - -static void nc_compare_RFC822Name_to_subtrees(const void *value, void *context) { - CFStringRef rfc822Name = (CFStringRef)value; - char *rfc822NameString = NULL; - nc_san_match_context_t *san_context = context; - CFArrayRef subtrees = NULL; - if (san_context) { - subtrees = san_context->subtrees; - } - if (subtrees) { - CFIndex num_trees = CFArrayGetCount(subtrees); - CFRange range = { 0, num_trees }; - match_t match = { false, false }; - rfc822NameString = CFStringToCString(rfc822Name); - if (!rfc822NameString) { return; } - const DERItem addr = { (unsigned char *)rfc822NameString, - CFStringGetLength(rfc822Name) }; - nc_match_context_t match_context = {GNT_RFC822Name, &addr, &match}; - CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &match_context); - free(rfc822NameString); - - update_match(san_context->permit, &match, san_context->match); - - } -} - -static void nc_compare_subject_to_subtrees(SecCertificateRef certificate, CFArrayRef subtrees, - bool permit, match_t *match) { - CFDataRef subject = SecCertificateCopySubjectSequence(certificate); - /* An empty subject name is considered not present */ - if (!subject || isEmptySubject(subject)) { - CFReleaseNull(subject); - return; - } - - /* Compare X.500 distinguished name constraints */ - CFIndex num_trees = CFArrayGetCount(subtrees); - CFRange range = { 0, num_trees }; - match_t x500_match = { false, false }; - const DERItem subject_der = { (unsigned char *)CFDataGetBytePtr(subject), CFDataGetLength(subject) }; - nc_match_context_t context = {GNT_DirectoryName, &subject_der, &x500_match}; - CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &context); - CFReleaseNull(subject); - update_match(permit, &x500_match, match); - - /* Compare RFC822 constraints to subject email address */ - match_t email_match = { false, permit }; - CFArrayRef rfc822Names = SecCertificateCopyRFC822NamesFromSubject(certificate); - if (rfc822Names) { - CFRange emailRange = { 0, CFArrayGetCount(rfc822Names) }; - nc_san_match_context_t emailContext = { subtrees, &email_match, permit }; - CFArrayApplyFunction(rfc822Names, emailRange, nc_compare_RFC822Name_to_subtrees, &emailContext); - } - CFReleaseNull(rfc822Names); - update_match(permit, &email_match, match); -} - -static OSStatus nc_compare_subjectAltName_to_subtrees(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { - nc_san_match_context_t *san_context = context; - CFArrayRef subtrees = NULL; - if (san_context) { - subtrees = san_context->subtrees; - } - if (subtrees) { - CFIndex num_trees = CFArrayGetCount(subtrees); - CFRange range = { 0, num_trees }; - match_t match = { false, false }; - nc_match_context_t match_context = {gnType, generalName, &match}; - CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &match_context); - - update_match(san_context->permit, &match, san_context->match); - - return errSecSuccess; - } - - return errSecInvalidCertificate; -} - -OSStatus SecNameContraintsMatchSubtrees(SecCertificateRef certificate, CFArrayRef subtrees, bool *matched, bool permit) { - CFDataRef subject = NULL; - OSStatus status = errSecSuccess; - - require_action_quiet(subject = SecCertificateCopySubjectSequence(certificate), - out, - status = errSecInvalidCertificate); - const DERItem *subjectAltNames = SecCertificateGetSubjectAltName(certificate); - - /* Reject certificates with neither Subject Name nor SubjectAltName */ - require_action_quiet(!isEmptySubject(subject) || subjectAltNames, out, status = errSecInvalidCertificate); - - /* Verify that the subject name is within all of the subtrees */ - match_t subject_match = { false, permit }; - nc_compare_subject_to_subtrees(certificate, subtrees, permit, &subject_match); - - /* permit tells us whether to start with true or false. If we are looking at permitted - * subtrees, we are going to "and" the matching results because all present types must match - * to permit. For excluded subtrees, we are going to "or" the matching results because - * any matching present types causes exclusion. */ - match_t san_match = { false, permit }; - nc_san_match_context_t san_context = {subtrees, &san_match, permit}; - - /* And verify that each of the alternative names in the subjectAltName extension (critical or non-critical) - * is within any of the subtrees for that name type. */ - if (subjectAltNames) { - status = SecCertificateParseGeneralNames(subjectAltNames, - &san_context, - nc_compare_subjectAltName_to_subtrees); - /* If failed to parse */ - require_action_quiet(status == errSecSuccess, out, *matched = false); - } - - /* If we are excluding based on the subtrees, lack of names of the - same type is not a match. But if we are permitting, it is. - */ - if (subject_match.present) { - if (san_match.present && - ((subject_match.isMatch && !san_match.isMatch) || - (!subject_match.isMatch && san_match.isMatch))) { - /* If both san and subject types are present, but don't agree on match - * we should exclude on the basis of the match and not permit on the - * basis of the failed match. */ - *matched = permit ? false : true; - } - else { - /* If san type wasn't present or both had the same result, use the - * result from matching against the subject. */ - *matched = subject_match.isMatch; - } - } - else if (san_match.present) { - *matched = san_match.isMatch; - } - else { - /* Neither subject nor san had same type as subtrees, permit and don't - * exclude the cert. */ - *matched = permit ? true : false; - } - -out: - CFReleaseNull(subject); - return status; -} - -typedef struct { - CFMutableArrayRef existing_trees; - CFMutableArrayRef trees_to_add; -} nc_intersect_context_t; - -static SecCEGeneralNameType nc_gn_type_convert (DERTag tag) { - switch (tag) { - case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: - return GNT_OtherName; - case ASN1_CONTEXT_SPECIFIC | 1: - return GNT_RFC822Name; - case ASN1_CONTEXT_SPECIFIC | 2: - return GNT_DNSName; - case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: - return GNT_X400Address; - case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: - return GNT_DirectoryName; - case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: - return GNT_EdiPartyName; - case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: - case ASN1_CONTEXT_SPECIFIC | 6: - return GNT_URI; - case ASN1_CONTEXT_SPECIFIC | 7: - return GNT_IPAddress; - case ASN1_CONTEXT_SPECIFIC | 8: - return GNT_RegisteredID; - default: - return GNT_OtherName; - } -} - -/* The recommended processing algorithm states: - * If permittedSubtrees is present in the certificate, set the permitted_subtrees state variable to the intersection - * of its previous value and the value indicated in the extension field. - * However, in practice, certs are issued with permittedSubtrees whose intersection would be the empty set. For now, - * wherever a new permittedSubtree is a subset of an existing subtree, we'll replace the existing subtree; otherwise, - * we just append the new subtree. - */ -static void nc_intersect_tree_with_subtrees (const void *value, void *context) { - CFDataRef new_subtree = value; - nc_intersect_context_t *intersect_context = context; - CFMutableArrayRef existing_subtrees = intersect_context->existing_trees; - CFMutableArrayRef trees_to_append = intersect_context->trees_to_add; - - if (!new_subtree || !existing_subtrees) return; - - /* convert new subtree to DERItem */ - const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(new_subtree), CFDataGetLength(new_subtree) }; - DERDecodedInfo general_name_content; - if(DR_Success != DERDecodeItem(&general_name, &general_name_content)) return; - - SecCEGeneralNameType gnType; - DERItem *new_subtree_item = &general_name_content.content; - - /* Attempt to intersect if one of the supported types: DirectoryName and DNSName. - * Otherwise, just append the new tree. */ - gnType = nc_gn_type_convert(general_name_content.tag); - if (!(gnType == GNT_DirectoryName || gnType == GNT_DNSName)) { - CFArrayAppendValue(trees_to_append, new_subtree); - } - - CFIndex subtreeIX; - CFIndex num_existing_subtrees = CFArrayGetCount(existing_subtrees); - match_t match = { false, false }; - nc_match_context_t match_context = { gnType, new_subtree_item, &match}; - for (subtreeIX = 0; subtreeIX < num_existing_subtrees; subtreeIX++) { - CFDataRef candidate_subtree = CFArrayGetValueAtIndex(existing_subtrees, subtreeIX); - /* Convert candidate subtree to DERItem */ - const DERItem candidate = { (unsigned char *)CFDataGetBytePtr(candidate_subtree), CFDataGetLength(candidate_subtree) }; - DERDecodedInfo candidate_content; - /* We could probably just delete any subtrees in the array that don't decode */ - if(DR_Success != DERDecodeItem(&candidate, &candidate_content)) continue; - - /* first test whether new tree matches the existing tree */ - OSStatus status = SecCertificateParseGeneralNameContentProperty(candidate_content.tag, - &candidate_content.content, - &match_context, - nc_compare_subtree); - if((status == errSecSuccess) && match.present && match.isMatch) { - break; - } - - /* then test whether existing tree matches the new tree*/ - match_t local_match = { false , false }; - nc_match_context_t local_match_context = { nc_gn_type_convert(candidate_content.tag), - &candidate_content.content, - &local_match }; - status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, - &general_name_content.content, - &local_match_context, - nc_compare_subtree); - if((status == errSecSuccess) && local_match.present && local_match.isMatch) { - break; - } - } - if (subtreeIX == num_existing_subtrees) { - /* No matches found. Append new subtree */ - CFArrayAppendValue(trees_to_append, new_subtree); - } - else if (match.present && match.isMatch) { - /* new subtree \subseteq existing subtree, replace existing tree */ - CFArraySetValueAtIndex(existing_subtrees, subtreeIX, new_subtree); - } - /* existing subtree \subset new subtree, drop the new tree so as not to broaden constraints*/ - return; - -} - -void SecNameConstraintsIntersectSubtrees(CFMutableArrayRef subtrees_state, CFArrayRef subtrees_new) { - assert(subtrees_state); - assert(subtrees_new); - - CFIndex num_new_trees = CFArrayGetCount(subtrees_new); - CFRange range = { 0, num_new_trees }; - - /* if existing subtrees state contains no subtrees, append new subtrees whole */ - if (!CFArrayGetCount(subtrees_state)) { - CFArrayAppendArray(subtrees_state, subtrees_new, range); - return; - } - - CFMutableArrayRef trees_to_append = NULL; - trees_to_append = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - nc_intersect_context_t context = { subtrees_state , trees_to_append }; - CFArrayApplyFunction(subtrees_new, range, nc_intersect_tree_with_subtrees, &context); - - /* don't append to the state until we've processed all the new trees */ - num_new_trees = CFArrayGetCount(trees_to_append); - if (trees_to_append && num_new_trees) { - range.length = num_new_trees; - CFArrayAppendArray(subtrees_state, trees_to_append, range); - } - - CFReleaseNull(trees_to_append); -} diff --git a/OSX/sec/securityd/nameconstraints.h b/OSX/sec/securityd/nameconstraints.h deleted file mode 100644 index e0311a8b..00000000 --- a/OSX/sec/securityd/nameconstraints.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header nameconstraints - The functions provided in nameconstraints.h provide an interface to - a name constraints implementation as specified in section 4.2.1.10 of rfc5280. - */ - -#ifndef _SECURITY_NAMECONSTRAINTS_H_ -#define _SECURITY_NAMECONSTRAINTS_H_ - -#include -#include -#include - -OSStatus SecNameContraintsMatchSubtrees(SecCertificateRef certificate, CFArrayRef subtrees, bool *matched, bool permit); - -void SecNameConstraintsIntersectSubtrees(CFMutableArrayRef subtrees_state, CFArrayRef subtrees_new); - -#endif /* SECURITY_NAMECONSTRAINTS_H */ diff --git a/OSX/sec/securityd/personalization.c b/OSX/sec/securityd/personalization.c deleted file mode 100644 index 05e42b9e..00000000 --- a/OSX/sec/securityd/personalization.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include "personalization.h" -#include -#include -#include -#include - diff --git a/OSX/sec/securityd/personalization.h b/OSX/sec/securityd/personalization.h deleted file mode 100644 index 6f6bf262..00000000 --- a/OSX/sec/securityd/personalization.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _SECURITY_PERSONALIZATION_H_ -#define _SECURITY_PERSONALIZATION_H_ - -#include -#include -#include - - -#endif /* _SECURITY_PERSONALIZATION_H_ */ diff --git a/OSX/sec/securityd/policytree.c b/OSX/sec/securityd/policytree.c deleted file mode 100644 index 2dacf7ef..00000000 --- a/OSX/sec/securityd/policytree.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012,2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * policytree.c - rfc5280 section 6.1.2 and later policy_tree implementation. - */ - -#include "policytree.h" -#include - -#include - -#include - -#define DUMP_POLICY_TREE 0 - -#if !defined(DUMP_POLICY_TREE) -#include -#endif - -static policy_set_t policy_set_create(const oid_t *p_oid) { - policy_set_t policy_set = - (policy_set_t)malloc(sizeof(*policy_set)); - policy_set->oid_next = NULL; - policy_set->oid = *p_oid; - secdebug("policy-set", "%p", policy_set); - return policy_set; -} - -void policy_set_add(policy_set_t *policy_set, const oid_t *p_oid) { - policy_set_t node = (policy_set_t)malloc(sizeof(*node)); - node->oid_next = *policy_set; - node->oid = *p_oid; - *policy_set = node; - secdebug("policy-set", "%p -> %p", node, node->oid_next); -} - -void policy_set_free(policy_set_t node) { - while (node) { - policy_set_t next = node->oid_next; - secdebug("policy-set", "%p -> %p", node, next); - free(node); - node = next; - } -} - -bool policy_set_contains(policy_set_t node, const oid_t *oid) { - for (; node; node = node->oid_next) { - if (oid_equal(node->oid, *oid)) - return true; - } - return false; -} - -void policy_set_intersect(policy_set_t *policy_set, policy_set_t other_set) { - bool other_has_any = policy_set_contains(other_set, &oidAnyPolicy); - if (policy_set_contains(*policy_set, &oidAnyPolicy)) { - policy_set_t node = other_set; - if (other_has_any) { - /* Both sets contain anyPolicy so the intersection is anyPolicy - plus all oids in either set. */ - while (node) { - if (!policy_set_contains(*policy_set, &node->oid)) { - policy_set_add(policy_set, &node->oid); - } - } - } else { - /* The result set contains anyPolicy and other_set doesn't. The - result set should be a copy of other_set. */ - policy_set_free(*policy_set); - *policy_set = NULL; - while (node) { - policy_set_add(policy_set, &node->oid); - } - } - } else if (!other_has_any) { - /* Neither set contains any policy oid so remove any values from the - result set that aren't in other_set. */ - policy_set_t *pnode = policy_set; - while (*pnode) { - policy_set_t node = *pnode; - if (policy_set_contains(other_set, &node->oid)) { - pnode = &node->oid_next; - } else { - *pnode = node->oid_next; - node->oid_next = NULL; - policy_set_free(node); - } - } - } -} - -policy_tree_t policy_tree_create(const oid_t *p_oid, policy_qualifier_t p_q) { - policy_tree_t node = malloc(sizeof(*node)); - memset(node, 0, sizeof(*node)); - node->valid_policy = *p_oid; - node->qualifier_set = p_q; - node->expected_policy_set = policy_set_create(p_oid); - secdebug("policy-node", "%p", node); - return node; -} - -/* Walk the nodes in a tree at depth and invoke callback for each one. */ -bool policy_tree_walk_depth(policy_tree_t root, int depth, - bool(*callback)(policy_tree_t, void *), void *ctx) { - policy_tree_t *stack = (policy_tree_t *)malloc(sizeof(policy_tree_t) * (depth + 1)); - if (!stack) { - return false; - } - int stack_ix = 0; - stack[stack_ix] = root; - policy_tree_t node; - bool match = false; - bool child_visited = false; - while (stack_ix >= 0) { - /* stack[stack_ix - 1] is the parent of the current node. */ - node = stack[stack_ix]; - policy_tree_t child = node->children; - if (!child_visited && stack_ix < depth && child ) { - /* If we have a child and we haven't reached the - required depth yet, we go depth first and proccess it. */ - stack[++stack_ix] = child; - } else { - /* Get the sibling now in case we delete the node in the callback */ - policy_tree_t sibling = node->siblings; - if (stack_ix == depth) { - /* Proccess node. */ - match |= callback(node, ctx); - } - - /* Move on to sibling of node. */ - if (sibling) { - /* Replace current node with it's sibling. */ - stack[stack_ix] = sibling; - child_visited = false; - } else { - /* No more siblings left, so pop the stack and backtrack. */ - stack_ix--; - /* We've handled the top of the stack's child already so - just look at it's siblings. */ - child_visited = true; - } - } - } - free(stack); - return match; -} - -static void policy_tree_free_node(policy_tree_t node) { - secdebug("policy-node", "%p children: %p siblngs: %p", node, - node->children, node->siblings); - if (node->expected_policy_set) { - policy_set_free(node->expected_policy_set); - node->expected_policy_set = NULL; - } - free(node); -} - -void policy_tree_remove_node(policy_tree_t *node) { - /* Free node's children */ - policy_tree_t *child = &(*node)->children; - if (*child) - policy_tree_prune(child); - - /* Remove node from parent */ - policy_tree_t parent = (*node)->parent; - parent->children = (*node)->siblings; - - /* Free node */ - policy_tree_free_node(*node); - *node = NULL; -} - -/* Prune nodes from node down. */ -void policy_tree_prune(policy_tree_t *node) { - /* Free all our children and siblings. */ - policy_tree_t *child = &(*node)->children; - if (*child) - policy_tree_prune(child); - policy_tree_t *sibling = &(*node)->siblings; - if (*sibling) - policy_tree_prune(sibling); - policy_tree_free_node(*node); - *node = NULL; -} - -/* Prune childless nodes at depth. */ -void policy_tree_prune_childless(policy_tree_t *root, int depth) { - policy_tree_t *stack[depth + 1]; - int stack_ix = 0; - stack[stack_ix] = root; - bool child_visited = false; - while (stack_ix >= 0) { - policy_tree_t *node; - node = stack[stack_ix]; - policy_tree_t *child = &(*node)->children; - if (!child_visited && stack_ix < depth && *child) { - /* If we have a child and we haven't reached the - required depth yet, we go depth first and proccess it. */ - stack[++stack_ix] = child; - } else if (!*child) { - /* Childless node found, nuke it. */ -#if !defined(DUMP_POLICY_TREE) - printf("# prune /<%.08lx<\\ |%.08lx| >%.08lx> :%s: depth %d\n", - (intptr_t)node, (intptr_t)*node, (intptr_t)(*node)->siblings, - (child_visited ? "v" : " "), stack_ix); -#endif - - policy_tree_t next = (*node)->siblings; - (*node)->siblings = NULL; - policy_tree_free_node(*node); - *node = next; - if (next) { - /* stack[stack_ix] (node) already points to next now. */ - child_visited = false; - } else { - /* No more siblings left, so pop the stack and backtrack. */ - stack_ix--; - child_visited = true; - } - } else { - policy_tree_t *sibling = &(*node)->siblings; - if (*sibling) { - /* Replace current node with it's sibling. */ - stack[stack_ix] = sibling; - child_visited = false; - } else { - /* No more siblings left, so pop the stack and backtrack. */ - stack_ix--; - child_visited = true; - } - } - } -} - -/* Add a new child to the tree. */ -static void policy_tree_add_child_explicit(policy_tree_t parent, - const oid_t *p_oid, policy_qualifier_t p_q, policy_set_t p_expected) { - policy_tree_t child = malloc(sizeof(*child)); - memset(child, 0, sizeof(*child)); - child->valid_policy = *p_oid; - child->qualifier_set = p_q; - child->expected_policy_set = p_expected; - child->parent = parent; - -#if 0 - printf("# /%.08lx\\ |%.08lx| \\%.08lx/ >%.08lx> \\>%.08lx>/\n", - (intptr_t)parent, (intptr_t)child, (intptr_t)parent->children, - (intptr_t)parent->siblings, - (intptr_t)(parent->children ? parent->children->siblings : NULL)); -#endif - - /* Previous child becomes new child's first sibling. */ - child->siblings = parent->children; - /* New child becomes parent's first child. */ - parent->children = child; - - secdebug("policy-node", "%p siblngs: %p", child, child->siblings); -} - -/* Add a new child to the tree parent setting valid_policy to p_oid, - qualifier_set to p_q and expected_policy_set to a set containing - just p_oid. */ -void policy_tree_add_child(policy_tree_t parent, - const oid_t *p_oid, policy_qualifier_t p_q) { - policy_set_t policy_set = policy_set_create(p_oid); - policy_tree_add_child_explicit(parent, p_oid, p_q, policy_set); -} - -/* Add a new sibling to the tree setting valid_policy to p_oid, - qualifier set to p_q and expected_policy_set to p_expected */ -void policy_tree_add_sibling(policy_tree_t sibling, const oid_t *p_oid, - policy_qualifier_t p_q, policy_set_t p_expected) { - policy_tree_add_child_explicit(sibling->parent, p_oid, p_q, p_expected); -} - -void policy_tree_set_expected_policy(policy_tree_t node, - policy_set_t p_expected) { - if (node->expected_policy_set) - policy_set_free(node->expected_policy_set); - node->expected_policy_set = p_expected; -} - -#if !defined(DUMP_POLICY_TREE) -/* Dump a policy tree. */ -static void policy_tree_dump4(policy_tree_t node, policy_tree_t parent, - policy_tree_t prev_sibling, int depth) { - policy_tree_t child = node->children; - policy_tree_t sibling = node->siblings; - static const char *spaces = " "; - printf("# %.*s/%.08lx\\ |%.08lx| <%.08lx< >%.08lx> depth %d\n", - depth * 11, spaces, - (intptr_t)parent, (intptr_t)node, (intptr_t)prev_sibling, - (intptr_t)sibling, depth); - if (child) - policy_tree_dump4(child, node, NULL, depth + 1); - if (sibling) - policy_tree_dump4(sibling, parent, node, depth); -} -#endif /* !defined(DUMP_POLICY_TREE) */ - -void policy_tree_dump(policy_tree_t node) { -#if !defined(DUMP_POLICY_TREE) - policy_tree_dump4(node, NULL, NULL, 0); -#endif /* !defined(DUMP_POLICY_TREE) */ -} diff --git a/OSX/sec/securityd/policytree.h b/OSX/sec/securityd/policytree.h deleted file mode 100644 index bbc07ebf..00000000 --- a/OSX/sec/securityd/policytree.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header policytree - The functions provided in policytree.h provide an interface to - a policy_tree implementation as specified in section 6 of rfc5280. -*/ - -#ifndef _SECURITY_POLICYTREE_H_ -#define _SECURITY_POLICYTREE_H_ - -#include -#include -#include - -__BEGIN_DECLS - - -#define oid_equal(oid1, oid2) DEROidCompare(&oid1, &oid2) -typedef DERItem oid_t; -typedef DERItem der_t; - -typedef struct policy_set *policy_set_t; -struct policy_set { - oid_t oid; - policy_set_t oid_next; -}; - -typedef const DERItem *policy_qualifier_t; - -typedef struct policy_tree *policy_tree_t; -struct policy_tree { - oid_t valid_policy; - policy_qualifier_t qualifier_set; - policy_set_t expected_policy_set; - policy_tree_t children; - policy_tree_t siblings; - policy_tree_t parent; -}; - -void policy_set_add(policy_set_t *policy_set, const oid_t *p_oid); -void policy_set_intersect(policy_set_t *policy_set, policy_set_t other_set); -bool policy_set_contains(policy_set_t policy_set, const oid_t *oid); -void policy_set_free(policy_set_t policy_set); - -policy_tree_t policy_tree_create(const oid_t *p_oid, policy_qualifier_t p_q); - -bool policy_tree_walk_depth(policy_tree_t root, int depth, - bool(*callback)(policy_tree_t, void *), void *ctx); - -void policy_tree_remove_node(policy_tree_t *node); -void policy_tree_prune(policy_tree_t *node); -void policy_tree_prune_childless(policy_tree_t *root, int depth); -void policy_tree_add_child(policy_tree_t parent, - const oid_t *p_oid, policy_qualifier_t p_q); -void policy_tree_add_sibling(policy_tree_t sibling, const oid_t *p_oid, - policy_qualifier_t p_q, policy_set_t p_expected); -void policy_tree_set_expected_policy(policy_tree_t node, - policy_set_t p_expected); - -/* noop unless !defined NDEBUG */ -void policy_tree_dump(policy_tree_t node); - -__END_DECLS - -#endif /* !_SECURITY_POLICYTREE_H_ */ diff --git a/OSX/sec/securityd/spi.c b/OSX/sec/securityd/spi.c deleted file mode 100644 index 04fbc37a..00000000 --- a/OSX/sec/securityd/spi.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if TARGET_DARWINOS -#undef OCTAGON -#undef SECUREOBJECTSYNC -#undef SHAREDWEBCREDENTIALS -#endif - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wfour-char-constants" - -#include "securityd/spi.h" -#include "ipc/SecdWatchdog.h" -#include "ipc/server_security_helpers.h" -#include "ipc/securityd_client.h" -#include "securityd/SecItemBackupServer.h" -#include "securityd/SecItemServer.h" -#include -#include -#include -#include "securityd/SOSCloudCircleServer.h" -#include "securityd/SecOTRRemote.h" -#include "securityd/SecLogSettingsServer.h" - -#include -#include "utilities/iOSforOSX.h" -#include "utilities/SecFileLocations.h" -#include "OTATrustUtilities.h" -#include "../../trustd/trustd_spi.h" - -#pragma clang diagnostic pop - -static struct securityd securityd_spi = { - .sec_item_add = _SecItemAdd, - .sec_item_copy_matching = _SecItemCopyMatching, - .sec_item_update = _SecItemUpdate, - .sec_item_delete = _SecItemDelete, - .sec_item_delete_all = _SecItemDeleteAll, - .sec_keychain_backup = _SecServerKeychainCreateBackup, - .sec_keychain_restore = _SecServerKeychainRestore, - .sec_item_copy_parent_certificates = _SecItemCopyParentCertificates, - .sec_item_certificate_exists = _SecItemCertificateExists, - .sec_roll_keys = _SecServerRollKeysGlue, - .sec_item_update_token_items = _SecItemUpdateTokenItems, - .sec_delete_items_with_access_groups = _SecItemServerDeleteAllWithAccessGroups, -#if SHAREDWEBCREDENTIALS - .sec_add_shared_web_credential = _SecAddSharedWebCredential, - .sec_copy_shared_web_credential = _SecCopySharedWebCredential, -#endif -#if SECUREOBJECTSYNC - .sec_keychain_backup_syncable = _SecServerBackupSyncable, - .sec_keychain_restore_syncable = _SecServerRestoreSyncable, - .sec_item_backup_copy_names = SecServerItemBackupCopyNames, - .sec_item_backup_handoff_fd = SecServerItemBackupHandoffFD, - .sec_item_backup_set_confirmed_manifest = SecServerItemBackupSetConfirmedManifest, - .sec_item_backup_restore = SecServerItemBackupRestore, - .sec_otr_session_create_remote = _SecOTRSessionCreateRemote, - .sec_otr_session_process_packet_remote = _SecOTRSessionProcessPacketRemote, - .soscc_TryUserCredentials = SOSCCTryUserCredentials_Server, - .soscc_SetUserCredentials = SOSCCSetUserCredentials_Server, - .soscc_SetUserCredentialsAndDSID = SOSCCSetUserCredentialsAndDSID_Server, - .soscc_SetUserCredentialsAndDSIDWithAnalytics = SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server, - .soscc_CanAuthenticate = SOSCCCanAuthenticate_Server, - .soscc_PurgeUserCredentials = SOSCCPurgeUserCredentials_Server, - .soscc_ThisDeviceIsInCircle = SOSCCThisDeviceIsInCircle_Server, - .soscc_RequestToJoinCircle = SOSCCRequestToJoinCircle_Server, - .soscc_RequestToJoinCircleAfterRestore = SOSCCRequestToJoinCircleAfterRestore_Server, - .soscc_RequestToJoinCircleAfterRestoreWithAnalytics = SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server, - .soscc_RequestEnsureFreshParameters = SOSCCRequestEnsureFreshParameters_Server, - .soscc_GetAllTheRings = SOSCCGetAllTheRings_Server, - .soscc_ApplyToARing = SOSCCApplyToARing_Server, - .soscc_WithdrawlFromARing = SOSCCWithdrawlFromARing_Server, - .soscc_EnableRing = SOSCCEnableRing_Server, - .soscc_RingStatus = SOSCCRingStatus_Server, - .soscc_SetToNew = SOSCCAccountSetToNew_Server, - .soscc_ResetToOffering = SOSCCResetToOffering_Server, - .soscc_ResetToEmpty = SOSCCResetToEmpty_Server, - .soscc_ResetToEmptyWithAnalytics = SOSCCResetToEmptyWithAnalytics_Server, - .soscc_View = SOSCCView_Server, - .soscc_ViewSet = SOSCCViewSet_Server, - .soscc_ViewSetWithAnalytics = SOSCCViewSetWithAnalytics_Server, - .soscc_RemoveThisDeviceFromCircle = SOSCCRemoveThisDeviceFromCircle_Server, - .soscc_RemoveThisDeviceFromCircleWithAnalytics = SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server, - .soscc_RemovePeersFromCircle = SOSCCRemovePeersFromCircle_Server, - .soscc_RemovePeersFromCircleWithAnalytics = SOSCCRemovePeersFromCircleWithAnalytics_Server, - .soscc_LoggedOutOfAccount = SOSCCLoggedOutOfAccount_Server, - .soscc_BailFromCircle = SOSCCBailFromCircle_Server, - .soscc_AcceptApplicants = SOSCCAcceptApplicants_Server, - .soscc_RejectApplicants = SOSCCRejectApplicants_Server, - .soscc_CopyApplicantPeerInfo = SOSCCCopyApplicantPeerInfo_Server, - .soscc_CopyGenerationPeerInfo = SOSCCCopyGenerationPeerInfo_Server, - .soscc_CopyValidPeerPeerInfo = SOSCCCopyValidPeerPeerInfo_Server, - .soscc_ValidateUserPublic = SOSCCValidateUserPublic_Server, - .soscc_CopyNotValidPeerPeerInfo = SOSCCCopyNotValidPeerPeerInfo_Server, - .soscc_CopyRetirementPeerInfo = SOSCCCopyRetirementPeerInfo_Server, - .soscc_CopyViewUnawarePeerInfo = SOSCCCopyViewUnawarePeerInfo_Server, - .soscc_CopyEngineState = SOSCCCopyEngineState_Server, - .soscc_CopyPeerInfo = SOSCCCopyPeerPeerInfo_Server, - .soscc_CopyConcurringPeerInfo = SOSCCCopyConcurringPeerPeerInfo_Server, - .soscc_ProcessSyncWithPeers = SOSCCProcessSyncWithPeers_Server, - .soscc_ProcessSyncWithAllPeers = SOSCCProcessSyncWithAllPeers_Server, - .soscc_EnsurePeerRegistration = SOSCCProcessEnsurePeerRegistration_Server, - .sec_keychain_sync_update_message = _SecServerKeychainSyncUpdateMessage, - .sec_get_log_settings = SecCopyLogSettings_Server, - .sec_set_xpc_log_settings = SecSetXPCLogSettings_Server, - .sec_set_circle_log_settings = SecSetCircleLogSettings_Server, - .soscc_CopyMyPeerInfo = SOSCCCopyMyPeerInfo_Server, - .soscc_SetLastDepartureReason = SOSCCSetLastDepartureReason_Server, - .soscc_SetNewPublicBackupKey = SOSCCSetNewPublicBackupKey_Server, - .soscc_RegisterSingleRecoverySecret = SOSCCRegisterSingleRecoverySecret_Server, - .soscc_WaitForInitialSync = SOSCCWaitForInitialSync_Server, - .soscc_WaitForInitialSyncWithAnalytics = SOSCCWaitForInitialSyncWithAnalytics_Server, - .soscc_CopyYetToSyncViewsList = SOSCCCopyYetToSyncViewsList_Server, - .soscc_SetEscrowRecords = SOSCCSetEscrowRecord_Server, - .soscc_CopyEscrowRecords = SOSCCCopyEscrowRecord_Server, - .sosbskb_WrapToBackupSliceKeyBagForView = SOSWrapToBackupSliceKeyBagForView_Server, - .soscc_CopyAccountState = SOSCCCopyAccountState_Server, - .soscc_DeleteAccountState = SOSCCDeleteAccountState_Server, - .soscc_CopyEngineData = SOSCCCopyEngineData_Server, - .soscc_DeleteEngineState = SOSCCDeleteEngineState_Server, - .soscc_AccountHasPublicKey = SOSCCAccountHasPublicKey_Server, - .soscc_AccountIsNew = SOSCCAccountIsNew_Server, - .soscc_IsThisDeviceLastBackup = SOSCCkSecXPCOpIsThisDeviceLastBackup_Server, - .soscc_SOSCCPeersHaveViewsEnabled = SOSCCPeersHaveViewsEnabled_Server, - .soscc_RegisterRecoveryPublicKey = SOSCCRegisterRecoveryPublicKey_Server, - .soscc_CopyRecoveryPublicKey = SOSCCCopyRecoveryPublicKey_Server, - .soscc_CopyBackupInformation = SOSCCCopyBackupInformation_Server, - .soscc_SOSCCMessageFromPeerIsPending = SOSCCMessageFromPeerIsPending_Server, - .soscc_SOSCCSendToPeerIsPending = SOSCCSendToPeerIsPending_Server, -#endif /* SECUREOBJECTSYNC */ -}; - -#if SECD_SERVER && SECUREOBJECTSYNC -static CFTypeRef -delayedSOSSharedObject(void) -{ - return SOSKeychainAccountGetSharedAccount(); -} -#endif - -void securityd_init_local_spi(void) { - gSecurityd = &securityd_spi; -#if SECD_SERVER && SECUREOBJECTSYNC - // We're the server: we need to handle this locally. Bring them up and set them in the global object. - securityd_spi.soscc_status = delayedSOSSharedObject; -#endif - // You're trying to bring up a (non-trustd) 'securityd'. Create the local handler for securityd XPCs. - securityd_spi.secd_xpc_server = SecCreateLocalCFSecuritydXPCServer(); -} - -void securityd_init_server(void) { - securityd_init_local_spi(); - - // Lazy initialization is no good; bring up the keychain on start - // If you want to not do this, you'll need to check the APSConnection Mach mailbox for messages here instead (good luck) - CFErrorRef cferror = nil; - bool keychainAlive = kc_with_dbt(false, &cferror, ^bool(SecDbConnectionRef dbt) { - secnotice("keychain", "Keychain initialized!"); - return true; - }); - if(!keychainAlive || cferror) { - secerror("Couldn't bring up keychain: %@", cferror); - } - CFReleaseNull(cferror); - - SecdLoadWatchDog(); -} - -void securityd_init(CFURLRef home_path) { - if (home_path) { - SetCustomHomeURL(home_path); - } - - securityd_init_server(); -#ifdef LIBTRUSTD - trustd_init_server(); -#endif -} diff --git a/OSX/sec/securityd/spi.h b/OSX/sec/securityd/spi.h deleted file mode 100644 index efe159fe..00000000 --- a/OSX/sec/securityd/spi.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef _SECURITYD_SPI_H_ -#define _SECURITYD_SPI_H_ - -#include "utilities/SecCFError.h" -#include -#include - -__BEGIN_DECLS - -/* Calling this function initializes the spi interface in the library to call - directly into the backend. It uses home_dir for root of files if specified. - This function only initializes the trust spi interface if libtrustd is linked - by the caller and LIBTRUSTD=1 is specified. */ -void securityd_init(CFURLRef home_dir); - -// Don't call either of these functions unless you are really securityd -void securityd_init_server(void); -void securityd_init_local_spi(void); - -__END_DECLS - -#endif /* _SECURITYD_SPI_H_ */ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer new file mode 100644 index 00000000..9e2b0a66 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/BaltimoreCyberTrustRoot.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/BaltimoreCyberTrustRoot.cer new file mode 100644 index 00000000..da96dbb2 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/BaltimoreCyberTrustRoot.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer new file mode 100644 index 00000000..7b9d9be5 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer new file mode 100644 index 00000000..b17a7614 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer differ diff --git a/OSX/trustd/com.apple.trustd.asl b/OSX/trustd/com.apple.trustd.asl deleted file mode 100644 index f1a68ebe..00000000 --- a/OSX/trustd/com.apple.trustd.asl +++ /dev/null @@ -1,4 +0,0 @@ -? [= Sender authd] claim only -* file /var/log/authd.log mode=0640 compress format=bsd rotate=seq file_max=5M all_max=20M -? [<= Level error] file /var/log/system.log -? [<= Level error] store diff --git a/OSX/trustd/iOS/AppleCorporateRootCA.cer b/OSX/trustd/iOS/AppleCorporateRootCA.cer deleted file mode 100644 index c23d1c46..00000000 Binary files a/OSX/trustd/iOS/AppleCorporateRootCA.cer and /dev/null differ diff --git a/OSX/trustd/iOS/AppleCorporateRootCA2.cer b/OSX/trustd/iOS/AppleCorporateRootCA2.cer deleted file mode 100644 index e16cc0fb..00000000 Binary files a/OSX/trustd/iOS/AppleCorporateRootCA2.cer and /dev/null differ diff --git a/OSX/trustd/iOS/com.apple.trustd.plist b/OSX/trustd/iOS/com.apple.trustd.plist deleted file mode 100644 index fa838619..00000000 --- a/OSX/trustd/iOS/com.apple.trustd.plist +++ /dev/null @@ -1,38 +0,0 @@ - - - - - EnablePressuredExit - - EnableTransactions - - EnvironmentVariables - - DEBUGSCOPE - -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well, ringSigning - WAIT4DEBUGGER - NO - - GroupName - _securityd - Label - com.apple.trustd - MachServices - - com.apple.trustd - - - ProgramArguments - - /usr/libexec/trustd - - Umask - 54 - UserName - _securityd - POSIXSpawnType - Adaptive - MinimalBootProfile - - - diff --git a/OSX/trustd/iOS/entitlements.plist b/OSX/trustd/iOS/entitlements.plist deleted file mode 100644 index dc6f6d2e..00000000 --- a/OSX/trustd/iOS/entitlements.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - application-identifier - com.apple.trustd - com.apple.application-identifier - com.apple.trustd - com.apple.private.necp.match - - com.apple.private.network.socket-delegate - - com.apple.private.network.delegation-whitelist - - com.apple.private.keychain.certificates - - com.apple.private.assets.accessible-asset-types - - com.apple.MobileAsset.PKITrustSupplementals - com.apple.MobileAsset.SecExperimentAssets - - seatbelt-profiles - - trustd - - - diff --git a/OSX/trustd/macOS/SecTrustOSXEntryPoints.h b/OSX/trustd/macOS/SecTrustOSXEntryPoints.h deleted file mode 100644 index 142b62e5..00000000 --- a/OSX/trustd/macOS/SecTrustOSXEntryPoints.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecTrustOSXEntryPoints - Interface for unified SecTrust into OS X Security - * Framework. - */ - -#ifndef _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ -#define _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ - -#include -#include - -__BEGIN_DECLS - -void SecTrustLegacySourcesListenForKeychainEvents(void); - -__END_DECLS - -#endif /* _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ */ diff --git a/OSX/trustd/macOS/com.apple.trustd.agent.plist b/OSX/trustd/macOS/com.apple.trustd.agent.plist deleted file mode 100644 index 8b315af2..00000000 --- a/OSX/trustd/macOS/com.apple.trustd.agent.plist +++ /dev/null @@ -1,39 +0,0 @@ - - - - - EnablePressuredExit - - EnableTransactions - - EnvironmentVariables - - DEBUGSCOPE - -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well - WAIT4DEBUGGER - NO - - Label - com.apple.trustd.agent - LimitLoadToSessionType - - Aqua - Background - LoginWindow - - MachServices - - com.apple.trustd.agent - - - POSIXSpawnType - Adaptive - ProgramArguments - - /usr/libexec/trustd - --agent - - Umask - 54 - - diff --git a/OSX/trustd/macOS/com.apple.trustd.plist b/OSX/trustd/macOS/com.apple.trustd.plist deleted file mode 100644 index fac729cb..00000000 --- a/OSX/trustd/macOS/com.apple.trustd.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - EnablePressuredExit - - EnableTransactions - - EnvironmentVariables - - DEBUGSCOPE - -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well - WAIT4DEBUGGER - NO - - Label - com.apple.trustd - MachServices - - com.apple.trustd - - - POSIXSpawnType - Adaptive - ProgramArguments - - /usr/libexec/trustd - - - diff --git a/OSX/trustd/macOS/com.apple.trustd.sb b/OSX/trustd/macOS/com.apple.trustd.sb deleted file mode 100644 index f13684b1..00000000 --- a/OSX/trustd/macOS/com.apple.trustd.sb +++ /dev/null @@ -1,72 +0,0 @@ -(version 1) - -(deny default) -(deny file-map-executable iokit-get-properties process-info* nvram*) -(deny dynamic-code-generation) - -(import "system.sb") -(import "com.apple.corefoundation.sb") -(corefoundation) - -(allow process-info* (target self)) - -;; For resolving symlinks, realpath(3), and equivalents. -(allow file-read-metadata) - -;; For validating the entitlements of clients (for keychain and trust settings) -;; see 31353815 -(allow process-info-codesignature) -(allow process-info-pidinfo) -(allow file-read*) - -;; ${PRODUCT_NAME}’s preference domain. -(allow user-preference-read user-preference-write - (preference-domain "com.apple.trustd")) - -;; Global and security preferences -(allow user-preference-read - (preference-domain "com.apple.security") - (preference-domain ".GlobalPreferences") - (preference-domain "com.apple.MobileAsset")) - -;; Read/write access to a temporary directory. -(allow file-read* file-write* - (subpath (param "_TMPDIR")) - (subpath (param "_DARWIN_CACHE_DIR"))) - -;; Read/write access to keychains and caches -(allow file-read* file-write* - (subpath "/private/var/db/mds/") - (subpath "/private/var/db/crls/") - (subpath "/System/Library/Security/") - (subpath "/Library/Keychains/") - (subpath "/private/var/root/Library/Caches/com.apple.nsurlsessiond/")) - -(allow file-read* - (literal "/usr/libexec") - (literal "/usr/libexec/trustd") - (literal "/Library/Preferences/com.apple.security.plist") - (regex #"/.GlobalPreferences[^/]*\.plist") - (literal "/Library/Preferences/com.apple.SoftwareUpdate.plist") - (literal "/Library/Application Support/CrashReporter/SubmitDiagInfo.domains")) - -(allow file-map-executable - (regex #"/CoreServicesInternal") - (regex #"/csparser")) - -(allow mach-lookup - (global-name "com.apple.ocspd") - (global-name "com.apple.SecurityServer") - (global-name "com.apple.SystemConfiguration.configd") - (global-name "com.apple.mobileassetd.v2") - (global-name "com.apple.securityd.xpc") - (global-name "com.apple.cfnetwork.cfnetworkagent") - (global-name "com.apple.nsurlsessiond") - (xpc-service-name "com.apple.powerlog.plxpclogger.xpc") - (global-name "com.apple.nesessionmanager.content-filter")) - -(allow ipc-posix-shm - (ipc-posix-name "com.apple.AppleDatabaseChanged")) - -(allow network-outbound) -(allow system-socket) diff --git a/OSX/trustd/macOS/entitlements.plist b/OSX/trustd/macOS/entitlements.plist deleted file mode 100644 index efa5ea47..00000000 --- a/OSX/trustd/macOS/entitlements.plist +++ /dev/null @@ -1,23 +0,0 @@ - - - - - application-identifier - com.apple.trustd - com.apple.application-identifier - com.apple.trustd - com.apple.private.necp.match - - com.apple.private.network.socket-delegate - - com.apple.private.network.delegation-whitelist - - com.apple.private.keychain.certificates - - com.apple.private.assets.accessible-asset-types - - com.apple.MobileAsset.PKITrustSupplementals - com.apple.MobileAsset.SecExperimentAssets - - - diff --git a/OSX/trustd/macOS/trustd.8 b/OSX/trustd/macOS/trustd.8 deleted file mode 100644 index 21914269..00000000 --- a/OSX/trustd/macOS/trustd.8 +++ /dev/null @@ -1,14 +0,0 @@ -.Dd Sat Jan 14 2017 \" DATE -.Dt trustd 8 \" Program name and manual section number -.Os -.Sh NAME \" Section Header - required - don't modify -.Nm trustd -.Nd Daemon and LaunchAgent that performs trust evaluations -.Sh SYNOPSIS \" Section Header - required - don't modify -.Nm -.Sh DESCRIPTION \" Section Header - required - don't modify -.Nm -provides services for evaluating trust in certificates for all processes on -the system. -.Pp -This command is not intended to be invoked directly. diff --git a/OSX/trustd/trustd-Info.plist b/OSX/trustd/trustd-Info.plist deleted file mode 100644 index 98f152cf..00000000 --- a/OSX/trustd/trustd-Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - XPC! - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSHumanReadableCopyright - Copyright © 2015-2017 Apple. All rights reserved. - XPCService - - ServiceType - System - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - - diff --git a/OSX/trustd/trustd-Prefix.pch b/OSX/trustd/trustd-Prefix.pch deleted file mode 100644 index 34946106..00000000 --- a/OSX/trustd/trustd-Prefix.pch +++ /dev/null @@ -1,14 +0,0 @@ -// -// Prefix header for all source files of the 'security.auth' target in the 'security.auth' project -// - -#include "authtypes.h" -#include "object.h" - -#include -#include -#include -#include -#include -#include -#include diff --git a/OSX/trustd/trustd.c b/OSX/trustd/trustd.c deleted file mode 100644 index 898a2c40..00000000 --- a/OSX/trustd/trustd.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if TARGET_OS_IPHONE -#include -#endif - -#if TARGET_OS_OSX -#include -#include -#include -#endif - -#include "OTATrustUtilities.h" -#include "trustd_spi.h" - -static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) { - if (!path) - return true; - __block xpc_object_t xpc_chain = NULL; - require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed"))); - CFArrayForEach(path, ^(const void *value) { - SecCertificateRef cert = (SecCertificateRef)value; - if (xpc_chain && !SecCertificateAppendToXPCArray(cert, xpc_chain, error)) { - xpc_release(xpc_chain); - xpc_chain = NULL; - } - }); - -exit: - if (!xpc_chain) - return false; - - xpc_dictionary_set_value(message, key, xpc_chain); - xpc_release(xpc_chain); - return true; -} - -static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) { - size_t length = 0; - const void *bytes = xpc_dictionary_get_data(message, key, &length); - if (bytes) { - SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length); - if (certificate) - return certificate; - SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key); - } else { - SecError(errSecParam, error, CFSTR("object for key %s missing"), key); - } - return NULL; -} - -static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { - xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); - if (!xpc_certificates) - return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key); - *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); - return *certificates; -} - -static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { - xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); - if (!xpc_certificates) { - *certificates = NULL; - return true; - } - *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); - return *certificates; -} - -static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) { - xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key); - if (!xpc_policies) { - if (policies) - *policies = NULL; - return true; - } - *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error); - return *policies != NULL; -} - -// Returns error if entitlement isn't present. -static bool -EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error) -{ - if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) { - SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement); - return false; - } - return true; -} - -static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) { - SecTrustStoreRef ts = NULL; - CFStringRef domain = SecXPCDictionaryCopyString(message, key, error); - if (domain) { - ts = SecTrustStoreForDomainName(domain, error); - CFRelease(domain); - } - return ts; -} - -static bool SecXPCTrustStoreContains(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); - if (digest) { - bool contains; - if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) { - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains); - result = true; - } - CFReleaseNull(digest); - } - } - return result; -} - -static bool SecXPCTrustStoreSetTrustSettings(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool noError = false; - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); - if (ts) { - SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error); - if (certificate) { - CFTypeRef trustSettingsDictOrArray = NULL; - if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, error)) { - bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, error); - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); - noError = true; - CFReleaseSafe(trustSettingsDictOrArray); - } - CFReleaseNull(certificate); - } - } - return noError; -} - -static bool SecXPCTrustStoreRemoveCertificate(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); - if (digest) { - bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error); - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); - CFReleaseNull(digest); - return true; - } - } - return false; -} - -static bool SecXPCTrustStoreCopyAll(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); - if (ts) { - CFArrayRef trustStoreContents = NULL; - if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) { - SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error); - CFReleaseNull(trustStoreContents); - return true; - } - } - return false; -} - -static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); - if (digest) { - CFArrayRef usageConstraints = NULL; - if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) { - SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error); - CFReleaseNull(usageConstraints); - result = true; - } - CFReleaseNull(digest); - } - } - return result; -} - -static bool SecXPC_OCSPCacheFlush(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t __unused reply, CFErrorRef *error) { - if(SecOCSPCacheFlush(error)) { - return true; - } - return false; -} - -static bool SecXPC_OTAPKI_GetCurrentTrustStoreVersion(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t reply, CFErrorRef *error) { - xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentTrustStoreVersion(error)); - return true; -} - -static bool SecXPC_OTAPKI_GetCurrentAssetVersion(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t reply, CFErrorRef *error) { - xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentAssetVersion(error)); - return true; -} - -static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType"); - CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error); - if (array) { - xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array); - xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array); - xpc_release(xpc_array); - result = true; - } - CFReleaseNull(array); - return result; -} - -static bool SecXPC_OTAPKI_GetNewAsset(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t reply, CFErrorRef *error) { - xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKISignalNewAsset(error)); - return true; -} - -static bool SecXPC_OTASecExperiment_GetNewAsset(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t reply, CFErrorRef *error) { - xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTASecExperimentGetNewAsset(error)); - return true; -} - -static bool SecXPC_OTASecExperiment_GetAsset(SecurityClient * __unused client, xpc_object_t __unused event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - CFDictionaryRef asset = SecOTASecExperimentCopyAsset(error); - if (asset) { - xpc_object_t xpc_dict = _CFXPCCreateXPCObjectFromCFObject(asset); - if (xpc_dict) { - xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dict); - xpc_release(xpc_dict); - result = true; - } - } - CFReleaseNull(asset); - return result; -} - -static bool SecXPC_OTAPKI_CopyTrustedCTLogs(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - CFDictionaryRef trustedLogs = SecOTAPKICopyCurrentTrustedCTLogs(error); - if (trustedLogs) { - xpc_object_t xpc_dictionary = _CFXPCCreateXPCObjectFromCFObject(trustedLogs); - if (xpc_dictionary) { - xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dictionary); - xpc_release(xpc_dictionary); - result = true; - } - } - CFReleaseNull(trustedLogs); - return result; -} - -static bool SecXPC_OTAPKI_CopyCTLogForKeyID(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - bool result = false; - size_t length = 0; - const void *bytes = xpc_dictionary_get_data(event, kSecXPCData, &length); - CFDataRef keyID = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull); - if (keyID) { - CFDictionaryRef logDict = SecOTAPKICopyCTLogForKeyID(keyID, error); - if (logDict) { - xpc_object_t xpc_dictionary = _CFXPCCreateXPCObjectFromCFObject(logDict); - xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dictionary); - xpc_release(xpc_dictionary); - CFReleaseNull(logDict); - result = true; - } - CFReleaseNull(keyID); - } - return result; -} - -static bool SecXPC_Networking_AnalyticsReport(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - xpc_object_t attributes = xpc_dictionary_get_dictionary(event, kSecTrustEventAttributesKey); - CFStringRef eventName = SecXPCDictionaryCopyString(event, kSecTrustEventNameKey, error); - bool result = false; - if (attributes && eventName) { - result = SecNetworkingAnalyticsReport(eventName, attributes, error); - } - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); - CFReleaseNull(eventName); - return result; -} - -static bool SecXPCTrustStoreSetCTExceptions(SecurityClient *client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - CFStringRef appID = NULL; - CFDictionaryRef exceptions = NULL; - if (!SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error) || !appID) { - /* We always want to set the app ID with the exceptions */ - appID = SecTaskCopyApplicationIdentifier(client->task); - } - (void)SecXPCDictionaryCopyDictionaryOptional(event, kSecTrustExceptionsKey, &exceptions, error); - bool result = _SecTrustStoreSetCTExceptions(appID, exceptions, error); - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); - CFReleaseNull(exceptions); - CFReleaseNull(appID); - return false; -} - -static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient * __unused client, xpc_object_t event, - xpc_object_t reply, CFErrorRef *error) { - CFStringRef appID = NULL; - (void)SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error); - CFDictionaryRef exceptions = _SecTrustStoreCopyCTExceptions(appID, error); - SecXPCDictionarySetPListOptional(reply, kSecTrustExceptionsKey, exceptions, error); - CFReleaseNull(exceptions); - CFReleaseNull(appID); - return false; -} - -#if TARGET_OS_IPHONE -static bool SecXPCTrustGetExceptionResetCount(SecurityClient * __unused client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { - uint64_t exceptionResetCount = SecTrustServerGetExceptionResetCount(error); - if (error && *error) { - return false; - } - - xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, exceptionResetCount); - return true; -} - -static bool SecXPCTrustIncrementExceptionResetCount(SecurityClient * __unused client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { - OSStatus status = errSecInternal; - bool result = SecTrustServerIncrementExceptionResetCount(error); - if (result && (!error || (error && !*error))) { - status = errSecSuccess; - } - - xpc_dictionary_set_bool(reply, kSecXPCKeyResult, status); - return result; -} -#endif - -typedef bool(*SecXPCOperationHandler)(SecurityClient *client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error); - -typedef struct { - CFStringRef entitlement; - SecXPCOperationHandler handler; -} SecXPCServerOperation; - -struct trustd_operations { - SecXPCServerOperation trust_store_contains; - SecXPCServerOperation trust_store_set_trust_settings; - SecXPCServerOperation trust_store_remove_certificate; - SecXPCServerOperation trust_store_copy_all; - SecXPCServerOperation trust_store_copy_usage_constraints; - SecXPCServerOperation ocsp_cache_flush; - SecXPCServerOperation ota_pki_trust_store_version; - SecXPCServerOperation ota_pki_asset_version; - SecXPCServerOperation ota_pki_get_escrow_certs; - SecXPCServerOperation ota_pki_get_new_asset; - SecXPCServerOperation ota_pki_copy_trusted_ct_logs; - SecXPCServerOperation ota_pki_copy_ct_log_for_keyid; - SecXPCServerOperation networking_analytics_report; - SecXPCServerOperation trust_store_set_ct_exceptions; - SecXPCServerOperation trust_store_copy_ct_exceptions; - SecXPCServerOperation ota_secexperiment_get_asset; - SecXPCServerOperation ota_secexperiment_get_new_asset; -#if TARGET_OS_IPHONE - SecXPCServerOperation trust_get_exception_reset_count; - SecXPCServerOperation trust_increment_exception_reset_count; -#endif -}; - -static struct trustd_operations trustd_ops = { - .trust_store_contains = { NULL, SecXPCTrustStoreContains }, - .trust_store_set_trust_settings = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetTrustSettings }, - .trust_store_remove_certificate = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreRemoveCertificate }, - .trust_store_copy_all = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyAll }, - .trust_store_copy_usage_constraints = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyUsageConstraints }, - .ocsp_cache_flush = { NULL, SecXPC_OCSPCacheFlush }, - .ota_pki_trust_store_version = { NULL, SecXPC_OTAPKI_GetCurrentTrustStoreVersion }, - .ota_pki_asset_version = { NULL, SecXPC_OTAPKI_GetCurrentAssetVersion }, - .ota_pki_get_escrow_certs = { NULL, SecXPC_OTAPKI_GetEscrowCertificates }, - .ota_pki_get_new_asset = { NULL, SecXPC_OTAPKI_GetNewAsset }, - .ota_secexperiment_get_new_asset = { NULL, SecXPC_OTASecExperiment_GetNewAsset }, - .ota_secexperiment_get_asset = { NULL, SecXPC_OTASecExperiment_GetAsset }, - .ota_pki_copy_trusted_ct_logs = { NULL, SecXPC_OTAPKI_CopyTrustedCTLogs }, - .ota_pki_copy_ct_log_for_keyid = { NULL, SecXPC_OTAPKI_CopyCTLogForKeyID }, - .networking_analytics_report = { NULL, SecXPC_Networking_AnalyticsReport }, - .trust_store_set_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetCTExceptions }, - .trust_store_copy_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyCTExceptions }, -#if TARGET_OS_IPHONE - .trust_get_exception_reset_count = { NULL, SecXPCTrustGetExceptionResetCount }, - .trust_increment_exception_reset_count = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustIncrementExceptionResetCount }, -#endif -}; - -static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) { - xpc_type_t type = xpc_get_type(event); - __block CFErrorRef error = NULL; - xpc_object_t xpcError = NULL; - xpc_object_t replyMessage = NULL; - CFDataRef clientAuditToken = NULL; - CFArrayRef domains = NULL; - SecurityClient client = { - .task = NULL, - .accessGroups = NULL, - .musr = NULL, - .uid = xpc_connection_get_euid(connection), - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - .canAccessNetworkExtensionAccessGroups = false, -#if TARGET_OS_IPHONE - .inMultiUser = false, -#endif - }; - - secdebug("serverxpc", "entering"); - if (type == XPC_TYPE_DICTIONARY) { - replyMessage = xpc_dictionary_create_reply(event); - - uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation); - - audit_token_t auditToken = {}; - xpc_connection_get_audit_token(connection, &auditToken); - - client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); - clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken)); - client.accessGroups = SecTaskCopyAccessGroups(client.task); - - secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation); - - if (operation == sec_trust_evaluate_id) { - CFArrayRef certificates = NULL, anchors = NULL, policies = NULL, responses = NULL, scts = NULL, trustedLogs = NULL, exceptions = NULL; - bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey); - bool keychainsAllowed = xpc_dictionary_get_bool(event, kSecTrustKeychainsAllowedKey); - double verifyTime; - if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) && - SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) && - SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) && - SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustResponsesKey, &responses, &error) && - SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustSCTsKey, &scts, &error) && - SecXPCDictionaryCopyArrayOptional(event, kSecTrustTrustedLogsKey, &trustedLogs, &error) && - SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error) && - SecXPCDictionaryCopyArrayOptional(event, kSecTrustExceptionsKey, &exceptions, &error)) { - // If we have no error yet, capture connection and reply in block and properly retain them. - xpc_retain(connection); - CFRetainSafe(client.task); - CFRetainSafe(clientAuditToken); - - // Clear replyMessage so we don't send a synchronous reply. - xpc_object_t asyncReply = replyMessage; - replyMessage = NULL; - - SecTrustServerEvaluateBlock(SecTrustServerGetWorkloop(), clientAuditToken, certificates, anchors, anchorsOnly, keychainsAllowed, policies, - responses, scts, trustedLogs, verifyTime, client.accessGroups, exceptions, - ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, - CFErrorRef replyError) { - // Send back reply now - if (replyError) { - CFRetain(replyError); - } else { - xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr); - SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) && - SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) && - SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError); - } - if (replyError) { - secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError); - xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError); - if (xpcReplyError) { - xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError); - xpc_release(xpcReplyError); - } - CFReleaseNull(replyError); - } else { - secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply); - } - - xpc_connection_send_message(connection, asyncReply); - xpc_release(asyncReply); - xpc_release(connection); - CFReleaseSafe(client.task); - CFReleaseSafe(clientAuditToken); - }); - } - CFReleaseSafe(policies); - CFReleaseSafe(anchors); - CFReleaseSafe(certificates); - CFReleaseSafe(responses); - CFReleaseSafe(scts); - CFReleaseSafe(trustedLogs); - CFReleaseSafe(exceptions); - } else { - SecXPCServerOperation *server_op = NULL; - switch (operation) { - case sec_trust_store_contains_id: - server_op = &trustd_ops.trust_store_contains; - break; - case sec_trust_store_set_trust_settings_id: - server_op = &trustd_ops.trust_store_set_trust_settings; - break; - case sec_trust_store_remove_certificate_id: - server_op = &trustd_ops.trust_store_remove_certificate; - break; - case sec_trust_store_copy_all_id: - server_op = &trustd_ops.trust_store_copy_all; - break; - case sec_trust_store_copy_usage_constraints_id: - server_op = &trustd_ops.trust_store_copy_usage_constraints; - break; - case sec_ocsp_cache_flush_id: - server_op = &trustd_ops.ocsp_cache_flush; - break; - case sec_ota_pki_trust_store_version_id: - server_op = &trustd_ops.ota_pki_trust_store_version; - break; - case sec_ota_pki_asset_version_id: - server_op = &trustd_ops.ota_pki_asset_version; - break; - case kSecXPCOpOTAGetEscrowCertificates: - server_op = &trustd_ops.ota_pki_get_escrow_certs; - break; - case kSecXPCOpOTAPKIGetNewAsset: - server_op = &trustd_ops.ota_pki_get_new_asset; - break; - case kSecXPCOpOTASecExperimentGetNewAsset: - server_op = &trustd_ops.ota_secexperiment_get_new_asset; - break; - case kSecXPCOpOTASecExperimentGetAsset: - server_op = &trustd_ops.ota_secexperiment_get_asset; - break; - case kSecXPCOpOTAPKICopyTrustedCTLogs: - server_op = &trustd_ops.ota_pki_copy_trusted_ct_logs; - break; - case kSecXPCOpOTAPKICopyCTLogForKeyID: - server_op = &trustd_ops.ota_pki_copy_ct_log_for_keyid; - break; - case kSecXPCOpNetworkingAnalyticsReport: - server_op = &trustd_ops.networking_analytics_report; - break; - case kSecXPCOpSetCTExceptions: - server_op = &trustd_ops.trust_store_set_ct_exceptions; - break; - case kSecXPCOpCopyCTExceptions: - server_op = &trustd_ops.trust_store_copy_ct_exceptions; - break; -#if TARGET_OS_IPHONE - case sec_trust_get_exception_reset_count_id: - server_op = &trustd_ops.trust_get_exception_reset_count; - break; - case sec_trust_increment_exception_reset_count_id: - server_op = &trustd_ops.trust_increment_exception_reset_count; - break; -#endif - default: - break; - } - if (server_op && server_op->handler) { - bool entitled = true; - if (server_op->entitlement) { - entitled = EntitlementPresentAndTrue(operation, client.task, server_op->entitlement, &error); - } - if (entitled) { - (void)server_op->handler(&client, event, replyMessage, &error); - } - } - } - - if (error) - { - if(SecErrorGetOSStatus(error) == errSecItemNotFound) - secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); - else if (SecErrorGetOSStatus(error) == errSecAuthNeeded) - secwarning("Authentication is needed %@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); - else - secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); - - xpcError = SecCreateXPCObjectWithCFError(error); - if (replyMessage) { - xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError); - } - } else if (replyMessage) { - secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage); - } - } else { - SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, &error, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event); - secerror("%@: returning error: %@", client.task, error); - xpcError = SecCreateXPCObjectWithCFError(error); - replyMessage = xpc_create_reply_with_format(event, "{%string: %value}", kSecXPCKeyError, xpcError); - } - - if (replyMessage) { - xpc_connection_send_message(connection, replyMessage); - xpc_release(replyMessage); - } - if (xpcError) - xpc_release(xpcError); - CFReleaseSafe(error); - CFReleaseSafe(client.accessGroups); - CFReleaseSafe(client.musr); - CFReleaseSafe(client.task); - CFReleaseSafe(domains); - CFReleaseSafe(clientAuditToken); -} - -static void trustd_xpc_init(const char *service_name) -{ - secdebug("serverxpc", "start"); - xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); - if (!listener) { - seccritical("security failed to register xpc listener for %s, exiting", service_name); - abort(); - } - - xpc_connection_set_event_handler(listener, ^(xpc_object_t connection) { - if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) { - xpc_connection_set_target_queue(connection, SecTrustServerGetWorkloop()); - xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { - if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { - trustd_xpc_dictionary_handler(connection, event); - } - }); - xpc_connection_activate(connection); - } - }); - xpc_connection_activate(listener); -} - -static void trustd_sandbox(void) { -#if TARGET_OS_OSX - char buf[PATH_MAX] = ""; - - if (!_set_user_dir_suffix("com.apple.trustd") || - confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0 || - (mkdir(buf, 0700) && errno != EEXIST)) { - secerror("failed to initialize temporary directory (%d): %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - char *tempdir = realpath(buf, NULL); - if (tempdir == NULL) { - secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0 || - (mkdir(buf, 0700) && errno != EEXIST)) { - secerror("failed to initialize cache directory (%d): %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - char *cachedir = realpath(buf, NULL); - if (cachedir == NULL) { - secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - const char *parameters[] = { - "_TMPDIR", tempdir, - "_DARWIN_CACHE_DIR", cachedir, - NULL - }; - - char *sberror = NULL; - if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED, parameters, &sberror) != 0) { - secerror("Failed to enter trustd sandbox: %{public}s", sberror); - exit(EXIT_FAILURE); - } - - free(tempdir); - free(cachedir); -#else // !TARGET_OS_OSX - char buf[PATH_MAX] = ""; - _set_user_dir_suffix("com.apple.trustd"); - confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)); -#endif // !TARGET_OS_OSX -} - -int main(int argc, char *argv[]) -{ - DisableLocalization(); - - char *wait4debugger = getenv("WAIT4DEBUGGER"); - if (wait4debugger && !strcasecmp("YES", wait4debugger)) { - seccritical("SIGSTOPing self, awaiting debugger"); - kill(getpid(), SIGSTOP); - seccritical("Again, for good luck (or bad debuggers)"); - kill(getpid(), SIGSTOP); - } - - trustd_sandbox(); - - const char *serviceName = kTrustdXPCServiceName; - if (argc > 1 && (!strcmp(argv[1], "--agent"))) { - serviceName = kTrustdAgentXPCServiceName; - } - - /* set up SQLite before some other component has a chance to create a database connection */ - _SecDbServerSetup(); - - gTrustd = &trustd_spi; - - /* Initialize static content */ - SecPolicyServerInitialize(); // set up callbacks for policy checks - SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced - SecPinningDbInitialize(); // set up the pinning database -#if TARGET_OS_OSX - SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation) -#endif - - /* We're ready now. Go. */ - trustd_xpc_init(serviceName); - dispatch_main(); -} diff --git a/OSX/trustd/trustd_spi.c b/OSX/trustd/trustd_spi.c deleted file mode 100644 index 4a9082ab..00000000 --- a/OSX/trustd/trustd_spi.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifdef LIBTRUSTD -#include - -#include "../utilities/SecFileLocations.h" - -#include "../sec/ipc/securityd_client.h" -#include "../sec/securityd/SecPolicyServer.h" -#include "../sec/securityd/SecTrustServer.h" -#include "../sec/securityd/SecTrustStoreServer.h" -#include "../sec/securityd/SecOCSPCache.h" -#include "../sec/securityd/OTATrustUtilities.h" -#include "../sec/securityd/SecTrustLoggingServer.h" -#include "../sec/securityd/SecRevocationDb.h" -#include "../sec/securityd/SecPinningDb.h" -#include "trustd_spi.h" - -#if TARGET_OS_OSX -#include -#endif - -#if TARGET_OS_IPHONE -#include -#endif - -#endif // LIBTRUSTD - -#ifdef LIBTRUSTD -struct trustd trustd_spi = { - .sec_trust_store_for_domain = SecTrustStoreForDomainName, - .sec_trust_store_contains = SecTrustStoreContainsCertificateWithDigest, - .sec_trust_store_set_trust_settings = _SecTrustStoreSetTrustSettings, - .sec_trust_store_remove_certificate = SecTrustStoreRemoveCertificateWithDigest, - .sec_truststore_remove_all = _SecTrustStoreRemoveAll, - .sec_trust_evaluate = SecTrustServerEvaluate, - .sec_ota_pki_trust_store_version = SecOTAPKIGetCurrentTrustStoreVersion, - .sec_ota_pki_asset_version = SecOTAPKIGetCurrentAssetVersion, - .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates, - .sec_ota_pki_copy_trusted_ct_logs = SecOTAPKICopyCurrentTrustedCTLogs, - .sec_ota_pki_copy_ct_log_for_keyid = SecOTAPKICopyCTLogForKeyID, - .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset, - .sec_ota_secexperiment_get_new_asset = SecOTASecExperimentGetNewAsset, - .sec_ota_secexperiment_get_asset = SecOTASecExperimentCopyAsset, - .sec_trust_store_copy_all = _SecTrustStoreCopyAll, - .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints, - .sec_ocsp_cache_flush = SecOCSPCacheFlush, - .sec_networking_analytics_report = SecNetworkingAnalyticsReport, - .sec_trust_store_set_ct_exceptions = _SecTrustStoreSetCTExceptions, - .sec_trust_store_copy_ct_exceptions = _SecTrustStoreCopyCTExceptions, -#if TARGET_OS_IPHONE - .sec_trust_get_exception_reset_count = SecTrustServerGetExceptionResetCount, - .sec_trust_increment_exception_reset_count = SecTrustServerIncrementExceptionResetCount, -#endif -}; -#endif - -void trustd_init(CFURLRef home_path) { - if (home_path) - SetCustomHomeURL(home_path); - - trustd_init_server(); -} - -void trustd_init_server(void) { -#ifdef LIBTRUSTD - gTrustd = &trustd_spi; - SecPolicyServerInitialize(); - SecRevocationDbInitialize(); - SecPinningDbInitialize(); -#if TARGET_OS_OSX - SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation) -#endif -#endif // LIBTRUSTD -} diff --git a/OSX/trustd/trustd_spi.h b/OSX/trustd/trustd_spi.h deleted file mode 100644 index 107acec6..00000000 --- a/OSX/trustd/trustd_spi.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _TRUSTD_SPI_h -#define _TRUSTD_SPI_h - -#include -#include - -// Don't call these functions unless you are trustd -extern struct trustd trustd_spi; - -void trustd_init_server(void); -void trustd_init(CFURLRef home_dir); - -#endif /* _TRUSTD_SPI_h */ diff --git a/OSX/utilities/SecABC.h b/OSX/utilities/SecABC.h new file mode 100644 index 00000000..53c3f7b7 --- /dev/null +++ b/OSX/utilities/SecABC.h @@ -0,0 +1,32 @@ +// +// SecABC.h +// Security +// + +#include + +void SecABCTrigger(CFStringRef _Nonnull type, + CFStringRef _Nonnull subtype, + CFStringRef _Nullable subtypeContext, + CFDictionaryRef _Nullable payload); + +#if __OBJC__ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SecABC : NSObject + ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType + subtypeContext:(NSString * _Nullable)subtypeContext + events:(NSArray * _Nullable)events + payload:(NSDictionary * _Nullable)payload + detectedProcess:(NSString * _Nullable)process; + + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/OSX/utilities/SecABC.m b/OSX/utilities/SecABC.m new file mode 100644 index 00000000..23519a62 --- /dev/null +++ b/OSX/utilities/SecABC.m @@ -0,0 +1,71 @@ +// +// SecABC.m +// Security +// + +#import "SecABC.h" +#import + + +#if ABC_BUGCAPTURE +#import +#endif + +void SecABCTrigger(CFStringRef type, + CFStringRef subtype, + CFStringRef subtypeContext, + CFDictionaryRef payload) +{ + [SecABC triggerAutoBugCaptureWithType:(__bridge NSString *)type + subType:(__bridge NSString *)subtype + subtypeContext:(__bridge NSString *)subtypeContext + events:nil + payload:(__bridge NSDictionary *)payload + detectedProcess:nil]; +} + + +@implementation SecABC + ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType + subtypeContext:(NSString *)subtypeContext + events:(NSArray *)events + payload:(NSDictionary *)payload + detectedProcess:(NSString *)process +{ +#if ABC_BUGCAPTURE + os_log(OS_LOG_DEFAULT, "TriggerABC for %{public}@/%{public}@/%{public}@", + type, subType, subtypeContext); + + // no ABC on darwinos + if ([SDRDiagnosticReporter class] == nil) { + return; + } + + SDRDiagnosticReporter *diagnosticReporter = [[SDRDiagnosticReporter alloc] init]; + NSMutableDictionary *signature = [diagnosticReporter signatureWithDomain:@"com.apple.security.keychain" + type:type + subType:subType + subtypeContext:subtypeContext + detectedProcess:process?:[[NSProcessInfo processInfo] processName] + triggerThresholdValues:nil]; + if (signature == NULL) { + os_log(OS_LOG_DEFAULT, "TriggerABC signature generation failed"); + return; + } + + (void)[diagnosticReporter snapshotWithSignature:signature + duration:30.0 + events:events + payload:payload + actions:NULL + reply:^void(NSDictionary *response) + { + os_log(OS_LOG_DEFAULT, "Received response from Diagnostic Reporter - %{public}@/%{public}@/%{public}@: %{public}@", + type, subType, subtypeContext, response); + }]; +#endif +} + +@end diff --git a/OSX/utilities/SecCFWrappers.h b/OSX/utilities/SecCFWrappers.h index b9672113..f1efbf3f 100644 --- a/OSX/utilities/SecCFWrappers.h +++ b/OSX/utilities/SecCFWrappers.h @@ -902,6 +902,9 @@ static inline CFMutableSetRef CFSetCreateIntersection(CFAllocatorRef allocator, static inline CFSetRef CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array) { CFIndex count = CFArrayGetCount(array); + if (SIZE_MAX/sizeof(const void *) < (size_t)count) { + return NULL; + } const void **values = (const void **)malloc(sizeof(const void *) * count); CFArrayGetValues(array, CFRangeMake(0, count), values); CFSetRef set = CFSetCreate(CFGetAllocator(array), values, count, &kCFTypeSetCallBacks); diff --git a/OSX/utilities/SecDb.c b/OSX/utilities/SecDb.c index dbc32864..729520a4 100644 --- a/OSX/utilities/SecDb.c +++ b/OSX/utilities/SecDb.c @@ -408,7 +408,9 @@ static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn, bool didCre void SecDbCorrupt(SecDbConnectionRef dbconn, CFErrorRef error) { - os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error); + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error); + } dbconn->isCorrupted = true; CFRetainAssign(dbconn->corruptionError, error); } diff --git a/OSX/utilities/debugging.h b/OSX/utilities/debugging.h index 3a2a3106..52769f19 100644 --- a/OSX/utilities/debugging.h +++ b/OSX/utilities/debugging.h @@ -148,6 +148,7 @@ void __security_stackshotreport(CFStringRef reason, uint32_t code); /* For testing only, turns off/on simulated crashes, when turning on, returns number of simulated crashes which were not reported since last turned off. */ int __security_simulatecrash_enable(bool enable); +bool __security_simulatecrash_enabled(void); /* Logging control functions */ diff --git a/OSX/utilities/simulate_crash.c b/OSX/utilities/simulate_crash.c deleted file mode 100644 index 0ccd2f5d..00000000 --- a/OSX/utilities/simulate_crash.c +++ /dev/null @@ -1,98 +0,0 @@ -// -// simulate_crash -// utilities -// -// Copyright (c) 2014 Apple Inc. All Rights Reserved. -// - -#include "debugging.h" - -#include -#include -#include - -/// Type to represent a boolean value. -#if TARGET_OS_IPHONE && __LP64__ -typedef bool BOOL; -#else -typedef signed char BOOL; -// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" -// even if -funsigned-char is used. -#endif - -static void * -__security_get_CrashReporterSupport(void) -{ - static void *image = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - image = dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW); - }); - return image; -} - -static void __security_simulatecrash_link(CFStringRef reason, uint32_t code) -{ -#if !TARGET_OS_SIMULATOR - // Prototype defined in , but objC only. - // Soft linking here so we don't link unless we hit this. - static BOOL (*__SimulateCrash)(pid_t pid, mach_exception_data_type_t exceptionCode, CFStringRef description) = NULL; - - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ - void *image = __security_get_CrashReporterSupport(); - if (image) - __SimulateCrash = dlsym(image, "SimulateCrash"); - }); - - if (__SimulateCrash) - __SimulateCrash(getpid(), code, reason); - else - secerror("SimulateCrash not available"); -#else - secerror("SimulateCrash not available in iOS simulator"); -#endif -} - -static int __simulate_crash_counter = -1; - -void __security_simulatecrash(CFStringRef reason, uint32_t code) -{ - secerror("Simulating crash, reason: %@, code=%08x", reason, code); - if (__simulate_crash_counter < 0) - __security_simulatecrash_link(reason, code); - else - __simulate_crash_counter++; -} - -void __security_stackshotreport(CFStringRef reason, uint32_t code) -{ - secerror("stackshot report, reason: %@, code=%08x", reason, code); -#if !TARGET_OS_SIMULATOR - // Prototype defined in , but objC only. - // Soft linking here so we don't link unless we hit this. - static BOOL (*__WriteStackshotReport)(void *, mach_exception_data_type_t) = NULL; - - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ - void *image = __security_get_CrashReporterSupport(); - if (image) - __WriteStackshotReport = dlsym(image, "WriteStackshotReport"); - }); - - if (__WriteStackshotReport) - __WriteStackshotReport((void *)reason, code); - else - secerror("WriteStackshotReport not available"); -#else - secerror("WriteStackshotReport not available in iOS simulator"); -#endif -} - - -int __security_simulatecrash_enable(bool enable) -{ - int count = __simulate_crash_counter; - __simulate_crash_counter = enable ? -1 : 0; - return count; -} diff --git a/OSX/utilities/simulate_crash.m b/OSX/utilities/simulate_crash.m new file mode 100644 index 00000000..197dfe35 --- /dev/null +++ b/OSX/utilities/simulate_crash.m @@ -0,0 +1,58 @@ +// +// simulate_crash +// utilities +// +// Copyright (c) 2014 Apple Inc. All Rights Reserved. +// + +#include "debugging.h" + +#import +#import +#import + +SOFT_LINK_FRAMEWORK_SAFE(PrivateFrameworks, CrashReporterSupport); + +SOFT_LINK_FUNCTION(CrashReporterSupport, SimulateCrash, soft_SimulateCrash, \ + BOOL, (pid_t pid, mach_exception_data_type_t exceptionCode, NSString *description), + (pid, exceptionCode, description)); +SOFT_LINK_FUNCTION(CrashReporterSupport, WriteStackshotReport, soft_WriteStackshotReport, \ + BOOL, (NSString *reason, mach_exception_data_type_t exceptionCode), + (reason, exceptionCode)); + +static int __simulate_crash_counter = -1; + +void __security_simulatecrash(CFStringRef reason, uint32_t code) +{ + secerror("Simulating crash, reason: %@, code=%08x", reason, code); + if (__security_simulatecrash_enabled() && isCrashReporterSupportAvailable()) { + soft_SimulateCrash(getpid(), code, (__bridge NSString *)reason); + } else { + __simulate_crash_counter++; + } +} + +void __security_stackshotreport(CFStringRef reason, uint32_t code) +{ + secerror("stackshot report, reason: %@, code=%08x", reason, code); + if (!__security_simulatecrash_enabled() && isCrashReporterSupportAvailable()) { + return; + } + if (isCrashReporterSupportAvailable()) { + soft_WriteStackshotReport((__bridge NSString *)reason, code); + } +} + + +int __security_simulatecrash_enable(bool enable) +{ + int count = __simulate_crash_counter; + __simulate_crash_counter = enable ? -1 : 0; + return count; +} + +bool __security_simulatecrash_enabled(void) +{ + return __simulate_crash_counter == -1; +} + diff --git a/RegressionTests/Security.plist b/RegressionTests/Security.plist index 0c9e0521..15cb464c 100644 --- a/RegressionTests/Security.plist +++ b/RegressionTests/Security.plist @@ -31,42 +31,6 @@ /AppleInternal/CoreOS/tests/Security/secedumodetest - - TestName - secitemstresstest - Command - - /AppleInternal/CoreOS/tests/Security/secitemstresstest - - - - TestName - secitemnotifications - Command - - /AppleInternal/CoreOS/tests/Security/secitemnotifications - - - - TestName - secd_02_upgrade_while_locked - Command - - /usr/local/bin/secdtests - -1 - secd_02_upgrade_while_locked - - - - TestName - secd_35_keychain_migrate_inet - Command - - /usr/local/bin/secdtests - -1 - secd_35_keychain_migrate_inet - - TestName keychainnetworkextensionsharing-1 diff --git a/RegressionTests/SecurityLocalKeychain.plist b/RegressionTests/SecurityLocalKeychain.plist index 39337485..dfca88b5 100644 --- a/RegressionTests/SecurityLocalKeychain.plist +++ b/RegressionTests/SecurityLocalKeychain.plist @@ -35,42 +35,28 @@ TestName secitemfunctionality - EnableEasyperf - - EasyperfArgs - - -p - secd - Command /AppleInternal/CoreOS/tests/Security/secitemfunctionality ShowSubtestResults - EligibleResource - type != 'CAMEmbeddedDeviceResource' TestName - secitemfunctionality - EnableEasyperf - - EasyperfArgs + secitemstresstest + Command - -p - securityd + /AppleInternal/CoreOS/tests/Security/secitemstresstest - AsRoot - + + + TestName + secitemnotifications Command - /AppleInternal/CoreOS/tests/Security/secitemfunctionality + /AppleInternal/CoreOS/tests/Security/secitemnotifications - ShowSubtestResults - - EligibleResource - type == 'CAMEmbeddedDeviceResource' diff --git a/RegressionTests/secitemfunctionality/secitemfunctionality.m b/RegressionTests/secitemfunctionality/secitemfunctionality.m index 4afbc161..e7810946 100644 --- a/RegressionTests/secitemfunctionality/secitemfunctionality.m +++ b/RegressionTests/secitemfunctionality/secitemfunctionality.m @@ -38,6 +38,7 @@ fail(const char *fmt, ...) va_end(ap); } +#if 0 /* * Create item w/o data, try to make sure we end up in the OS X keychain */ @@ -78,6 +79,7 @@ CheckItemAddDeleteMaybeLegacyKeychainNoData(void) printf("[PASS] %s\n", __FUNCTION__); } +#endif static void CheckItemAddDeleteNoData(void) @@ -91,6 +93,7 @@ CheckItemAddDeleteNoData(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemDelete((__bridge CFDictionaryRef)query); if (status != errSecSuccess && status != errSecItemNotFound) @@ -125,10 +128,12 @@ CheckItemUpdateAccessGroupGENP(void) NSDictionary *clean1 = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", + (id)kSecUseDataProtectionKeychain: @YES, }; NSDictionary *clean2 = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test2", + (id)kSecUseDataProtectionKeychain: @YES, }; (void)SecItemDelete((__bridge CFDictionaryRef)clean1); @@ -144,6 +149,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecAttrAccount : @"item-delete-me", (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemAdd((__bridge CFDictionaryRef)add, NULL); if (status != errSecSuccess) @@ -156,7 +162,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; NSDictionary *modified = @{ (id)kSecAttrAccessGroup : @"keychain-test2", @@ -173,7 +179,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check1, NULL); if (status != errSecItemNotFound) @@ -184,7 +190,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test2", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check2, NULL); if (status != errSecSuccess) @@ -280,7 +286,7 @@ CheckIdentityItem(NSString *accessGroup, OSStatus expectedStatus) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : accessGroup, (id)kSecAttrLabel : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check, NULL); if (status != expectedStatus) @@ -324,7 +330,7 @@ CheckItemUpdateAccessGroupIdentity(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"item-delete-me", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemAdd((__bridge CFDictionaryRef)add, &ref); @@ -371,7 +377,7 @@ CheckItemUpdateAccessGroupIdentity(void) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : @"keychain-test2", (id)kSecAttrLabel : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef : (id)kCFBooleanTrue, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)prefQuery, (CFTypeRef *)&data); @@ -444,7 +450,7 @@ CheckFindIdentityByReference(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemAdd((__bridge CFDictionaryRef)add, (CFTypeRef *)&pref); @@ -483,6 +489,7 @@ CheckFindIdentityByReference(void) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemCopyMatching((CFDictionaryRef)query2, (CFTypeRef *)&pref2); @@ -506,6 +513,7 @@ CheckFindIdentityByReference(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", (id)kSecValueRef : (__bridge id)identity, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemCopyMatching((CFDictionaryRef)query3, (CFTypeRef *)&pref2); @@ -636,7 +644,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, (id)kSecAttrAccessGroup : @"keychain-test1", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecValueData : data, }; SecItemAdd((__bridge CFDictionaryRef)item, NULL); @@ -647,17 +655,20 @@ CheckItemPerformance(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitOne, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"FindOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccount : @"account-0", (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"Find1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunDigestPerfTest(@"Digest1000Items", (id)kSecClassGenericPassword, @"keychain-test1", 1000); RunCopyPerfTest(@"GetAttrOneItemUnique", @{ @@ -666,12 +677,14 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetData1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -679,6 +692,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataAttrOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -687,6 +701,7 @@ CheckItemPerformance(void) (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); #if TARGET_OS_IPHONE /* macOS doesn't support fetching data for more then one item */ RunCopyPerfTest(@"GetData1000Items", @{ @@ -694,6 +709,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataAttr1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -701,6 +717,7 @@ CheckItemPerformance(void) (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); #endif @@ -715,17 +732,11 @@ main(int argc, const char ** argv) { printf("[TEST] secitemfunctionality\n"); -#if TARGET_OS_OSX - char *user = getenv("USER"); - if (user && strcmp("bats", user) == 0) { - (void)SecKeychainUnlock(NULL, 4, "bats", true); - } -#endif CheckItemPerformance(); CheckFindIdentityByReference(); - CheckItemAddDeleteMaybeLegacyKeychainNoData(); + //CheckItemAddDeleteMaybeLegacyKeychainNoData(); CheckItemAddDeleteNoData(); CheckItemUpdateAccessGroupGENP(); CheckItemUpdateAccessGroupIdentity(); diff --git a/Security.exp-in b/Security.exp-in index bf1ddfe8..5da8fa4d 100644 --- a/Security.exp-in +++ b/Security.exp-in @@ -324,6 +324,7 @@ _kSSLSessionConfig_anonymous /* end workaround */ _SecAbsoluteTimeFromDateContent +_SecAbsoluteTimeFromDateContentWithError /* Internal securityd RPC stuff */ _CKKSSetupControlProtocol @@ -343,9 +344,6 @@ _kSecEntitlementPrivateOctagonEscrow _OTCliqueStatusToString _OTCliqueStatusFromString -_OTCliqueCFTypeRepair -_OTCliqueCFTypePasscode -_OTCliqueCFTypeUpgrade _OTCliqueCDPContextTypeNone _OTCliqueCDPContextTypeSignIn _OTCliqueCDPContextTypeRepair @@ -375,6 +373,7 @@ _OTCKContainerName _CuttlefishTrustZone _CuttlefishErrorDomain _TrustedPeersHelperErrorDomain +_CuttlefishErrorRetryAfterKey _OctagonPlatformSupportsSOS _OctagonSetPlatformSupportsSOS @@ -386,6 +385,8 @@ _OctagonRecoveryKeyIsEnabled _OctagonRecoveryKeySetIsEnabled _OctagonAuthoritativeTrustIsEnabled _OctagonAuthoritativeTrustSetIsEnabled +_OctagonIsSOSFeatureEnabled +_OctagonSetSOSFeatureEnabled SEC_EXP_CLASS(OTJoiningConfiguration) SEC_EXP_CLASS(OTControl) @@ -2032,6 +2033,7 @@ _ApplyScopeListForID _SecLogAPICreate ___security_simulatecrash ___security_simulatecrash_enable +___security_simulatecrash_enabled ___security_stackshotreport _api_trace _secLogEnabled diff --git a/Security.xcodeproj/project.pbxproj b/Security.xcodeproj/project.pbxproj index 1dfe15aa..5d5176ea 100644 --- a/Security.xcodeproj/project.pbxproj +++ b/Security.xcodeproj/project.pbxproj @@ -211,6 +211,7 @@ D4E0E9982224DF9A00A802E0 /* PBXTargetDependency */, D4E0E9962224DF9300A802E0 /* PBXTargetDependency */, D4E0E9942224DF8D00A802E0 /* PBXTargetDependency */, + D4E0E95C2224DE1000A802E0 /* PBXTargetDependency */, D4E0E9902224DF8500A802E0 /* PBXTargetDependency */, D4E0E9922224DF8500A802E0 /* PBXTargetDependency */, D4E0E98E2224DF7D00A802E0 /* PBXTargetDependency */, @@ -778,17 +779,16 @@ 0C0DA5D01FE1F1F3003BD3BB /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; }; 0C0E60DA20D033E400E654F2 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; 0C0E60E020D033E400E654F2 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; - 0C101F942053528700387951 /* OTBottledPeerState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C101F932053528700387951 /* OTBottledPeerState.m */; }; 0C12B1F12138D31600BE0A98 /* OTClientStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */; }; 0C16371C1FD116B300210823 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; }; - 0C1637211FD12F1500210823 /* OTCloudStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */; }; 0C1637271FD2065400210823 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; 0C1637291FD2066A00210823 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; }; 0C16372B1FD2067F00210823 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; 0C16372D1FD2069300210823 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; 0C1637301FD206BC00210823 /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; }; 0C1B8BB72233244F0094D5DA /* OTVouchWithRecoveryKeyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */; }; - 0C24D693204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */; }; + 0C29BF222323288C003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; + 0C29BF2523232897003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; 0C2BCBAF1D06401F00ED7A2F /* ioSock.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CE5A65809C79E0600D27A3F /* ioSock.c */; }; 0C2BCBB01D06401F00ED7A2F /* sslAppUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE5A65A09C79E0600D27A3F /* sslAppUtils.cpp */; }; 0C2BCBB41D06401F00ED7A2F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; @@ -809,12 +809,9 @@ 0C3C00731EF3636500AB19FE /* secd-155-otr-negotiation-monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */; }; 0C3E316B21372FA50093C04B /* OctagonPairingTests+ProximitySetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604812134DD5D00BFBBB8 /* OctagonPairingTests+ProximitySetup.swift */; }; 0C46A5712034C6BA00F17112 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; - 0C46A57B2035019800F17112 /* OTLockStateNetworkingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */; }; 0C48990B1E0E0FF300C6CF70 /* SOSTransportCircleCK.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */; }; 0C4899121E0E105D00C6CF70 /* SOSTransportCircleCK.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */; }; 0C4899231E0F386900C6CF70 /* SOSAccountTrustClassic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C4899221E0F386900C6CF70 /* SOSAccountTrustClassic.h */; }; - 0C48B371202E3ED800A0E1AA /* OTIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */; }; - 0C48B377202E3EE700A0E1AA /* OTContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE981FC9DA5A00580909 /* OTContext.m */; }; 0C48B380202E438100A0E1AA /* CloudKitKeychainSyncingMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */; }; 0C4C547620E1A0B400BA61BA /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C4C548020E1A53D00BA61BA /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; @@ -830,7 +827,6 @@ 0C5824A52286002D009E8C15 /* OctagonTests+HealthCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C5824A322860001009E8C15 /* OctagonTests+HealthCheck.swift */; }; 0C5960641FB2E2070095BA29 /* libprequelite.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CE98B5B1FA9360700CF1D54 /* libprequelite.tbd */; settings = {ATTRIBUTES = (Weak, ); }; }; 0C5960811FB369C50095BA29 /* CKKSHealTLKSharesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBF2F841F913EF000ED0CA4 /* CKKSHealTLKSharesOperation.m */; }; - 0C5A8C1D200A9B0C004C771D /* OTPreflightInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */; }; 0C61F1F62194FC79009566D4 /* OTPrivateKey+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3522188E18A0018FC14 /* OTPrivateKey+SF.m */; }; 0C61F1F92194FC82009566D4 /* OTAuthenticatedCiphertext+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3542188E18B0018FC14 /* OTAuthenticatedCiphertext+SF.m */; }; 0C66046A2134983900BFBBB8 /* OTEstablishOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604692134983900BFBBB8 /* OTEstablishOperation.m */; }; @@ -842,8 +838,6 @@ 0C6C0FD221F146E700CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C6C0FD621F14D3900CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; - 0C770EBC1FCF7C9800B5F0E2 /* OTCloudStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */; }; - 0C770EC41FCF7E2000B5F0E2 /* OTCloudStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */; }; 0C78826F20132069002B7475 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0C78827520132074002B7475 /* SFSignInAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */; }; 0C78F1CC16A5E1BF00654E08 /* sectask-10-sectask.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */; }; @@ -884,12 +878,6 @@ 0C87D3E4229368BD007853B5 /* OctagonTests+SOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C87D3E2229368A7007853B5 /* OctagonTests+SOS.swift */; }; 0C8884012154C4E80053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; 0C8884042154C4EA0053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; - 0C8A03461FDF42BA0042E8BE /* OTEscrowKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */; }; - 0C8A034D1FDF4CCE0042E8BE /* OTLocalStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */; }; - 0C8A034F1FDF60070042E8BE /* OTBottledPeerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */; }; - 0C8BBE9F1FC9DBA400580909 /* OTBottledPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */; }; - 0C8BBEA51FC9DBB100580909 /* OTEscrowKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */; }; - 0C8BBEA91FC9DBBF00580909 /* OTLocalStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */; }; 0C8FD52521483EF20098E3FB /* OT.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCCC7C820261D310024405E /* OT.m */; }; 0C98122821ACCC9300784441 /* OTClique.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F336A20DD643B0031A92D /* OTClique.m */; }; 0C9AEEAF20783FBB00BF6237 /* SFSignInAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */; }; @@ -912,7 +900,6 @@ 0CAD1E5D1E1C5CF900537693 /* secd-80-views-alwayson.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E08B1DFD0A380021E1B7 /* secd-80-views-alwayson.m */; }; 0CAD1E5E1E1C5D0600537693 /* secd-95-escrow-persistence.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */; }; 0CADDF0721545CF100DF8B06 /* OctagonPairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CADDF0421545C8E00DF8B06 /* OctagonPairingTests.swift */; }; - 0CAEC9D81FD740CF00D1F2CA /* OTContextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */; }; 0CB50A0D20AA486800FE4675 /* SOSAccountTrustClassic+Expansion.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */; }; 0CB50A0E20AA4C2F00FE4675 /* SOSAccountTrustClassic+Circle.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */; }; 0CB582C82189157F0040C5F2 /* OTAuthenticatedCiphertext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C5218915390040C5F2 /* OTAuthenticatedCiphertext.m */; }; @@ -932,10 +919,8 @@ 0CB72DA121E42FCF00D8BC9B /* OTSponsorToApplicantRound2M2.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C9AE290214054F7003BFDB5 /* OTSponsorToApplicantRound2M2.m */; }; 0CB8DC9A2194B14C0021A7C8 /* OTVouchWithBottleOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */; }; 0CB9754F2023A8F5008D6B48 /* CloudKitMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */; }; - 0CB975512023B199008D6B48 /* OTRampingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB975502023B199008D6B48 /* OTRampingTests.m */; }; 0CBA047D214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA047C214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift */; }; 0CBD55B31FE883F200A8CE21 /* SFBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */; }; - 0CBDF64D1FFC951200433E0D /* OTBottledPeerTLK.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */; }; 0CBEF3432242CA0600015691 /* TestsObjcTranslation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */; }; 0CBFEACA200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0CBFEACB200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; @@ -953,7 +938,6 @@ 0CD5797A21498F8200C43496 /* OctagonPairingTests+Piggybacking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD5797721498F7700C43496 /* OctagonPairingTests+Piggybacking.swift */; }; 0CD8CB051ECA50780076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; 0CD8CB0B1ECA50920076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; - 0CD9E8001FE05B6600F66C38 /* OTContextRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */; }; 0CDD6F79226E83F6009094C2 /* OTTriggerEscrowUpdateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */; }; 0CE079F41FEA15B20040A3F1 /* SFBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */; }; 0CE15E2C222DF63600B7EAA4 /* RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA4 /* RecoveryKey.swift */; }; @@ -970,8 +954,6 @@ 0CE15E43222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; 0CE15E44222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; 0CE15E46222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; - 0CE1BCCE1FCE11680017230E /* OTBottledPeerSigned.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */; }; - 0CE407AC1FD4769B00F59B31 /* OTCloudStoreState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */; }; 0CE751AF20ACC497002B2832 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0CE760501E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE7604F1E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h */; }; 0CE760521E1314F700B4381E /* SOSAccountTrustClassic+Identity.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE760511E1314F700B4381E /* SOSAccountTrustClassic+Identity.h */; }; @@ -992,13 +974,12 @@ 0CF70BE3218CF2AA00EC3515 /* OTBottle.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C4218915390040C5F2 /* OTBottle.m */; }; 0CF70BE4218CF2AA00EC3515 /* OTBottleContents.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C62189153A0040C5F2 /* OTBottleContents.m */; }; 0CF70BE5218CF2AA00EC3515 /* OTPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C3218915390040C5F2 /* OTPrivateKey.m */; }; - 0CF74E4120DDD5290014A5DB /* OTTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337720DD64C20031A92D /* OTTestsBase.m */; }; - 0CF74E4720DDD5390014A5DB /* OTCliqueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337520DD64C10031A92D /* OTCliqueTests.m */; }; 0CFC029C1D41650700E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 0CFC02C21D41651E00E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 107226D30D91DB32003CF14F /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 107226D10D91DB32003CF14F /* SecTask.h */; settings = {ATTRIBUTES = (Private, ); }; }; 18F7F67914D77F4400F88A12 /* NtlmGenerator.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA10AB5F0BB0010451D /* NtlmGenerator.c */; }; 18F7F67A14D77F4400F88A12 /* ntlmBlobPriv.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA30AB5F0BB0010451D /* ntlmBlobPriv.c */; }; + 1B0CDF64231C9E0E004401F0 /* ContainerMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D18206C4AD300B53D16 /* ContainerMap.swift */; }; 1B4AE38722400A22002188E1 /* TPDictionaryMatchingRules.m in Sources */ = {isa = PBXBuildFile; fileRef = DC8846802237431400738068 /* TPDictionaryMatchingRules.m */; }; 1B4C444B223AE65500C6F97F /* TPPBPolicyKeyViewMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B4C4448223AE65400C6F97F /* TPPBPolicyKeyViewMapping.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1B4C444C223AE65500C6F97F /* TPPBPolicyKeyViewMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B4C444A223AE65400C6F97F /* TPPBPolicyKeyViewMapping.m */; }; @@ -1010,6 +991,8 @@ 1B916CD0223FFF25006657FD /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; }; 1B995259226681FA00A2D6CD /* PolicyReporter.h in Sources */ = {isa = PBXBuildFile; fileRef = 1B995256226681ED00A2D6CD /* PolicyReporter.h */; }; 1B99525A226681FA00A2D6CD /* PolicyReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B995258226681EE00A2D6CD /* PolicyReporter.m */; }; + 1BB1CAB7232C05BD001D0C71 /* CuttlefishXPCWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */; }; + 1BB1CAB8232C05BD001D0C71 /* CuttlefishXPCWrapper.h in Sources */ = {isa = PBXBuildFile; fileRef = 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */; }; 1BC6F79C21C9955F005ED67A /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC6F79821C9955E005ED67A /* util.h */; }; 1BDEBEF92252DEB1009AD3D6 /* policy_dryrun.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */; }; 1BDEBEFD2253E6D9009AD3D6 /* policy_dryrun.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */; }; @@ -1186,15 +1169,12 @@ 4718AE37205B39C40068EC3F /* CKKSAccountStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFB12C41E95A4C000510F5F /* CKKSAccountStateTracker.m */; }; 4718AE38205B39C40068EC3F /* SecCDKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 470D96701FCDE55B0065FE90 /* SecCDKeychain.m */; }; 4718AE3A205B39C40068EC3F /* CKKSGroupOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */; }; - 4718AE3B205B39C40068EC3F /* OTContextRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */; }; 4718AE3D205B39C40068EC3F /* CKKSManifestLeafRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */; }; 4718AE3E205B39C40068EC3F /* CKKSItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */; }; 4718AE3F205B39C40068EC3F /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; 4718AE40205B39C40068EC3F /* CKKSOutgoingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */; }; 4718AE42205B39C40068EC3F /* CKKSIncomingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */; }; - 4718AE43205B39C40068EC3F /* OTLocalStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */; }; 4718AE44205B39C40068EC3F /* SFKeychainControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 473337781FDAFBCC00E19F30 /* SFKeychainControlManager.m */; }; - 4718AE45205B39C40068EC3F /* OTBottledPeerSigned.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */; }; 4718AE46205B39C40068EC3F /* CKKSIncomingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */; }; 4718AE47205B39C40068EC3F /* CKKSOutgoingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */; }; 4718AE48205B39C40068EC3F /* CKKSZoneStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */; }; @@ -1203,7 +1183,6 @@ 4718AE4C205B39C40068EC3F /* CKKSCurrentItemPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */; }; 4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3D748B1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m */; }; 4718AE4E205B39C40068EC3F /* OTManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0F1FCB481800580909 /* OTManager.m */; }; - 4718AE4F205B39C40068EC3F /* OTEscrowKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */; }; 4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */; }; 4718AE51205B39C40068EC3F /* CKKSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */; }; 4718AE52205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */; }; @@ -1238,18 +1217,15 @@ 4718AE6F205B39C40068EC3F /* OTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = EB10A3E420356E2000E84270 /* OTConstants.m */; }; 4718AE71205B39C40068EC3F /* SecItemServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9A1D8085D800865A7C /* SecItemServer.c */; }; 4718AE72205B39C40068EC3F /* SecDbKeychainSerializedAKSWrappedKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 47922D361FAA7C030008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.m */; }; - 4718AE74205B39C40068EC3F /* OTContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE981FC9DA5A00580909 /* OTContext.m */; }; 4718AE75205B39C40068EC3F /* NSOperationCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1447951F5766D200236DB4 /* NSOperationCategories.m */; }; 4718AE76205B39C40068EC3F /* SecKeybagSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */; }; 4718AE77205B39C40068EC3F /* SecLogSettingsServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */; }; 4718AE78205B39C40068EC3F /* CKKSDeviceStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */; }; 4718AE79205B39C40068EC3F /* CKKSFixups.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAD9B431F8D939C00C5E2AE /* CKKSFixups.m */; }; - 4718AE7A205B39C40068EC3F /* OTIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */; }; 4718AE7C205B39C40068EC3F /* SecOTRRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB41D8085D800865A7C /* SecOTRRemote.m */; }; 4718AE7D205B39C40068EC3F /* CKKSUpdateCurrentItemPointerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */; }; 4718AE7E205B39C40068EC3F /* CKKSNewTLKOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */; }; 4718AE7F205B39C40068EC3F /* CKKSLockStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */; }; - 4718AE80205B39C40068EC3F /* OTCloudStoreState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */; }; 4718AE81205B39C40068EC3F /* SecDbKeychainSerializedSecretData.m in Sources */ = {isa = PBXBuildFile; fileRef = 47922D3F1FAA7C1B0008F7E0 /* SecDbKeychainSerializedSecretData.m */; }; 4718AE82205B39C40068EC3F /* CKKSKeychainView.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */; }; 4718AE83205B39C40068EC3F /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; @@ -1261,12 +1237,8 @@ 4718AE8A205B39C40068EC3F /* SecBackupKeybagEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */; }; 4718AE8B205B39C40068EC3F /* iCloudTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB31D8085D800865A7C /* iCloudTrace.c */; }; 4718AE8C205B39C40068EC3F /* OctagonAPSReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D841E2F14810089CF55 /* OctagonAPSReceiver.m */; }; - 4718AE8D205B39C40068EC3F /* OTBottledPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */; }; 4718AE8F205B39C40068EC3F /* SOSEnsureBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C860C7A1F4F63DB004100A1 /* SOSEnsureBackup.m */; }; - 4718AE90205B39C40068EC3F /* OTBottledPeerRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */; }; - 4718AE91205B39C40068EC3F /* OTCloudStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */; }; 4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */; }; - 4718AE93205B39C40068EC3F /* OTPreflightInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */; }; 4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */; }; 4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */; }; 4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D961E3014250089CF55 /* CKKSZone.m */; }; @@ -1279,7 +1251,6 @@ 4718AEA2205B39C40068EC3F /* CKKSGroupOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */; }; 4718AEA3205B39C40068EC3F /* CKKSRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */; }; 4718AEA4205B39C40068EC3F /* SecDbKeychainSerializedItemV7.h in Headers */ = {isa = PBXBuildFile; fileRef = 47922D501FAA7DF60008F7E0 /* SecDbKeychainSerializedItemV7.h */; }; - 4718AEA5205B39C40068EC3F /* OTCloudStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */; }; 4718AEA6205B39C40068EC3F /* CKKSResultOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1447881F5764C600236DB4 /* CKKSResultOperation.h */; }; 4718AEA7205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */; }; 4718AEA8205B39C40068EC3F /* CKKSViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */; }; @@ -1492,6 +1463,7 @@ 482FE56E2177CF340031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 482FE56B2177C7AE0031C11E /* AuthKit.framework */; }; 482FE56F2177CF520031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; }; 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.m in Sources */ = {isa = PBXBuildFile; fileRef = 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */; }; + 48AC7B73232B1DA600F02B6F /* SOSIntervalEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */; }; 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */; }; 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.m */; }; 48E617221DBEC6C60098EAAD /* SOSBackupInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 48E6171B1DBEC40D0098EAAD /* SOSBackupInformation.h */; }; @@ -2064,8 +2036,6 @@ BE22FBD11EE2084100893431 /* Config.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBD01EE2084100893431 /* Config.m */; }; BE22FC041EE3584400893431 /* mark.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBFC1EE23D9100893431 /* mark.m */; }; BE25C41618B83491003320E0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; - BE2AD2B31FDA07EF00739F96 /* OTBottledPeerRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */; }; - BE2AD2BA1FDA080800739F96 /* OTBottledPeerRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */; }; BE405EE21DC2F10E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; BE405EE31DC2F11E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; BE442BAE18B7FDB800F24DAE /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; @@ -2587,6 +2557,8 @@ DA20716222E9367500E209E4 /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; }; DA2C402E2189302F005F1CC3 /* mach_notify.defs in Sources */ = {isa = PBXBuildFile; fileRef = DA2C402D2189302E005F1CC3 /* mach_notify.defs */; settings = {ATTRIBUTES = (Server, ); }; }; DA30D6851DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */; }; + DA31CB212319DC8F0039F1CC /* TPStringTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA700FC82310C0E00051A7DE /* TPStringTable.m */; }; + DA3AD86A2319AA5D0049AFD6 /* TPStringTableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */; }; DA41FE1A2241AF4600838FB3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA41FE192241AF3E00838FB3 /* main.m */; }; DA41FE1B2241AF8200838FB3 /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; DA45865C2245AEDB0073F993 /* OTPairingService.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4586592245AEDA0073F993 /* OTPairingService.m */; }; @@ -2594,6 +2566,8 @@ DA5B871D2065A8440093F083 /* SecAutorelease.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5B871B2065A8430093F083 /* SecAutorelease.m */; }; DA6AA1651FE88AFB004565B0 /* CKKSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */; }; DA6AA1671FE88AFB004565B0 /* CKKSControlServer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6AA1641FE88AFA004565B0 /* CKKSControlServer.h */; }; + DA700FC92310C0E00051A7DE /* TPStringTable.h in Headers */ = {isa = PBXBuildFile; fileRef = DA700FC62310C0DF0051A7DE /* TPStringTable.h */; }; + DA700FCA2310C0E00051A7DE /* TPStringTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA700FC82310C0E00051A7DE /* TPStringTable.m */; }; DAB27AE11FA29EE300DEBBDE /* SOSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB27AE01FA29EB800DEBBDE /* SOSControlServer.m */; }; DAC58D1B22443C0700D4CD41 /* KeychainCircle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C75AC642141F18D0073A2F9 /* KeychainCircle.framework */; }; DAC58D202244528B00D4CD41 /* OTPairingPacketContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC58D1E2244528000D4CD41 /* OTPairingPacketContext.m */; }; @@ -3149,7 +3123,7 @@ DC0BCDA91D8C6A1F00070CB0 /* SecFileLocations.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */; }; DC0BCDAA1D8C6A1F00070CB0 /* SecXPCError.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */; }; DC0BCDAB1D8C6A1F00070CB0 /* SecXPCError.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */; }; - DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */; }; + DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.m in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */; }; DC0BCDAD1D8C6A1F00070CB0 /* SecSCTUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */; }; DC0BCDAE1D8C6A1F00070CB0 /* SecSCTUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */; }; DC0BCDAF1D8C6A1F00070CB0 /* SecAppleAnchor.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */; }; @@ -3309,7 +3283,6 @@ DC1787851D7791CE00B50D50 /* SecTrustSettingsPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC17890B1D77980500B50D50 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DC1789131D7798B300B50D50 /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; - DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DC17891D1D77999700B50D50 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891C1D77999700B50D50 /* libpam.dylib */; }; DC17891F1D77999D00B50D50 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; @@ -3355,6 +3328,8 @@ DC19484D21812EC5007C2260 /* OTDeviceInformationAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC19484B21812EC5007C2260 /* OTDeviceInformationAdapter.m */; }; DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */; }; DC1DA6681E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */; }; + DC1E5AB623063A4E00918162 /* CKKSPeerProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */; }; + DC1E5AB723063A4E00918162 /* CKKSPeerProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */; }; DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; DC1ED8C61DD55476002BDCFA /* CKKS.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8C51DD55476002BDCFA /* CKKS.m */; }; DC221BAB2267E2A60068DBCF /* OTUpdateTPHOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC221BA92267E2A60068DBCF /* OTUpdateTPHOperation.h */; }; @@ -3370,6 +3345,7 @@ DC2353311ECA658B00D7C1BE /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; }; DC2353321ECA659000D7C1BE /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; DC2353331ECA659000D7C1BE /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DC25B3AC233C2EBC00CB1409 /* CloudKitCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC94BCC91F10448600E07CEB /* CloudKitCategories.m */; }; DC26666A21CAC32700F19960 /* OTControlCLI.m in Sources */ = {isa = PBXBuildFile; fileRef = DC26666921CAC32700F19960 /* OTControlCLI.m */; }; DC26666C21CAC97000F19960 /* OTControlCLI.m in Sources */ = {isa = PBXBuildFile; fileRef = DC26666921CAC32700F19960 /* OTControlCLI.m */; }; DC2670F21F3E6EC500816EED /* debugging.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC531D8C68CF00070CB0 /* debugging.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -3546,7 +3522,6 @@ DC4EA5961E70A237008840B4 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC5060EB20E2D88300925005 /* OTCuttlefishContext.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5060E920E2D88300925005 /* OTCuttlefishContext.h */; }; DC5060ED20E2D88300925005 /* OTCuttlefishContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5060EA20E2D88300925005 /* OTCuttlefishContext.m */; }; - DC5060F520E2DB9700925005 /* OTCuttlefishContextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */; }; DC52E7C41D80BCAD00B0A59C /* SecDbItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8E1D8085D800865A7C /* SecDbItem.c */; }; DC52E7C51D80BCB300B0A59C /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; }; DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9C1D8085D800865A7C /* SecItemBackupServer.c */; }; @@ -3880,7 +3855,6 @@ DC5AC0C71D8353C800CF422C /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0C61D8353C800CF422C /* PCSC.framework */; }; DC5AC0C91D8353D100CF422C /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DC5AC0CE1D83542B00CF422C /* libsecurity_tokend_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0CD1D83542700CF422C /* libsecurity_tokend_client.a */; }; - DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0B91D83533400CF422C /* libsecuritydservice_client.a */; }; DC5AC0D61D83548300CF422C /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; @@ -5997,6 +5971,9 @@ EB3A8DFF1BEEC66F001A89AA /* Security_edumode.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */; }; EB3D1FBA2092CB030049EF95 /* SecurityInduceLowDisk.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EBE202752092913500B48020 /* SecurityInduceLowDisk.plist */; }; EB3F9C9D21FCFD67007B6EBA /* OctagonTestHarness.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3F9C9B21FCFC60007B6EBA /* OctagonTestHarness.m */; }; + EB3FB9B8231C12AD00DF52EA /* com.apple.security.trustedpeers.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */; }; + EB3FBB4F231F836500DF52EA /* CKKSListenerCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3AF52B2229E6C0006577E8 /* CKKSListenerCollection.m */; }; + EB3FBC09232063A100DF52EA /* SecABC.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3FBBF52320629400DF52EA /* SecABC.m */; }; EB413B801E663AEB00592085 /* PairingChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = EB413B761E6624A500592085 /* PairingChannel.m */; }; EB413B821E663AFA00592085 /* PairingChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = EB413B751E6624A400592085 /* PairingChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB425CA21C65846D000ECE53 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; @@ -6009,9 +5986,7 @@ EB49B2B1202D8780003F34A0 /* mockaksKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = EB49B2B0202D8780003F34A0 /* mockaksKeychain.m */; }; EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; EB49B2BC202DEF14003F34A0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CB96BB41F966E0C00E11457 /* libsqlite3.tbd */; }; - EB49B2BD202DEF29003F34A0 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; EB49B2BE202DEF29003F34A0 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; - EB49B2BF202DEF67003F34A0 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; EB49B2C0202DEF7D003F34A0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; EB49B2C1202DEF8D003F34A0 /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; }; EB49B2C2202DF002003F34A0 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246911F9AE2E400D63882 /* libDER.a */; }; @@ -6021,7 +5996,6 @@ EB49B2D1202DF15F003F34A0 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; }; EB49B2D2202DF17D003F34A0 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; }; EB49B2D3202DF1AC003F34A0 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; }; - EB49B2D4202DF1C1003F34A0 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; }; EB49B2D5202DF1D8003F34A0 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; EB49B2D7202DF1F7003F34A0 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; EB49B2D8202DF1F7003F34A0 /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; @@ -11544,6 +11518,17 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + EB3FB9A3231C125400DF52EA /* Copy Logging Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/Preferences/Logging/Subsystems; + dstSubfolderSpec = 0; + files = ( + EB3FB9B8231C12AD00DF52EA /* com.apple.security.trustedpeers.plist in Copy Logging Files */, + ); + name = "Copy Logging Files"; + runOnlyForDeploymentPostprocessing = 1; + }; EB6952B4223B75C300F02C1C /* launchd plist */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -11678,7 +11663,7 @@ /* Begin PBXFileReference section */ 091B396D2063B64A00ECAB6F /* RemoteServiceDiscovery.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RemoteServiceDiscovery.framework; path = System/Library/PrivateFrameworks/RemoteServiceDiscovery.framework; sourceTree = SDKROOT; }; - 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecKeyProxy.h; path = keychain/SecKeyProxy.h; sourceTree = ""; }; + 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecKeyProxy.h; path = keychain/headers/SecKeyProxy.h; sourceTree = ""; }; 09A3B9DF1F8271A200C5C324 /* si-44-seckey-proxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "si-44-seckey-proxy.m"; path = "OSX/shared_regressions/si-44-seckey-proxy.m"; sourceTree = SOURCE_ROOT; }; 09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainEntitlementsTest.m; sourceTree = ""; }; 09C3E08B22A83B40004ACFC4 /* securityd.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = securityd.entitlements; sourceTree = ""; }; @@ -11695,15 +11680,11 @@ 0C0CEC9D1DA45EA200C22FBC /* recovery_key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recovery_key.h; sourceTree = ""; }; 0C0CEC9E1DA45EA200C22FBC /* recovery_key.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = recovery_key.m; sourceTree = ""; }; 0C0F76DD21399AF40074EDDF /* OTPairingMessage.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = OTPairingMessage.proto; sourceTree = ""; }; - 0C101F932053528700387951 /* OTBottledPeerState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerState.m; sourceTree = ""; }; - 0C101F96205352AF00387951 /* OTBottledPeerState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerState.h; sourceTree = ""; }; 0C108C4B208A677100E8CF70 /* SFSignInAnalytics+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFSignInAnalytics+Internal.h"; sourceTree = ""; }; 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientStateMachine.m; sourceTree = ""; }; 0C12B1F52138D32F00BE0A98 /* OTClientStateMachine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClientStateMachine.h; sourceTree = ""; }; - 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStoreTests.m; sourceTree = ""; }; 0C1B8BB3223323710094D5DA /* OTVouchWithRecoveryKeyOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTVouchWithRecoveryKeyOperation.h; sourceTree = ""; }; 0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTVouchWithRecoveryKeyOperation.m; sourceTree = ""; }; - 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerUpdateBottlesTests.m; sourceTree = ""; }; 0C2A04152152ED7F00FD4FAD /* KCJoiningAcceptSession+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KCJoiningAcceptSession+Internal.h"; sourceTree = ""; }; 0C2A041A2152EF3000FD4FAD /* KCJoiningRequestSession+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KCJoiningRequestSession+Internal.h"; sourceTree = ""; }; 0C2BCBA51D063F7D00ED7A2F /* dtlsEchoClient.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dtlsEchoClient.c; sourceTree = ""; }; @@ -11714,17 +11695,11 @@ 0C2F336A20DD643B0031A92D /* OTClique.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTClique.m; sourceTree = ""; }; 0C2F337020DD647C0031A92D /* OTRamping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRamping.h; sourceTree = ""; }; 0C2F337120DD647D0031A92D /* OTRamping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRamping.m; sourceTree = ""; }; - 0C2F337520DD64C10031A92D /* OTCliqueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTCliqueTests.m; sourceTree = ""; }; - 0C2F337620DD64C20031A92D /* OTTestsBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTTestsBase.h; sourceTree = ""; }; - 0C2F337720DD64C20031A92D /* OTTestsBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTTestsBase.m; sourceTree = ""; }; - 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTPreflightInfo.m; sourceTree = ""; }; - 0C36B3202007EE9B0029F7A2 /* OTPreflightInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPreflightInfo.h; sourceTree = ""; }; 0C3BB3522188E18A0018FC14 /* OTPrivateKey+SF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OTPrivateKey+SF.m"; path = "keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m"; sourceTree = SOURCE_ROOT; }; 0C3BB3542188E18B0018FC14 /* OTAuthenticatedCiphertext+SF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OTAuthenticatedCiphertext+SF.m"; path = "keychain/TrustedPeersHelper/categories/OTAuthenticatedCiphertext+SF.m"; sourceTree = SOURCE_ROOT; }; 0C3BB3562188E18B0018FC14 /* OTPrivateKey+SF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OTPrivateKey+SF.h"; path = "keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.h"; sourceTree = SOURCE_ROOT; }; 0C3BB3572188E18C0018FC14 /* OTAuthenticatedCiphertext+SF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OTAuthenticatedCiphertext+SF.h"; path = "keychain/TrustedPeersHelper/categories/OTAuthenticatedCiphertext+SF.h"; sourceTree = SOURCE_ROOT; }; 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-155-otr-negotiation-monitor.m"; sourceTree = ""; }; - 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLockStateNetworkingTests.m; sourceTree = ""; }; 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircleCK.h; sourceTree = ""; }; 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircleCK.m; sourceTree = ""; }; 0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrustClassic.m; path = SecureObjectSync/SOSAccountTrustClassic.m; sourceTree = ""; }; @@ -11744,7 +11719,6 @@ 0C6C2B682258211800C53C96 /* AppleAccount.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleAccount.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/AppleAccount.framework; sourceTree = DEVELOPER_DIR; }; 0C6C2B6C2258295D00C53C96 /* UIKitCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKitCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/UIKitCore.framework; sourceTree = DEVELOPER_DIR; }; 0C75AC642141F18D0073A2F9 /* KeychainCircle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = KeychainCircle.framework; path = System/Library/PrivateFrameworks/KeychainCircle.framework; sourceTree = SDKROOT; }; - 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStore.m; sourceTree = ""; }; 0C78F1C916A5E13400654E08 /* sectask_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sectask_regressions.h; sourceTree = ""; }; 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sectask-10-sectask.c"; sourceTree = ""; }; 0C78F1CB16A5E1BF00654E08 /* sectask_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = sectask_ipc.defs; sourceTree = ""; }; @@ -11754,22 +11728,7 @@ 0C87D3E2229368A7007853B5 /* OctagonTests+SOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+SOS.swift"; sourceTree = ""; }; 0C89BDA021554DD2003F3CC0 /* OTAccountMetadataClassC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTAccountMetadataClassC.m; sourceTree = ""; }; 0C89BDA121554DD3003F3CC0 /* OTAccountMetadataClassC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTAccountMetadataClassC.h; sourceTree = ""; }; - 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTEscrowKeyTests.m; sourceTree = ""; }; - 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLocalStoreTests.m; sourceTree = ""; }; - 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerTests.m; sourceTree = ""; }; - 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTCloudStore.h; sourceTree = ""; }; - 0C8BBE8A1FC9DA5300580909 /* OTIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTIdentity.h; sourceTree = ""; }; - 0C8BBE8B1FC9DA5300580909 /* OTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTContext.h; sourceTree = ""; }; - 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTLocalStore.m; sourceTree = ""; }; - 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTIdentity.m; sourceTree = ""; }; - 0C8BBE8E1FC9DA5500580909 /* OTLocalStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTLocalStore.h; sourceTree = ""; }; - 0C8BBE921FC9DA5700580909 /* OTEscrowKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTEscrowKeys.h; sourceTree = ""; }; - 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeer.m; sourceTree = ""; }; - 0C8BBE951FC9DA5800580909 /* OTBottledPeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTBottledPeer.h; sourceTree = ""; }; - 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTEscrowKeys.m; sourceTree = ""; }; 0C8BBE971FC9DA5A00580909 /* OTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTDefines.h; sourceTree = ""; }; - 0C8BBE981FC9DA5A00580909 /* OTContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTContext.m; sourceTree = ""; }; - 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTContextTests.m; sourceTree = ""; }; 0C8BBEF71FCB405700580909 /* otctl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = otctl.m; sourceTree = ""; }; 0C8BBEF81FCB407700580909 /* otctl-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "otctl-Entitlements.plist"; sourceTree = ""; }; 0C8BBF081FCB446400580909 /* otctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = otctl; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -11814,9 +11773,7 @@ 0CB582C72189153A0040C5F2 /* OTBottle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTBottle.h; sourceTree = ""; }; 0CB8DC962194B1300021A7C8 /* OTVouchWithBottleOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTVouchWithBottleOperation.h; sourceTree = ""; }; 0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTVouchWithBottleOperation.m; sourceTree = ""; }; - 0CB975502023B199008D6B48 /* OTRampingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTRampingTests.m; sourceTree = ""; }; 0CBA047C214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonPairingTests+ProxMultiClients.swift"; sourceTree = ""; }; - 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerTLK.m; sourceTree = ""; }; 0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestsObjcTranslation.m; sourceTree = ""; }; 0CBEF3422242C9BE00015691 /* TestsObjcTranslation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestsObjcTranslation.h; sourceTree = ""; }; 0CC8A8FA2123A9EB005D7F6A /* OTClientVoucherOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientVoucherOperation.m; sourceTree = ""; }; @@ -11832,8 +11789,6 @@ 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = ""; }; 0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = ""; }; 0CD8D654207D6E65005CDBE8 /* SFAnalytics+Signin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Signin.h"; sourceTree = ""; }; - 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTContextRecord.m; sourceTree = ""; }; - 0CD9E8071FE05B8700F66C38 /* OTContextRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTContextRecord.h; sourceTree = ""; }; 0CDBCD8620AD03FB007F8EA7 /* OTClique.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClique.h; sourceTree = ""; }; 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTTriggerEscrowUpdateOperation.m; sourceTree = ""; }; 0CDD6F78226E62BC009094C2 /* OTTriggerEscrowUpdateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTTriggerEscrowUpdateOperation.h; sourceTree = ""; }; @@ -11845,10 +11800,6 @@ 0CE15E3B222DF6A700B7EAA4 /* Recovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Recovery.h; sourceTree = ""; }; 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Recovery.m; sourceTree = ""; }; 0CE15E3D222DF6A700B7EAA4 /* OTRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRecovery.h; sourceTree = ""; }; - 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerSigned.m; sourceTree = ""; }; - 0CE1BCCD1FCE11610017230E /* OTBottledPeerSigned.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerSigned.h; sourceTree = ""; }; - 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStoreState.m; sourceTree = ""; }; - 0CE407B31FD476E000F59B31 /* OTCloudStoreState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTCloudStoreState.h; sourceTree = ""; }; 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Expansion.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Expansion.m"; sourceTree = ""; }; 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Circle.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Circle.m"; sourceTree = ""; }; 0CE7604B1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Identity.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Identity.m"; sourceTree = ""; }; @@ -11878,6 +11829,8 @@ 1B8341B72239AD39002BF18A /* TPPBPolicyKeyViewMapping.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = TPPBPolicyKeyViewMapping.proto; sourceTree = ""; }; 1B995256226681ED00A2D6CD /* PolicyReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PolicyReporter.h; sourceTree = ""; }; 1B995258226681EE00A2D6CD /* PolicyReporter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PolicyReporter.m; sourceTree = ""; }; + 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CuttlefishXPCWrapper.m; sourceTree = ""; }; + 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CuttlefishXPCWrapper.h; sourceTree = ""; }; 1BC6F79621C9955D005ED67A /* util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = util.m; sourceTree = ""; }; 1BC6F79821C9955E005ED67A /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = policy_dryrun.m; sourceTree = ""; }; @@ -11930,7 +11883,7 @@ 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ProtectedCloudStorage.framework; path = System/Library/PrivateFrameworks/ProtectedCloudStorage.framework; sourceTree = SDKROOT; }; 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libcoreauthd_client.a; path = usr/local/lib/libcoreauthd_client.a; sourceTree = SDKROOT; }; 4432AF8C1A01472C000958DC /* libaks_acl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libaks_acl.a; path = usr/local/lib/libaks_acl.a; sourceTree = SDKROOT; }; - 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecAccessControl.h; path = ../../../keychain/SecAccessControl.h; sourceTree = ""; }; + 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecAccessControl.h; path = keychain/headers/SecAccessControl.h; sourceTree = ""; }; 443381DA18A3D81400215606 /* SecAccessControlPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecAccessControlPriv.h; sourceTree = ""; }; 4469FBDC1AA0A45C0021AA26 /* libctkclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_test.a; path = usr/local/lib/libctkclient_test.a; sourceTree = SDKROOT; }; 4469FBDD1AA0A45C0021AA26 /* libctkclient_sep.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_sep.a; path = usr/local/lib/libctkclient_sep.a; sourceTree = SDKROOT; }; @@ -12065,6 +12018,8 @@ 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingRecovery.m; sourceTree = ""; }; 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingRecovery.h; sourceTree = ""; }; 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRecovery.m; sourceTree = ""; }; + 48AC7B5C232B1A1700F02B6F /* SOSIntervalEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSIntervalEvent.h; sourceTree = ""; }; + 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSIntervalEvent.m; sourceTree = ""; }; 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = accountCirclesViewsPrint.m; sourceTree = ""; }; 48C2F9331E4BCFC30093D70C /* accountCirclesViewsPrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = accountCirclesViewsPrint.h; sourceTree = ""; }; 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-66-account-recovery.m"; sourceTree = ""; }; @@ -12085,7 +12040,7 @@ 4C04A90811924BBC0020550C /* SecKeyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecKeyInternal.h; sourceTree = ""; }; 4C079EBC1794A96200D73970 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/PrivateFrameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 4C0B906C0ACCBD240077CD03 /* SecFramework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFramework.h; sourceTree = ""; }; - 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettingsPriv.h; path = trust/SecTrustSettingsPriv.h; sourceTree = ""; }; + 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettingsPriv.h; path = trust/headers/SecTrustSettingsPriv.h; sourceTree = ""; }; 4C198F1E0ACDB4BF00AAB142 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/Certificate.strings; sourceTree = ""; }; 4C198F200ACDB4BF00AAB142 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/OID.strings; sourceTree = ""; usesTabs = 1; }; 4C1B442C0BB9CAF900461B82 /* SecTrustStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustStore.h; sourceTree = ""; }; @@ -12104,7 +12059,7 @@ 4C3CECF21416E20400947741 /* DigiNotar_Root_CA_G2-RootCertificate.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "DigiNotar_Root_CA_G2-RootCertificate.crt"; sourceTree = ""; }; 4C3DD6AE179755560093F9D8 /* NSDate+TimeIntervalDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+TimeIntervalDescription.h"; sourceTree = ""; }; 4C3DD6AF179755560093F9D8 /* NSDate+TimeIntervalDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+TimeIntervalDescription.m"; sourceTree = ""; }; - 4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/SecTrustSettings.h; sourceTree = ""; }; + 4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/headers/SecTrustSettings.h; sourceTree = ""; }; 4C465C7D13AFD82300E841AC /* SecurityDevTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityDevTests-Info.plist"; sourceTree = ""; }; 4C47FA8D20A51DC700384CB6 /* AppleFSCompression.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleFSCompression.framework; path = System/Library/PrivateFrameworks/AppleFSCompression.framework; sourceTree = SDKROOT; }; 4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; @@ -12131,27 +12086,27 @@ 4C52D0E416EFCCA20079966E /* com.apple.security.CircleJoinRequested.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.security.CircleJoinRequested.plist; sourceTree = ""; }; 4C52D0E516EFCCA20079966E /* NSArray+map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+map.h"; sourceTree = ""; }; 4C52D0E616EFCCA20079966E /* NSArray+map.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+map.m"; sourceTree = ""; }; - 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyPriv.h; path = trust/SecPolicyPriv.h; sourceTree = ""; }; + 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyPriv.h; path = trust/headers/SecPolicyPriv.h; sourceTree = ""; }; 4C6416F00BB357D5001C83FD /* SecInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecInternal.h; path = base/SecInternal.h; sourceTree = ""; }; 4C64E00B0B8FBBF3009B306C /* Security.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Security.h; path = base/Security.h; sourceTree = ""; }; 4C696B3709BFA94F000CBC75 /* SecBase.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = SecBase.h; path = base/SecBase.h; sourceTree = ""; }; - 4C7072840AC9EA4E007CC205 /* SecKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKey.h; path = keychain/SecKey.h; sourceTree = ""; }; - 4C7072D30AC9ED5A007CC205 /* SecKeyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKeyPriv.h; path = keychain/SecKeyPriv.h; sourceTree = ""; }; + 4C7072840AC9EA4E007CC205 /* SecKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKey.h; path = keychain/headers/SecKey.h; sourceTree = ""; }; + 4C7072D30AC9ED5A007CC205 /* SecKeyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKeyPriv.h; path = keychain/headers/SecKeyPriv.h; sourceTree = ""; }; 4C7073C80ACB2BAD007CC205 /* SecRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRSAKey.h; sourceTree = ""; }; 4C711D7613AFCD0900FE865D /* SecurityDevTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecurityDevTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4C7391770B01745000C4CBFA /* vmdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmdh.h; sourceTree = ""; }; 4C7416020F1D71A2008E0E4D /* SecSCEP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecSCEP.h; sourceTree = ""; }; - 4C7608B10AC34A8100980096 /* SecCertificatePriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificatePriv.h; path = trust/SecCertificatePriv.h; sourceTree = ""; }; + 4C7608B10AC34A8100980096 /* SecCertificatePriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificatePriv.h; path = trust/headers/SecCertificatePriv.h; sourceTree = ""; }; 4C7913241799A5CB00A9633E /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 4C7CE56E0DC7DB0A00AE53FC /* SecEntitlements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecEntitlements.h; sourceTree = ""; }; 4C84DA541720698900AEE225 /* AppleAccount.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleAccount.framework; path = System/Library/PrivateFrameworks/AppleAccount.framework; sourceTree = SDKROOT; }; 4C84DA6217207E8D00AEE225 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; - 4C87F3A70D611C26000E7104 /* SecTrustPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustPriv.h; path = trust/SecTrustPriv.h; sourceTree = ""; }; + 4C87F3A70D611C26000E7104 /* SecTrustPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustPriv.h; path = trust/headers/SecTrustPriv.h; sourceTree = ""; }; 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudServices.framework; path = System/Library/PrivateFrameworks/CloudServices.framework; sourceTree = SDKROOT; }; 4C8B91C51416EB6A00A254E2 /* Invalid-webmail.portofamsterdam.nl.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-webmail.portofamsterdam.nl.crt"; sourceTree = ""; }; 4C8E99C20FC601D50072EB4C /* SecFrameworkStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFrameworkStrings.h; sourceTree = ""; }; - 4C8FD03D099D5C91006867B6 /* SecCertificate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificate.h; path = trust/SecCertificate.h; sourceTree = ""; }; - 4C8FD03E099D5C91006867B6 /* SecTrust.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecTrust.h; path = trust/SecTrust.h; sourceTree = ""; }; + 4C8FD03D099D5C91006867B6 /* SecCertificate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificate.h; path = trust/headers/SecCertificate.h; sourceTree = ""; }; + 4C8FD03E099D5C91006867B6 /* SecTrust.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecTrust.h; path = trust/headers/SecTrust.h; sourceTree = ""; }; 4C999BA10AB5F0BB0010451D /* NtlmGenerator.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = NtlmGenerator.c; sourceTree = ""; }; 4C999BA20AB5F0BB0010451D /* NtlmGenerator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NtlmGenerator.h; sourceTree = ""; }; 4C999BA30AB5F0BB0010451D /* ntlmBlobPriv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ntlmBlobPriv.c; sourceTree = ""; }; @@ -12163,17 +12118,17 @@ 4CA880C20DDBC87200D9A0F2 /* sslServer-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "sslServer-entitlements.plist"; sourceTree = ""; }; 4CA880C30DDBC87200D9A0F2 /* sslViewer-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "sslViewer-entitlements.plist"; sourceTree = ""; }; 4CAB97FD1114CC5300EFB38D /* README.keychain */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.keychain; sourceTree = ""; }; - 4CAC87D60B8F82720009C9FC /* SecIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentity.h; path = keychain/SecIdentity.h; sourceTree = ""; }; + 4CAC87D60B8F82720009C9FC /* SecIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentity.h; path = keychain/headers/SecIdentity.h; sourceTree = ""; }; 4CB7405F0A47498100D641BB /* Security.exp-in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "Security.exp-in"; sourceTree = ""; }; 4CB740680A4749C800D641BB /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; 4CB740A30A47567C00D641BB /* security */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = security; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CBA0E860BB33C0000E72B55 /* SecPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicy.h; path = trust/SecPolicy.h; sourceTree = ""; }; + 4CBA0E860BB33C0000E72B55 /* SecPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicy.h; path = trust/headers/SecPolicy.h; sourceTree = ""; }; 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 4CC3D28F178F310B0070FCC4 /* PersistentState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersistentState.h; sourceTree = ""; }; 4CC3D290178F310C0070FCC4 /* PersistentState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PersistentState.m; sourceTree = ""; }; 4CC92ABA15A3B3D900C6D578 /* testlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = testlist.h; sourceTree = ""; }; 4CC92B1B15A3BF2F00C6D578 /* testmain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testmain.c; sourceTree = ""; }; - 4CCE0AD90D41797400DDBB21 /* SecIdentityPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentityPriv.h; path = keychain/SecIdentityPriv.h; sourceTree = ""; }; + 4CCE0AD90D41797400DDBB21 /* SecIdentityPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentityPriv.h; path = keychain/headers/SecIdentityPriv.h; sourceTree = ""; }; 4CCE0AE10D417A2700DDBB21 /* sslAppUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslAppUtils.h; sourceTree = ""; }; 4CD3BA601106FF4D00BE8B75 /* SecECKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecECKey.h; sourceTree = ""; }; 4CE5A54D09C796E200D27A3F /* sslViewer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sslViewer; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -12190,8 +12145,8 @@ 4CE7EA561AEAE8D60067F5BD /* SecItemBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemBackup.h; sourceTree = ""; }; 4CEDF7370F3A6CFB0027C4FE /* SecItemInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemInternal.h; sourceTree = ""; }; 4CEF4CA70C5551FE00062475 /* SecCertificateInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateInternal.h; sourceTree = ""; }; - 4CF0484A0A5D988F00268236 /* SecItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecItem.h; path = keychain/SecItem.h; sourceTree = ""; }; - 4CF0487F0A5F016300268236 /* SecItemPriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecItemPriv.h; path = keychain/SecItemPriv.h; sourceTree = ""; }; + 4CF0484A0A5D988F00268236 /* SecItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecItem.h; path = keychain/headers/SecItem.h; sourceTree = ""; }; + 4CF0487F0A5F016300268236 /* SecItemPriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecItemPriv.h; path = keychain/headers/SecItemPriv.h; sourceTree = ""; }; 4CF4C19C171E0EA600877419 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; 4CF730310EF9CDE300E17471 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 4CFBF5F10D5A92E100969BBE /* SecPolicyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPolicyInternal.h; sourceTree = ""; }; @@ -12248,8 +12203,8 @@ 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; }; 5EBE247A1B00CCAE0007DB0E /* secacltests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secacltests; sourceTree = BUILT_PRODUCTS_DIR; }; 5EBE247C1B00CCAE0007DB0E /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; - 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExportPriv.h; path = keychain/SecImportExportPriv.h; sourceTree = ""; }; - 5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecTrustExceptionResetCount.m; path = OSX/sec/securityd/SecTrustExceptionResetCount.m; sourceTree = ""; }; + 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExportPriv.h; path = keychain/headers/SecImportExportPriv.h; sourceTree = ""; }; + 5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecTrustExceptionResetCount.m; sourceTree = ""; }; 617570BA22C2D19E00EFBA37 /* Security.macOS.private.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = Security.macOS.private.modulemap; path = Modules/Security.macOS.private.modulemap; sourceTree = ""; }; 6C02134C21F7ED16009D5C80 /* SecDbBackupTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = SecDbBackupTests.plist; path = tests/SecDbBackupTests/SecDbBackupTests.plist; sourceTree = SOURCE_ROOT; }; 6C02134D21F7ED16009D5C80 /* SecDbBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecDbBackupTests.m; path = tests/SecDbBackupTests/SecDbBackupTests.m; sourceTree = SOURCE_ROOT; }; @@ -12385,14 +12340,14 @@ 790851B60CA9859F0083CC4D /* securityd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = securityd; sourceTree = BUILT_PRODUCTS_DIR; }; 7913B1DF0D17280500601FE9 /* sslServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sslServer.cpp; sourceTree = ""; }; 7913B2110D172B3900601FE9 /* sslServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sslServer; sourceTree = BUILT_PRODUCTS_DIR; }; - 791766DD0DD0162C00F3B974 /* SecCertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateRequest.h; path = trust/SecCertificateRequest.h; sourceTree = ""; }; + 791766DD0DD0162C00F3B974 /* SecCertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateRequest.h; path = trust/headers/SecCertificateRequest.h; sourceTree = ""; }; 7940D4110C3ACF9000FDB5D8 /* SecDH.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecDH.h; sourceTree = ""; }; 794743191462137C00D638A3 /* Invalid-www.cybersecurity.my.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-www.cybersecurity.my.crt"; sourceTree = ""; }; 7947431C146214E500D638A3 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Digisign-Server-ID-Enrich-GTETrust-Cert.crt"; sourceTree = ""; }; 795CA9CC0D38435E00BAE6A2 /* p12pbegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = p12pbegen.h; sourceTree = ""; }; 79679E251462028800CF997F /* Digisign-Server-ID-Enrich-Entrust-Cert.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Digisign-Server-ID-Enrich-Entrust-Cert.crt"; sourceTree = ""; }; 79679E261462028800CF997F /* Invalid-webmail.jaring.my.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-webmail.jaring.my.crt"; sourceTree = ""; }; - 79EF5B6C0D3D6A31009F5270 /* SecImportExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExport.h; path = keychain/SecImportExport.h; sourceTree = ""; }; + 79EF5B6C0D3D6A31009F5270 /* SecImportExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExport.h; path = keychain/headers/SecImportExport.h; sourceTree = ""; }; 79EF5B720D3D6AFE009F5270 /* p12import.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = p12import.h; sourceTree = ""; }; 8E02FA691107BE460043545E /* pbkdf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pbkdf2.h; sourceTree = ""; }; 8E64DB4C1C17CD3F0076C9DF /* com.apple.security.cloudkeychainproxy3.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.cloudkeychainproxy3.ios.plist; path = KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.ios.plist; sourceTree = ""; }; @@ -12416,7 +12371,7 @@ B61577EE1F2021BC004A3930 /* padding-00-mmcs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "padding-00-mmcs.c"; sourceTree = ""; }; B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecPaddingConfigurationsPriv.h; sourceTree = ""; }; B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecPaddingConfigurations.c; sourceTree = ""; }; - BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSharedCredential.h; path = ../../../keychain/SecSharedCredential.h; sourceTree = ""; }; + BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSharedCredential.h; path = keychain/headers/SecSharedCredential.h; sourceTree = ""; }; BE197F2619116FD100BA91D1 /* SharedWebCredentialViewService.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SharedWebCredentialViewService.app; sourceTree = BUILT_PRODUCTS_DIR; }; BE197F2919116FD100BA91D1 /* SharedWebCredentialViewService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SharedWebCredentialViewService-Info.plist"; sourceTree = ""; }; BE197F2B19116FD100BA91D1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -12436,8 +12391,6 @@ BE22FBD01EE2084100893431 /* Config.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Config.m; path = manifeststresstest/Config.m; sourceTree = ""; }; BE22FBFC1EE23D9100893431 /* mark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = mark.m; path = manifeststresstest/mark.m; sourceTree = ""; }; BE22FC031EE23DA600893431 /* mark.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mark.h; path = manifeststresstest/mark.h; sourceTree = ""; }; - BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerRecord.h; sourceTree = ""; }; - BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerRecord.m; sourceTree = ""; }; BE442BC118B7FDB800F24DAE /* swcagent */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = swcagent; sourceTree = BUILT_PRODUCTS_DIR; }; BE4AC9A118B7FFAD00B84964 /* swcagent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = swcagent.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; BE4AC9AD18B7FFC800B84964 /* com.apple.security.swcagent.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.swcagent.plist; sourceTree = ""; }; @@ -12575,12 +12528,12 @@ D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleiPhoneDeviceCACertificates.h; sourceTree = ""; }; D4119E72202BDF2B0048587B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; D41257CF1E9410A300781F23 /* trustd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trustd; sourceTree = BUILT_PRODUCTS_DIR; }; - D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.agent.plist; path = OSX/trustd/macOS/com.apple.trustd.agent.plist; sourceTree = ""; }; - D41257EA1E941CF200781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/macOS/com.apple.trustd.plist; sourceTree = ""; }; - D41257EB1E941CF200781F23 /* com.apple.trustd.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.trustd.sb; path = OSX/trustd/macOS/com.apple.trustd.sb; sourceTree = ""; }; - D41257EC1E941CF200781F23 /* trustd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = trustd.8; path = OSX/trustd/macOS/trustd.8; sourceTree = ""; }; - D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = OSX/trustd/macOS/SecTrustOSXEntryPoints.h; sourceTree = SOURCE_ROOT; }; - D41257EE1E941DA800781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/iOS/com.apple.trustd.plist; sourceTree = ""; }; + D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.trustd.agent.plist; sourceTree = ""; }; + D41257EA1E941CF200781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.trustd.plist; sourceTree = ""; }; + D41257EB1E941CF200781F23 /* com.apple.trustd.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.apple.trustd.sb; sourceTree = ""; }; + D41257EC1E941CF200781F23 /* trustd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = trustd.8; sourceTree = ""; }; + D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = trust/trustd/macOS/SecTrustOSXEntryPoints.h; sourceTree = SOURCE_ROOT; }; + D41257EE1E941DA800781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.trustd.plist; sourceTree = ""; }; D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libDiagnosticMessagesClient.tbd; path = usr/lib/libDiagnosticMessagesClient.tbd; sourceTree = SDKROOT; }; D42C838721158B3F008D3D83 /* cmsreclist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmsreclist.h; path = libsecurity_smime/lib/cmsreclist.h; sourceTree = SOURCE_ROOT; }; D42C838821158B40008D3D83 /* SecAsn1Item.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecAsn1Item.c; path = libsecurity_smime/lib/SecAsn1Item.c; sourceTree = SOURCE_ROOT; }; @@ -12642,49 +12595,49 @@ D43718BE21168BCC00EA350A /* libsecurity_cms.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = libsecurity_cms.txt; path = OSX/libsecurity_smime/docs/libsecurity_cms.txt; sourceTree = ""; }; D43718BF21168BCD00EA350A /* libsecurity_cms.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = libsecurity_cms.plist; path = OSX/libsecurity_smime/docs/libsecurity_cms.plist; sourceTree = ""; }; D43718C721168D7C00EA350A /* SecSMIME.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSMIME.h; path = CMS/SecSMIME.h; sourceTree = ""; }; - D43761641EB2996C00954447 /* SecRevocationNetworking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecRevocationNetworking.h; path = OSX/sec/securityd/SecRevocationNetworking.h; sourceTree = ""; }; - D43761651EB2996C00954447 /* SecRevocationNetworking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecRevocationNetworking.m; path = OSX/sec/securityd/SecRevocationNetworking.m; sourceTree = ""; }; - D43DBED71E99D17100C04AEA /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nameconstraints.c; path = OSX/sec/securityd/nameconstraints.c; sourceTree = ""; }; - D43DBED81E99D17100C04AEA /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nameconstraints.h; path = OSX/sec/securityd/nameconstraints.h; sourceTree = ""; }; - D43DBED91E99D17100C04AEA /* OTATrustUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OTATrustUtilities.m; path = OSX/sec/securityd/OTATrustUtilities.m; sourceTree = ""; }; - D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OTATrustUtilities.h; path = OSX/sec/securityd/OTATrustUtilities.h; sourceTree = ""; }; - D43DBEDB1E99D17100C04AEA /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = personalization.c; path = OSX/sec/securityd/personalization.c; sourceTree = ""; }; - D43DBEDC1E99D17100C04AEA /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = personalization.h; path = OSX/sec/securityd/personalization.h; sourceTree = ""; }; - D43DBEDD1E99D17100C04AEA /* policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = policytree.c; path = OSX/sec/securityd/policytree.c; sourceTree = ""; }; - D43DBEDE1E99D17200C04AEA /* policytree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = policytree.h; path = OSX/sec/securityd/policytree.h; sourceTree = ""; }; - D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCAIssuerCache.c; path = OSX/sec/securityd/SecCAIssuerCache.c; sourceTree = ""; }; - D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerCache.h; path = OSX/sec/securityd/SecCAIssuerCache.h; sourceTree = ""; }; - D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecCAIssuerRequest.m; path = OSX/sec/securityd/SecCAIssuerRequest.m; sourceTree = ""; }; - D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerRequest.h; path = OSX/sec/securityd/SecCAIssuerRequest.h; sourceTree = ""; }; - D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateServer.c; path = OSX/sec/securityd/SecCertificateServer.c; sourceTree = ""; }; - D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateServer.h; path = OSX/sec/securityd/SecCertificateServer.h; sourceTree = ""; }; - D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateSource.c; path = OSX/sec/securityd/SecCertificateSource.c; sourceTree = ""; }; - D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateSource.h; path = OSX/sec/securityd/SecCertificateSource.h; sourceTree = ""; }; - D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPCache.c; path = OSX/sec/securityd/SecOCSPCache.c; sourceTree = ""; }; - D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPCache.h; path = OSX/sec/securityd/SecOCSPCache.h; sourceTree = ""; }; - D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPRequest.c; path = OSX/sec/securityd/SecOCSPRequest.c; sourceTree = ""; }; - D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPRequest.h; path = OSX/sec/securityd/SecOCSPRequest.h; sourceTree = ""; }; - D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPResponse.c; path = OSX/sec/securityd/SecOCSPResponse.c; sourceTree = ""; }; - D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPResponse.h; path = OSX/sec/securityd/SecOCSPResponse.h; sourceTree = ""; }; - D43DBEED1E99D17200C04AEA /* SecPinningDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPinningDb.h; path = OSX/sec/securityd/SecPinningDb.h; sourceTree = ""; }; - D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecPinningDb.m; path = OSX/sec/securityd/SecPinningDb.m; sourceTree = ""; }; - D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecPolicyServer.c; path = OSX/sec/securityd/SecPolicyServer.c; sourceTree = ""; }; - D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyServer.h; path = OSX/sec/securityd/SecPolicyServer.h; sourceTree = ""; }; - D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationDb.c; path = OSX/sec/securityd/SecRevocationDb.c; sourceTree = ""; }; - D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationDb.h; path = OSX/sec/securityd/SecRevocationDb.h; sourceTree = ""; }; - D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationServer.c; path = OSX/sec/securityd/SecRevocationServer.c; sourceTree = ""; }; - D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationServer.h; path = OSX/sec/securityd/SecRevocationServer.h; sourceTree = ""; }; - D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecTrustLoggingServer.m; path = OSX/sec/securityd/SecTrustLoggingServer.m; sourceTree = ""; }; - D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustLoggingServer.h; path = OSX/sec/securityd/SecTrustLoggingServer.h; sourceTree = ""; }; - D43DBEF71E99D17300C04AEA /* SecTrustServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustServer.c; path = OSX/sec/securityd/SecTrustServer.c; sourceTree = ""; }; - D43DBEF81E99D17300C04AEA /* SecTrustServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustServer.h; path = OSX/sec/securityd/SecTrustServer.h; sourceTree = ""; }; - D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustStoreServer.c; path = OSX/sec/securityd/SecTrustStoreServer.c; sourceTree = ""; }; - D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = ""; }; + D43761641EB2996C00954447 /* SecRevocationNetworking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRevocationNetworking.h; sourceTree = ""; }; + D43761651EB2996C00954447 /* SecRevocationNetworking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecRevocationNetworking.m; sourceTree = ""; }; + D43DBED71E99D17100C04AEA /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nameconstraints.c; sourceTree = ""; }; + D43DBED81E99D17100C04AEA /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nameconstraints.h; sourceTree = ""; }; + D43DBED91E99D17100C04AEA /* OTATrustUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTATrustUtilities.m; sourceTree = ""; }; + D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTATrustUtilities.h; sourceTree = ""; }; + D43DBEDB1E99D17100C04AEA /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = personalization.c; sourceTree = ""; }; + D43DBEDC1E99D17100C04AEA /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = personalization.h; sourceTree = ""; }; + D43DBEDD1E99D17100C04AEA /* policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = policytree.c; sourceTree = ""; }; + D43DBEDE1E99D17200C04AEA /* policytree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policytree.h; sourceTree = ""; }; + D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCAIssuerCache.c; sourceTree = ""; }; + D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerCache.h; sourceTree = ""; }; + D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecCAIssuerRequest.m; sourceTree = ""; }; + D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerRequest.h; sourceTree = ""; }; + D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateServer.c; sourceTree = ""; }; + D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateServer.h; sourceTree = ""; }; + D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateSource.c; sourceTree = ""; }; + D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateSource.h; sourceTree = ""; }; + D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPCache.c; sourceTree = ""; }; + D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPCache.h; sourceTree = ""; }; + D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPRequest.c; sourceTree = ""; }; + D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPRequest.h; sourceTree = ""; }; + D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPResponse.c; sourceTree = ""; }; + D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPResponse.h; sourceTree = ""; }; + D43DBEED1E99D17200C04AEA /* SecPinningDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPinningDb.h; sourceTree = ""; }; + D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecPinningDb.m; sourceTree = ""; }; + D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecPolicyServer.c; sourceTree = ""; }; + D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPolicyServer.h; sourceTree = ""; }; + D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecRevocationDb.c; sourceTree = ""; }; + D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRevocationDb.h; sourceTree = ""; }; + D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecRevocationServer.c; sourceTree = ""; }; + D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRevocationServer.h; sourceTree = ""; }; + D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecTrustLoggingServer.m; sourceTree = ""; }; + D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustLoggingServer.h; sourceTree = ""; }; + D43DBEF71E99D17300C04AEA /* SecTrustServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustServer.c; sourceTree = ""; }; + D43DBEF81E99D17300C04AEA /* SecTrustServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustServer.h; sourceTree = ""; }; + D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustStoreServer.c; sourceTree = ""; }; + D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustStoreServer.h; sourceTree = ""; }; D43DDE511F620F09009742A5 /* SecPolicyChecks.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicyChecks.list; sourceTree = ""; }; D43DDE581F638061009742A5 /* SecPolicy.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicy.list; sourceTree = ""; }; D44282FE22D68556001746B3 /* TrustEvaluationTestHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustEvaluationTestHelpers.m; path = tests/TrustTests/TrustEvaluationTestHelpers.m; sourceTree = ""; }; - D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA2.cer; path = OSX/trustd/iOS/AppleCorporateRootCA2.cer; sourceTree = ""; }; - D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA.cer; path = OSX/trustd/iOS/AppleCorporateRootCA.cer; sourceTree = ""; }; + D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = AppleCorporateRootCA2.cer; sourceTree = ""; }; + D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = AppleCorporateRootCA.cer; sourceTree = ""; }; D44D08B420AB890E0023C439 /* Security.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Security.apinotes; path = base/Security.apinotes; sourceTree = ""; }; D44D1F662115893000E76E1A /* libCMS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCMS.a; sourceTree = BUILT_PRODUCTS_DIR; }; D44D1F8321158AAB00E76E1A /* plhash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = plhash.h; path = libsecurity_smime/lib/plhash.h; sourceTree = SOURCE_ROOT; }; @@ -12696,8 +12649,8 @@ D44D1F8921158AAE00E76E1A /* cmsreclist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cmsreclist.c; path = libsecurity_smime/lib/cmsreclist.c; sourceTree = SOURCE_ROOT; }; D44D1F8A21158AAF00E76E1A /* cmsencode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cmsencode.c; path = libsecurity_smime/lib/cmsencode.c; sourceTree = SOURCE_ROOT; }; D44D1F8B21158AAF00E76E1A /* secoidt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = secoidt.h; path = libsecurity_smime/lib/secoidt.h; sourceTree = SOURCE_ROOT; }; - D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = ""; }; - D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = ""; }; + D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; + D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; D453A4C02122236D00850A26 /* TrustTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrustTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D453C38A1FEC669300DE349B /* trust_update.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = trust_update.m; sourceTree = ""; }; D453C47F1FFD857400DE349B /* security_tool_commands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = security_tool_commands.h; sourceTree = ""; }; @@ -12731,7 +12684,7 @@ D458C51B214E2CFF0043D982 /* si-20-sectrust-policies-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-20-sectrust-policies-data"; path = "OSX/shared_regressions/si-20-sectrust-policies-data"; sourceTree = ""; }; D458C51E214E2E0C0043D982 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Main.storyboard; path = tests/TrustTests/TestRunners/Main.storyboard; sourceTree = ""; }; D46246911F9AE2E400D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; - D46246A21F9AE49E00D63882 /* oids.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = oids.h; path = trust/oids.h; sourceTree = ""; }; + D46246A21F9AE49E00D63882 /* oids.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = oids.h; path = trust/headers/oids.h; sourceTree = ""; }; D46246A91F9AE6C900D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; D46246AF1F9AE73F00D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; D46246C31F9AEA5200D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; @@ -12758,8 +12711,8 @@ D48BD195206C476B0075DDC9 /* si-35-cms-expiration-time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-35-cms-expiration-time.h"; sourceTree = ""; }; D48F029B1EA1671B00ACC3C9 /* si-61-pkcs12.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-61-pkcs12.h"; sourceTree = ""; }; D4911167209558900066A1E4 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustURLSessionDelegate.m; path = OSX/sec/securityd/TrustURLSessionDelegate.m; sourceTree = ""; }; - D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TrustURLSessionDelegate.h; path = OSX/sec/securityd/TrustURLSessionDelegate.h; sourceTree = ""; }; + D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TrustURLSessionDelegate.m; sourceTree = ""; }; + D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TrustURLSessionDelegate.h; sourceTree = ""; }; D4A0F8BA211E69CB00443CA1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = tests/TrustTests/Info.plist; sourceTree = ""; }; D4A0F8BB211E69CB00443CA1 /* TestMacroConversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMacroConversions.h; path = tests/TrustTests/TestMacroConversions.h; sourceTree = ""; }; D4A0F8C1211E6A2F00443CA1 /* si-82-sectrust-ct-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-82-sectrust-ct-data"; path = "OSX/shared_regressions/si-82-sectrust-ct-data"; sourceTree = ""; }; @@ -12783,7 +12736,7 @@ D4AC5769214E195400A32C01 /* KeySizeTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = KeySizeTests_data.h; path = tests/TrustTests/EvaluationTests/KeySizeTests_data.h; sourceTree = ""; }; D4AC8BE721320AD0006E9871 /* CertificateParseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CertificateParseTests.m; path = tests/TrustTests/FrameworkTests/CertificateParseTests.m; sourceTree = ""; }; D4AC8BED2132127A006E9871 /* si-18-certificate-parse */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-18-certificate-parse"; path = "OSX/shared_regressions/si-18-certificate-parse"; sourceTree = ""; }; - D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "trustd-Info.plist"; path = "OSX/trustd/trustd-Info.plist"; sourceTree = ""; }; + D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "trustd-Info.plist"; sourceTree = ""; }; D4ADA3191E2B41670031CEA3 /* libtrustd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtrustd.a; sourceTree = BUILT_PRODUCTS_DIR; }; D4B2966822DBFDB100DCF250 /* TestCopyProperties_ios-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "TestCopyProperties_ios-data"; path = "tests/TrustTests/TestData/TestCopyProperties_ios-data"; sourceTree = ""; }; D4B3B1CB2115149C00A43409 /* SecCmsDigestedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsDigestedData.h; path = CMS/SecCmsDigestedData.h; sourceTree = ""; }; @@ -12793,12 +12746,12 @@ D4B3B1D721151B9900A43409 /* SecCmsSignedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsSignedData.h; path = CMS/SecCmsSignedData.h; sourceTree = ""; }; D4B3B1DA2115293300A43409 /* SecCmsSignerInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsSignerInfo.h; path = CMS/SecCmsSignerInfo.h; sourceTree = ""; }; D4B68C5C211A7D98009FED69 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; - D4B68C64211A8186009FED69 /* trustd_spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = trustd_spi.h; path = OSX/trustd/trustd_spi.h; sourceTree = ""; }; - D4B68C65211A8186009FED69 /* trustd_spi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = trustd_spi.c; path = OSX/trustd/trustd_spi.c; sourceTree = ""; }; + D4B68C64211A8186009FED69 /* trustd_spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trustd_spi.h; sourceTree = ""; }; + D4B68C65211A8186009FED69 /* trustd_spi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = trustd_spi.c; sourceTree = ""; }; D4B6D57B2069D8450099FBEF /* si-34-cms-timestamp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-34-cms-timestamp.m"; sourceTree = ""; }; D4B6D5822069D85B0099FBEF /* si-34-cms-timestamp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-34-cms-timestamp.h"; sourceTree = ""; }; D4B858661D370D9A003B2D95 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; - D4BEECE61E93093A00F76D1A /* trustd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trustd.c; path = OSX/trustd/trustd.c; sourceTree = ""; }; + D4BEECE61E93093A00F76D1A /* trustd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trustd.c; sourceTree = ""; }; D4C263C51F8FF2A9001317EA /* generateErrStrings.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = generateErrStrings.pl; path = OSX/lib/generateErrStrings.pl; sourceTree = ""; usesTabs = 1; }; D4C263C81F952E64001317EA /* SecDebugErrorMessages.strings */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; fileEncoding = 10; name = SecDebugErrorMessages.strings; path = derived_src/SecDebugErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; D4C263CD1F952F6C001317EA /* SecErrorMessages.strings */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = SecErrorMessages.strings; path = derived_src/en.lproj/SecErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -12844,7 +12797,7 @@ D4D92DA72278904F0009A7CF /* nist-certs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "nist-certs"; path = "SecurityTests/nist-certs"; sourceTree = ""; }; D4EA5CF622B225C000883439 /* LoggingServerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LoggingServerTests.m; path = tests/TrustTests/DaemonTests/LoggingServerTests.m; sourceTree = ""; }; D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-20-sectrust-policies-data"; path = "../OSX/shared_regressions/si-20-sectrust-policies-data"; sourceTree = ""; }; - D4EF321E215F0F76000A31A5 /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecTrustStoreServer.m; path = OSX/sec/securityd/SecTrustStoreServer.m; sourceTree = ""; }; + D4EF321E215F0F76000A31A5 /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecTrustStoreServer.m; sourceTree = ""; }; D4EF3222215F102F000A31A5 /* CTTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CTTests_data.h; path = tests/TrustTests/EvaluationTests/CTTests_data.h; sourceTree = ""; }; D4FC521C1EC3E05B00E99785 /* smime_attr_emails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = smime_attr_emails.h; sourceTree = ""; }; D4FD421B217D7891002B7EE2 /* NameConstraintsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = NameConstraintsTests.m; path = tests/TrustTests/EvaluationTests/NameConstraintsTests.m; sourceTree = ""; }; @@ -12857,6 +12810,7 @@ DA30D6781DF8C8FB00EC6B43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DA30D6831DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeychainSyncAccountUpdater.h; sourceTree = ""; }; DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeychainSyncAccountUpdater.m; sourceTree = ""; }; + DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPStringTableTests.m; sourceTree = ""; }; DA41FE0E2241ADC000838FB3 /* otpaird */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = otpaird; sourceTree = BUILT_PRODUCTS_DIR; }; DA41FE192241AF3E00838FB3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; DA4586572245AEDA0073F993 /* OTPairingService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTPairingService.h; sourceTree = ""; }; @@ -12867,6 +12821,8 @@ DA5B871B2065A8430093F083 /* SecAutorelease.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecAutorelease.m; sourceTree = ""; }; DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSControlServer.m; sourceTree = ""; }; DA6AA1641FE88AFA004565B0 /* CKKSControlServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSControlServer.h; sourceTree = ""; }; + DA700FC62310C0DF0051A7DE /* TPStringTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPStringTable.h; sourceTree = ""; }; + DA700FC82310C0E00051A7DE /* TPStringTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPStringTable.m; sourceTree = ""; }; DAB27ADA1FA29EB700DEBBDE /* SOSControlServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSControlServer.h; sourceTree = ""; }; DAB27AE01FA29EB800DEBBDE /* SOSControlServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSControlServer.m; sourceTree = ""; }; DAC58D1C2244527E00D4CD41 /* OTPairingPacketContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPairingPacketContext.h; sourceTree = ""; }; @@ -13357,7 +13313,7 @@ DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFileLocations.h; sourceTree = ""; }; DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecXPCError.h; sourceTree = ""; }; DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecXPCError.c; sourceTree = ""; }; - DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = simulate_crash.c; sourceTree = ""; }; + DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = simulate_crash.m; sourceTree = ""; }; DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecSCTUtils.h; sourceTree = ""; }; DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecSCTUtils.c; sourceTree = ""; }; DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAppleAnchor.c; sourceTree = ""; }; @@ -13499,7 +13455,6 @@ DC1789041D77980500B50D50 /* Security.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Security.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libDiagnosticMessagesClient.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libDiagnosticMessagesClient.dylib; sourceTree = DEVELOPER_DIR; }; DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libOpenScriptingUtil.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libOpenScriptingUtil.dylib; sourceTree = DEVELOPER_DIR; }; - DC1789161D77998700B50D50 /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libauto.dylib; sourceTree = DEVELOPER_DIR; }; DC1789181D77998C00B50D50 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libbsm.dylib; sourceTree = DEVELOPER_DIR; }; DC17891C1D77999700B50D50 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libpam.dylib; sourceTree = DEVELOPER_DIR; }; DC17891E1D77999D00B50D50 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libsqlite3.dylib; sourceTree = DEVELOPER_DIR; }; @@ -13542,6 +13497,8 @@ DC19484B21812EC5007C2260 /* OTDeviceInformationAdapter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTDeviceInformationAdapter.m; sourceTree = ""; }; DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSScanLocalItemsOperation.h; sourceTree = ""; }; DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSScanLocalItemsOperation.m; sourceTree = ""; }; + DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSPeerProvider.h; sourceTree = ""; }; + DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSPeerProvider.m; sourceTree = ""; }; DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSItemEncrypter.m; sourceTree = ""; }; DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSItemEncrypter.h; sourceTree = ""; }; DC1ED8C21DD5538C002BDCFA /* CKKS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKS.h; sourceTree = ""; }; @@ -13649,7 +13606,6 @@ DC4DB15E1E2590B100CD6769 /* CKKSAESSIVEncryptionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSAESSIVEncryptionTests.m; sourceTree = ""; }; DC5060E920E2D88300925005 /* OTCuttlefishContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTCuttlefishContext.h; sourceTree = ""; }; DC5060EA20E2D88300925005 /* OTCuttlefishContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCuttlefishContext.m; sourceTree = ""; }; - DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCuttlefishContextTests.m; sourceTree = ""; }; DC5225091E402D8B0021640A /* PlatformLibraries.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = PlatformLibraries.xcconfig; path = xcconfig/PlatformLibraries.xcconfig; sourceTree = ""; }; DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurityd_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecureObjectSyncServer.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -15248,8 +15204,8 @@ DCE4E7CC1D7A4AED00AFB96E /* sectests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sectests; sourceTree = BUILT_PRODUCTS_DIR; }; DCE4E7E11D7A4B7F00AFB96E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = OSX/sectests/main.c; sourceTree = SOURCE_ROOT; }; DCE4E7F61D7A4DA800AFB96E /* secd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secd; sourceTree = BUILT_PRODUCTS_DIR; }; - DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.secd.plist; path = ../ipc/com.apple.secd.plist; sourceTree = ""; }; - DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.securityd.plist; path = OSX/sec/os_log/com.apple.securityd.plist; sourceTree = ""; }; + DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.secd.plist; sourceTree = ""; }; + DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.securityd.plist; sourceTree = ""; }; DCE4E8141D7A4E6F00AFB96E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; DCE4E81B1D7A4E8F00AFB96E /* libsqlite3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.0.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libsqlite3.0.dylib; sourceTree = DEVELOPER_DIR; }; DCE4E8271D7A4F0E00AFB96E /* login.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = login.framework; path = System/Library/PrivateFrameworks/login.framework; sourceTree = SDKROOT; }; @@ -15756,10 +15712,10 @@ E7FCBE411314471B000DE34E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; E7FCBE431314471B000DE34E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E7FCBE451314471B000DE34E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedStore.m; path = ../../../../keychain/SecureObjectSync/CKDSimulatedStore.m; sourceTree = ""; }; - E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedStore.h; path = ../../../../keychain/SecureObjectSync/CKDSimulatedStore.h; sourceTree = ""; }; - E7FE40C71DC8084600F0F5B6 /* CKDSimulatedAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedAccount.h; path = ../../../../keychain/SecureObjectSync/Regressions/CKDSimulatedAccount.h; sourceTree = ""; }; - E7FE40C81DC8084600F0F5B6 /* CKDSimulatedAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedAccount.m; path = ../../../../keychain/SecureObjectSync/Regressions/CKDSimulatedAccount.m; sourceTree = ""; }; + E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedStore.m; path = ../../SecureObjectSync/CKDSimulatedStore.m; sourceTree = ""; }; + E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedStore.h; path = ../../SecureObjectSync/CKDSimulatedStore.h; sourceTree = ""; }; + E7FE40C71DC8084600F0F5B6 /* CKDSimulatedAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedAccount.h; path = ../../SecureObjectSync/Regressions/CKDSimulatedAccount.h; sourceTree = ""; }; + E7FE40C81DC8084600F0F5B6 /* CKDSimulatedAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedAccount.m; path = ../../SecureObjectSync/Regressions/CKDSimulatedAccount.m; sourceTree = ""; }; E7FEFB80169E26E200E18152 /* sub_commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sub_commands.h; sourceTree = ""; }; EB056E401FE5E390000A771E /* SecRemoteDeviceProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRemoteDeviceProtocol.h; sourceTree = ""; }; EB056E411FE5E390000A771E /* SecRemoteDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRemoteDevice.h; sourceTree = ""; }; @@ -15792,6 +15748,9 @@ EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Security_edumode.plist; sourceTree = ""; }; EB3F9C9B21FCFC60007B6EBA /* OctagonTestHarness.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OctagonTestHarness.m; sourceTree = ""; }; EB3F9C9E21FCFF8E007B6EBA /* OctagonTestHarness.exp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.exports; path = OctagonTestHarness.exp; sourceTree = ""; }; + EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.trustedpeers.plist; sourceTree = ""; }; + EB3FBBF42320629400DF52EA /* SecABC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecABC.h; sourceTree = ""; }; + EB3FBBF52320629400DF52EA /* SecABC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecABC.m; sourceTree = ""; }; EB413B751E6624A400592085 /* PairingChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PairingChannel.h; sourceTree = ""; }; EB413B761E6624A500592085 /* PairingChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PairingChannel.m; sourceTree = ""; }; EB413B7E1E663A8300592085 /* KCPairingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCPairingTest.m; path = Tests/KCPairingTest.m; sourceTree = ""; }; @@ -15820,7 +15779,7 @@ EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecRecoveryKey.m; sourceTree = ""; }; EB6928C91D9C9D9D00062A18 /* rk_01_recoverykey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = rk_01_recoverykey.m; path = Regressions/rk_01_recoverykey.m; sourceTree = ""; }; EB6952B9223B75C300F02C1C /* secitemd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secitemd; sourceTree = BUILT_PRODUCTS_DIR; }; - EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.secitemd.plist; path = OSX/sec/ipc/com.apple.secitemd.plist; sourceTree = SOURCE_ROOT; }; + EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.secitemd.plist; sourceTree = ""; }; EB69AB091BF4347700913AF1 /* SecEMCSPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecEMCSPriv.h; sourceTree = ""; }; EB6AC0AA22F22E80003F067B /* SecTapToRadarTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecTapToRadarTests.m; sourceTree = ""; }; EB6D1D5322FE8D3000205E83 /* SecItemTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecItemTests.m; sourceTree = ""; }; @@ -15877,7 +15836,7 @@ EB82A2A41FAFF26900CA64A9 /* SFBehavior.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFBehavior.h; sourceTree = ""; }; EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFBehavior.m; sourceTree = ""; }; EB89088621F17D3C00F0DDDB /* recovery_securityd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = recovery_securityd; sourceTree = BUILT_PRODUCTS_DIR; }; - EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.recovery_securityd.plist; path = ../ipc/com.apple.recovery_securityd.plist; sourceTree = ""; }; + EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.recovery_securityd.plist; sourceTree = ""; }; EB89111020E3C15D00DE533F /* UserManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserManagement.framework; path = System/Library/PrivateFrameworks/UserManagement.framework; sourceTree = SDKROOT; }; EB9795B422FE90E6002BDBFB /* SecurityUnitTests.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecurityUnitTests.entitlements; sourceTree = ""; }; EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-37-pairing-initial-sync.m"; sourceTree = ""; }; @@ -17146,7 +17105,6 @@ DC65E7241D8CB29E00152EF0 /* libutilities.a in Frameworks */, DC1789131D7798B300B50D50 /* libDiagnosticMessagesClient.dylib in Frameworks */, DC1789281D779A0F00B50D50 /* libaks_acl.a in Frameworks */, - DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */, DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */, DC17892A1D779A3200B50D50 /* libcoreauthd_client.a in Frameworks */, DC3A81D61D99D57F000C7419 /* libcoretls.dylib in Frameworks */, @@ -17334,7 +17292,6 @@ DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */, DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */, BEE523DC1DACAA9200DD0AA3 /* libz.dylib in Frameworks */, - DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */, DC1002AF1D8E18870025549C /* libsecurity_codesigning.a in Frameworks */, DCB7D8D11D8E185900867385 /* libsecurity_utilities.a in Frameworks */, DCD22D6C1D8CC6FD001C9B81 /* libsecurityd_client.a in Frameworks */, @@ -18038,22 +17995,20 @@ buildActionMask = 2147483647; files = ( DC4A76AC221269E4006F2D8F /* CloudServices.framework in Frameworks */, - 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */, - EB80DE59219600DF005B10FA /* libz.tbd in Frameworks */, + EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */, DC3E18EB2125FB8700073D80 /* libaks_mock.a in Frameworks */, - 482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */, + EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */, + EB80DE59219600DF005B10FA /* libz.tbd in Frameworks */, EB49B2C2202DF002003F34A0 /* libDER.a in Frameworks */, - EB49B2BD202DEF29003F34A0 /* libSecureObjectSyncFramework.a in Frameworks */, + 482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */, + 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */, EB49B2BE202DEF29003F34A0 /* libSecureObjectSyncServer.a in Frameworks */, - EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */, - EB49B2BF202DEF67003F34A0 /* libsecurity.a in Frameworks */, EB49B2C1202DEF8D003F34A0 /* libASN1.a in Frameworks */, EB49B2C0202DEF7D003F34A0 /* libutilities.a in Frameworks */, EB49B308202FF421003F34A0 /* OCMock.framework in Frameworks */, EB49B2D2202DF17D003F34A0 /* SecurityFoundation.framework in Frameworks */, EB49B2CD202DF0F9003F34A0 /* SystemConfiguration.framework in Frameworks */, EB49B2C7202DF0E9003F34A0 /* IOKit.framework in Frameworks */, - EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */, EB49B2BC202DEF14003F34A0 /* libsqlite3.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -18247,10 +18202,8 @@ children = ( DCD33D7D220B9D98000A390B /* State Machine Machinery */, DC130B7920D04CFE0065CE61 /* Categories */, - DC68527220D04C6000C61368 /* Octagon via CK API */, DC68527120D04A5800C61368 /* Framework */, DC68527020D04A3200C61368 /* IPC */, - DC68526A20D04A1000C61368 /* Bottled Peers */, DCC67E2A20DDC05900A70A31 /* Operations */, 0CCCC7C720261D050024405E /* OT.h */, 0CCCC7C820261D310024405E /* OT.m */, @@ -18264,18 +18217,12 @@ 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */, DCC67E0C20DD7E0A00A70A31 /* OTStates.h */, DCC67E0D20DD7E0A00A70A31 /* OTStates.m */, - 0CD9E8071FE05B8700F66C38 /* OTContextRecord.h */, - 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */, 0C8BBE971FC9DA5A00580909 /* OTDefines.h */, EBCE06E521C6E26000FB1493 /* OTDefines.m */, 0C6604782134C86500BFBBB8 /* OTDeviceInformation.h */, 0C66047B2134C88C00BFBBB8 /* OTDeviceInformation.m */, 5A04BAF622973E43001848A0 /* OTFollowup.h */, 5A04BAF722973E43001848A0 /* OTFollowup.m */, - 0C8BBE8A1FC9DA5300580909 /* OTIdentity.h */, - 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */, - 0C8BBE8E1FC9DA5500580909 /* OTLocalStore.h */, - 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */, 0C8BBF101FCB486B00580909 /* OTManager.h */, 0C8BBF0F1FCB481800580909 /* OTManager.m */, 0C8FD546214AEC650098E3FB /* OTJoiningConfiguration.h */, @@ -18300,7 +18247,6 @@ isa = PBXGroup; children = ( DC99B89720EAD4D20065B73B /* Octagon */, - DC99B89620EAD4AB0065B73B /* CK API */, ); path = tests; sourceTree = ""; @@ -18618,10 +18564,11 @@ isa = PBXGroup; children = ( DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */, + EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */, 48284A041D1DB06E00C76CB7 /* README_os_log_prefs.txt */, ); name = os_log; - path = ../../..; + path = ../../OSX/sec/os_log; sourceTree = ""; }; 4C198F1A0ACDB4BF00AAB142 /* strings */ = { @@ -18935,6 +18882,7 @@ D4707A0D211373D4005BCFDA /* CMSPrivate.h */, DC1785981D778C5300B50D50 /* cssmapple.h */, 4C28BCD60986EBCB0020C665 /* certextensions.h */, + 443381D918A3D81400215606 /* SecAccessControl.h */, 4C696B3709BFA94F000CBC75 /* SecBase.h */, 4C0208F80D3C154200BFE54E /* SecBasePriv.h */, 4C8FD03D099D5C91006867B6 /* SecCertificate.h */, @@ -18973,6 +18921,7 @@ 5A6D1B9420810EA40057CAC8 /* SecProtocolTypes.h */, AAE91C542162634200B6BF0B /* SecProtocolTypesPriv.h */, 4C2F81D40BF121D2003C4F77 /* SecRandom.h */, + BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */, D43718C721168D7C00EA350A /* SecSMIME.h */, 107226D10D91DB32003CF14F /* SecTask.h */, DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */, @@ -19551,6 +19500,8 @@ BECEC11120A508F600E97255 /* TPVoucher.m */, DC88467F2237431400738068 /* TPDictionaryMatchingRules.h */, DC8846802237431400738068 /* TPDictionaryMatchingRules.m */, + DA700FC62310C0DF0051A7DE /* TPStringTable.h */, + DA700FC82310C0E00051A7DE /* TPStringTable.m */, BEB49F29206E98CD008DA7F4 /* TPECPublicKeyFactory.h */, BEB49F2F206E98CE008DA7F4 /* TPECPublicKeyFactory.m */, BEB49F32206E9A18008DA7F4 /* SFKey+TPKey.h */, @@ -19583,6 +19534,7 @@ BE72782A209D27C800F0DA77 /* TPKeyTests.m */, BEB49F36206E9B89008DA7F4 /* TPECPublicKeyFactoryTests.m */, E291657E2048BCCB0046512B /* TPPBPeerStableInfoTests.m */, + DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */, BEF88C661EB0008E00357577 /* Info.plist */, ); name = Tests; @@ -20695,6 +20647,8 @@ 5A04BB1F2298728A001848A0 /* test */, DC0BCC3A1D8C68CF00070CB0 /* iCloudKeychainTrace.c */, DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */, + EB3FBBF42320629400DF52EA /* SecABC.h */, + EB3FBBF52320629400DF52EA /* SecABC.m */, EBF3749A1DC064200065D840 /* SecADWrapper.c */, EBF3749B1DC064200065D840 /* SecADWrapper.h */, DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */, @@ -20762,7 +20716,7 @@ DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */, DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */, DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */, - DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */, + DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */, DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */, DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */, DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */, @@ -20782,7 +20736,6 @@ DCC78E281D8085FC00865A7C /* AppleBaselineEscrowCertificates.h */, D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */, DCC78E301D8085FC00865A7C /* SecAccessControl.m */, - 443381D918A3D81400215606 /* SecAccessControl.h */, 443381DA18A3D81400215606 /* SecAccessControlPriv.h */, DCC78E351D8085FC00865A7C /* SecBase64.c */, 18351B8F14CB65870097860E /* SecBase64.h */, @@ -20858,7 +20811,6 @@ DCC78E8A1D8085FC00865A7C /* SecServerEncryptionSupport.c */, E7676DB519411DF300498DD4 /* SecServerEncryptionSupport.h */, DCC78E8C1D8085FC00865A7C /* SecSharedCredential.c */, - BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */, DCC78E8E1D8085FC00865A7C /* SecSignatureVerificationSupport.c */, DCC78E8F1D8085FC00865A7C /* SecSignatureVerificationSupport.h */, DCC78E901D8085FC00865A7C /* SecTrust.c */, @@ -21061,6 +21013,18 @@ path = generated_source; sourceTree = ""; }; + DC33071B2328567C0035CDFB /* ipc */ = { + isa = PBXGroup; + children = ( + DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */, + EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */, + DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */, + EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */, + ); + name = ipc; + path = ../../OSX/sec/ipc; + sourceTree = ""; + }; DC35021A1E009E0700BC0587 /* Database Helpers */ = { isa = PBXGroup; children = ( @@ -21639,10 +21603,7 @@ DC5AC2001D83653E00CF422C /* resources */ = { isa = PBXGroup; children = ( - DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */, - EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */, - DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */, - EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */, + DC33071B2328567C0035CDFB /* ipc */, DC9EBA2F1DEE651500D0F733 /* Info-macOS.plist */, ); name = resources; @@ -21726,25 +21687,6 @@ name = gk_reset_check; sourceTree = ""; }; - DC68526A20D04A1000C61368 /* Bottled Peers */ = { - isa = PBXGroup; - children = ( - 0C8BBE921FC9DA5700580909 /* OTEscrowKeys.h */, - 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */, - 0C8BBE951FC9DA5800580909 /* OTBottledPeer.h */, - 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */, - BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */, - BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */, - 0CE1BCCD1FCE11610017230E /* OTBottledPeerSigned.h */, - 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */, - 0C101F96205352AF00387951 /* OTBottledPeerState.h */, - 0C101F932053528700387951 /* OTBottledPeerState.m */, - 0C36B3202007EE9B0029F7A2 /* OTPreflightInfo.h */, - 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */, - ); - name = "Bottled Peers"; - sourceTree = ""; - }; DC68527020D04A3200C61368 /* IPC */ = { isa = PBXGroup; children = ( @@ -21769,19 +21711,6 @@ name = Framework; sourceTree = ""; }; - DC68527220D04C6000C61368 /* Octagon via CK API */ = { - isa = PBXGroup; - children = ( - 0C8BBE8B1FC9DA5300580909 /* OTContext.h */, - 0C8BBE981FC9DA5A00580909 /* OTContext.m */, - 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */, - 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */, - 0CE407B31FD476E000F59B31 /* OTCloudStoreState.h */, - 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */, - ); - name = "Octagon via CK API"; - sourceTree = ""; - }; DC6A82061D87731C00418608 /* libsecurityd */ = { isa = PBXGroup; children = ( @@ -22061,26 +21990,6 @@ path = Framework; sourceTree = ""; }; - DC99B89620EAD4AB0065B73B /* CK API */ = { - isa = PBXGroup; - children = ( - 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */, - 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */, - 0C2F337520DD64C10031A92D /* OTCliqueTests.m */, - 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */, - 0C2F337620DD64C20031A92D /* OTTestsBase.h */, - 0C2F337720DD64C20031A92D /* OTTestsBase.m */, - 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */, - 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */, - 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */, - 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */, - 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */, - 0CB975502023B199008D6B48 /* OTRampingTests.m */, - DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */, - ); - name = "CK API"; - sourceTree = ""; - }; DC99B89720EAD4D20065B73B /* Octagon */ = { isa = PBXGroup; children = ( @@ -22135,6 +22044,8 @@ DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */, DC9FD3281F8598F300C8AAC8 /* CKKSPeer.h */, DC9FD3291F8598F300C8AAC8 /* CKKSPeer.m */, + DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */, + DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */, DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */, DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */, 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */, @@ -22759,6 +22670,8 @@ DCC67E2A20DDC05900A70A31 /* Operations */ = { isa = PBXGroup; children = ( + 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */, + 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */, DCB946AD22FCB88400BE4490 /* OTDetermineHSA2AccountStatusOperation.h */, DCB946AE22FCB88500BE4490 /* OTDetermineHSA2AccountStatusOperation.m */, DCE772642290712F005862B4 /* OctagonCheckTrustStateOperation.h */, @@ -22963,7 +22876,7 @@ 1B995258226681EE00A2D6CD /* PolicyReporter.m */, ); name = "securityd iOS"; - path = OSX/sec/securityd; + path = keychain/securityd; sourceTree = ""; }; DCC78CFC1D8085F200865A7C /* CKBridge */ = { @@ -23041,6 +22954,8 @@ DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */, 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */, 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */, + 48AC7B5C232B1A1700F02B6F /* SOSIntervalEvent.h */, + 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */, DCC78D111D8085F200865A7C /* SOSExports.exp-in */, ); name = Account; @@ -24243,6 +24158,7 @@ DCE4E85D1D7A584D00AFB96E /* iOS */, ); name = trustd; + path = trust/trustd; sourceTree = ""; }; DCE4E85D1D7A584D00AFB96E /* iOS */ = { @@ -24253,7 +24169,7 @@ D41257EE1E941DA800781F23 /* com.apple.trustd.plist */, D45068691E948ACE00FA7675 /* entitlements.plist */, ); - name = iOS; + path = iOS; sourceTree = ""; }; DCE4E85E1D7A585300AFB96E /* macOS */ = { @@ -24265,7 +24181,7 @@ D41257EA1E941CF200781F23 /* com.apple.trustd.plist */, D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */, ); - name = macOS; + path = macOS; sourceTree = ""; }; DCE4E8A01D7F352600AFB96E /* authd */ = { @@ -25396,7 +25312,6 @@ DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */, EB2CA4D81D2C28C800AB770F /* libaks.a */, 4432AF8C1A01472C000958DC /* libaks_acl.a */, - DC1789161D77998700B50D50 /* libauto.dylib */, DC1789181D77998C00B50D50 /* libbsm.dylib */, E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */, 0CFC029B1D41650700E6283B /* libcoretls.dylib */, @@ -25702,7 +25617,6 @@ 4718AEA2205B39C40068EC3F /* CKKSGroupOperation.h in Headers */, 4718AEA3205B39C40068EC3F /* CKKSRateLimiter.h in Headers */, 4718AEA4205B39C40068EC3F /* SecDbKeychainSerializedItemV7.h in Headers */, - 4718AEA5205B39C40068EC3F /* OTCloudStore.h in Headers */, 4718AEA6205B39C40068EC3F /* CKKSResultOperation.h in Headers */, 4718AEA7205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.h in Headers */, 4718AEA8205B39C40068EC3F /* CKKSViewManager.h in Headers */, @@ -25868,7 +25782,6 @@ 6C73F48F2006B910003D5D63 /* SOSAnalytics.h in Headers */, DCD7EE9A1F4F5156007D9804 /* oidsocsp.h in Headers */, D4B3B1D821151BBF00A43409 /* SecCmsSignedData.h in Headers */, - BE2AD2B31FDA07EF00739F96 /* OTBottledPeerRecord.h in Headers */, 4AF7000115AFB73800B9D400 /* SecOTRMath.h in Headers */, 4AF7000315AFB73800B9D400 /* SecOTRPacketData.h in Headers */, D4707A232113E74B005BCFDA /* SecCmsEncoder.h in Headers */, @@ -25953,6 +25866,7 @@ BEF88C8E1EB000BE00357577 /* TPTypes.h in Headers */, DCD7DDA022B86A5500161396 /* TPPBDispositionDuplicateMachineID.h in Headers */, BEF88C811EB000BE00357577 /* TPPeer.h in Headers */, + DA700FC92310C0E00051A7DE /* TPStringTable.h in Headers */, BEC373B220D815F500DBDF5B /* TPPBUnknownMachineID.h in Headers */, DC730E1322400D7B0051DD48 /* TPDictionaryMatchingRules.h in Headers */, BEB49F30206E98D0008DA7F4 /* TPECPublicKeyFactory.h in Headers */, @@ -26681,6 +26595,7 @@ DC0FA6B02291F63F00FE01C4 /* OctagonPendingFlag.h in Headers */, 47922D421FAA7C240008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.h in Headers */, DCFE1C341F17ECE5007640C8 /* CKKSCondition.h in Headers */, + DC1E5AB623063A4E00918162 /* CKKSPeerProvider.h in Headers */, DC047081218BB21E0078BDAA /* OTCuttlefishAccountStateHolder.h in Headers */, DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */, DC2C5F5D1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */, @@ -26689,7 +26604,6 @@ 47922D541FAA7E060008F7E0 /* SecDbKeychainSerializedItemV7.h in Headers */, DCD33D93220CFF8A000A390B /* EscrowRequestPerformEscrowEnrollOperation.h in Headers */, DCC54181225C05180095D926 /* OTUploadNewCKKSTLKsOperation.h in Headers */, - 0C770EBC1FCF7C9800B5F0E2 /* OTCloudStore.h in Headers */, DC14478A1F5764C600236DB4 /* CKKSResultOperation.h in Headers */, DCFE1C511F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */, DCBDB3BB1E57CA7A00B61300 /* CKKSViewManager.h in Headers */, @@ -28820,6 +28734,7 @@ BEAA0027202A832500E51F45 /* Sources */, BEAA0029202A832500E51F45 /* Resources */, BEAA0028202A832500E51F45 /* Frameworks */, + EB3FB9A3231C125400DF52EA /* Copy Logging Files */, ); buildRules = ( ); @@ -32524,8 +32439,8 @@ inputFileListPaths = ( ); inputPaths = ( - "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA.cer", - "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA2.cer", + "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA.cer", + "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA2.cer", ); name = "Install Apple Corporate Roots"; outputFileListPaths = ( @@ -32536,7 +32451,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "ditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n"; + shellScript = "ditto ${SRCROOT}/trust/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/trust/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n"; }; D4C263C41F8FEAA8001317EA /* Run Script Generate Error Strings */ = { isa = PBXShellScriptBuildPhase; @@ -33039,20 +32954,12 @@ 0C7A8BBF21714CDC00F4C480 /* OTJoiningConfiguration.m in Sources */, 0C48B380202E438100A0E1AA /* CloudKitKeychainSyncingMockXCTest.m in Sources */, 0CB9754F2023A8F5008D6B48 /* CloudKitMockXCTest.m in Sources */, - 0C24D693204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m in Sources */, 0C0DA5D01FE1F1F3003BD3BB /* CKKSControlProtocol.m in Sources */, - 0CBDF64D1FFC951200433E0D /* OTBottledPeerTLK.m in Sources */, 0C16371C1FD116B300210823 /* MockCloudKit.m in Sources */, - 0C8A034F1FDF60070042E8BE /* OTBottledPeerTests.m in Sources */, 6C53A44D206AB1EF000FA611 /* LocalKeychainAnalytics.m in Sources */, - 0C1637211FD12F1500210823 /* OTCloudStoreTests.m in Sources */, - 0CAEC9D81FD740CF00D1F2CA /* OTContextTests.m in Sources */, 0C0DA5CF1FE1F1C5003BD3BB /* OTControlProtocol.m in Sources */, - 0C8A03461FDF42BA0042E8BE /* OTEscrowKeyTests.m in Sources */, - 0C8A034D1FDF4CCE0042E8BE /* OTLocalStoreTests.m in Sources */, DCDB296C1FD8820400B5D242 /* SFAnalytics.m in Sources */, 6C73F48D2006B83E003D5D63 /* SOSAnalytics.m in Sources */, - 0C46A57B2035019800F17112 /* OTLockStateNetworkingTests.m in Sources */, DC5B391820C08B39005B09F6 /* SecFramework.c in Sources */, DCDB296E1FD8821400B5D242 /* SFAnalyticsActivityTracker.m in Sources */, DCDB29701FD8821800B5D242 /* SFAnalyticsMultiSampler.m in Sources */, @@ -33061,23 +32968,19 @@ 0C46A5712034C6BA00F17112 /* OTControl.m in Sources */, DCDB29721FD8821D00B5D242 /* SFAnalyticsSampler.m in Sources */, DCDB297E1FD8849D00B5D242 /* SFObjCType.m in Sources */, - 0CF74E4120DDD5290014A5DB /* OTTestsBase.m in Sources */, 5A061197229ED6EB006AF14A /* NSDate+SFAnalytics.m in Sources */, DCDB297C1FD8848A00B5D242 /* SFSQLite.m in Sources */, 0CA4EBF4202B8DBE002B1D96 /* CloudKitKeychainSyncingTestsBase.m in Sources */, DCDB297D1FD8849A00B5D242 /* SFSQLiteStatement.m in Sources */, - 0CF74E4720DDD5390014A5DB /* OTCliqueTests.m in Sources */, DCDB297B1FD8847100B5D242 /* SecTask.c in Sources */, 0CE751AF20ACC497002B2832 /* SFSignInAnalytics.m in Sources */, 0C1637291FD2066A00210823 /* SecdWatchdog.m in Sources */, DCDB29791FD8844C00B5D242 /* client.c in Sources */, DCDB297A1FD8845600B5D242 /* client_endpoint.m in Sources */, - 0CB975512023B199008D6B48 /* OTRampingTests.m in Sources */, 0C16372B1FD2067F00210823 /* server_endpoint.m in Sources */, 0C16372D1FD2069300210823 /* server_entitlement_helpers.c in Sources */, 0C1637301FD206BC00210823 /* server_security_helpers.m in Sources */, 0C1637271FD2065400210823 /* spi.c in Sources */, - DC5060F520E2DB9700925005 /* OTCuttlefishContextTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -33255,17 +33158,15 @@ 4718AE37205B39C40068EC3F /* CKKSAccountStateTracker.m in Sources */, 4718AE38205B39C40068EC3F /* SecCDKeychain.m in Sources */, 4718AE3A205B39C40068EC3F /* CKKSGroupOperation.m in Sources */, - 4718AE3B205B39C40068EC3F /* OTContextRecord.m in Sources */, 4718AE3D205B39C40068EC3F /* CKKSManifestLeafRecord.m in Sources */, DC8DF6DF212F8A7D007B3FE8 /* OTSOSAdapter.m in Sources */, 4718AE3E205B39C40068EC3F /* CKKSItem.m in Sources */, 4718AE3F205B39C40068EC3F /* CKKSItemEncrypter.m in Sources */, 4718AE40205B39C40068EC3F /* CKKSOutgoingQueueEntry.m in Sources */, 4718AE42205B39C40068EC3F /* CKKSIncomingQueueEntry.m in Sources */, - 4718AE43205B39C40068EC3F /* OTLocalStore.m in Sources */, 4718AE44205B39C40068EC3F /* SFKeychainControlManager.m in Sources */, DC3AF52F2229E770006577E8 /* CKKSListenerCollection.m in Sources */, - 4718AE45205B39C40068EC3F /* OTBottledPeerSigned.m in Sources */, + 0C29BF2523232897003C807E /* OTDefines.m in Sources */, 4718AE46205B39C40068EC3F /* CKKSIncomingQueueOperation.m in Sources */, 4718AE47205B39C40068EC3F /* CKKSOutgoingQueueOperation.m in Sources */, 4718AE48205B39C40068EC3F /* CKKSZoneStateEntry.m in Sources */, @@ -33275,7 +33176,6 @@ 6C4AEF97218A12810012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */, 4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */, 4718AE4E205B39C40068EC3F /* OTManager.m in Sources */, - 4718AE4F205B39C40068EC3F /* OTEscrowKeys.m in Sources */, 4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */, 4718AE51205B39C40068EC3F /* CKKSControlServer.m in Sources */, 4718AE52205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.m in Sources */, @@ -33315,20 +33215,17 @@ 4718AE71205B39C40068EC3F /* SecItemServer.c in Sources */, 4718AE72205B39C40068EC3F /* SecDbKeychainSerializedAKSWrappedKey.m in Sources */, D491112D209515400066A1E4 /* CKKSAnalytics.m in Sources */, - 4718AE74205B39C40068EC3F /* OTContext.m in Sources */, 4718AE75205B39C40068EC3F /* NSOperationCategories.m in Sources */, 4718AE76205B39C40068EC3F /* SecKeybagSupport.c in Sources */, 4718AE77205B39C40068EC3F /* SecLogSettingsServer.m in Sources */, 4718AE78205B39C40068EC3F /* CKKSDeviceStateEntry.m in Sources */, 4718AE79205B39C40068EC3F /* CKKSFixups.m in Sources */, - 4718AE7A205B39C40068EC3F /* OTIdentity.m in Sources */, 4718AE7C205B39C40068EC3F /* SecOTRRemote.m in Sources */, 4718AE7D205B39C40068EC3F /* CKKSUpdateCurrentItemPointerOperation.m in Sources */, 4718AE7E205B39C40068EC3F /* CKKSNewTLKOperation.m in Sources */, 4718AE7F205B39C40068EC3F /* CKKSLockStateTracker.m in Sources */, 6C9791C821C20CFF0074C609 /* NSError+UsefulConstructors.m in Sources */, 6C4AEFA1218A189B0012C5DA /* SecAKSObjCWrappers.m in Sources */, - 4718AE80205B39C40068EC3F /* OTCloudStoreState.m in Sources */, 6C4AEF89218A09E80012C5DA /* CheckV12DevEnabled.m in Sources */, 4718AE81205B39C40068EC3F /* SecDbKeychainSerializedSecretData.m in Sources */, 4718AE82205B39C40068EC3F /* CKKSKeychainView.m in Sources */, @@ -33343,15 +33240,11 @@ 4718AE8B205B39C40068EC3F /* iCloudTrace.c in Sources */, 4718AE8C205B39C40068EC3F /* OctagonAPSReceiver.m in Sources */, DC391F9F21BF2F8700772585 /* CKKSConstants.m in Sources */, - 4718AE8D205B39C40068EC3F /* OTBottledPeer.m in Sources */, 6C880FCD21C3351500D38D66 /* SecDbBackupBag.m in Sources */, 4718AE8F205B39C40068EC3F /* SOSEnsureBackup.m in Sources */, - 4718AE90205B39C40068EC3F /* OTBottledPeerRecord.m in Sources */, 6C880FD121C3351500D38D66 /* SecDbBackupRecoverySet.m in Sources */, - 4718AE91205B39C40068EC3F /* OTCloudStore.m in Sources */, 6C880FCE21C3351500D38D66 /* SecDbBackupBagIdentity.m in Sources */, 4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */, - 4718AE93205B39C40068EC3F /* OTPreflightInfo.m in Sources */, 4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */, 4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */, 4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */, @@ -33839,6 +33732,7 @@ DC391F9D21BF2F8100772585 /* CKKSConstants.m in Sources */, BE9F8D10206C099800B53D16 /* Container.swift in Sources */, 0CB582D3218920090040C5F2 /* OTPrivateKey.m in Sources */, + DC25B3AC233C2EBC00CB1409 /* CloudKitCategories.m in Sources */, BE55C77C2044D0C90045863D /* Client.swift in Sources */, BE55C77E2044D7E60045863D /* main.swift in Sources */, DCAD8F8622C43EC1007C3872 /* Container_MachineIDs.swift in Sources */, @@ -33881,6 +33775,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1B0CDF64231C9E0E004401F0 /* ContainerMap.swift in Sources */, 0CB582CB2189157F0040C5F2 /* OTPrivateKey.m in Sources */, EBF5323A21C8B6330073C1C7 /* OTDefines.m in Sources */, 0CB582C92189157F0040C5F2 /* OTBottle.m in Sources */, @@ -33963,6 +33858,7 @@ DCE0777221ADD71C002662FD /* TPPBPolicyDocument.m in Sources */, DCE0777421ADD71C002662FD /* TPPBPolicyCategoriesByView.m in Sources */, DCE0777621ADD71C002662FD /* TPPBPolicyIntroducersByCategory.m in Sources */, + DA700FCA2310C0E00051A7DE /* TPStringTable.m in Sources */, DCE0777821ADD71C002662FD /* TPPBPolicyModelToCategory.m in Sources */, DCE0777A21ADD71C002662FD /* TPPBPolicyRedaction.m in Sources */, ); @@ -33973,10 +33869,12 @@ buildActionMask = 2147483647; files = ( 1B4AE38722400A22002188E1 /* TPDictionaryMatchingRules.m in Sources */, + DA31CB212319DC8F0039F1CC /* TPStringTable.m in Sources */, BEF88C941EB000FD00357577 /* TPDummyDecrypter.m in Sources */, BEF88C951EB000FD00357577 /* TPDummyEncrypter.m in Sources */, BE72782B209D27C800F0DA77 /* TPKeyTests.m in Sources */, BEF88C981EB000FD00357577 /* TPModelTests.m in Sources */, + DA3AD86A2319AA5D0049AFD6 /* TPStringTableTests.m in Sources */, DC730E142240103A0051DD48 /* TPDictionaryMatchingRuleTests.m in Sources */, E291657F2048BCCB0046512B /* TPPBPeerStableInfoTests.m in Sources */, BEF88C9B1EB000FD00357577 /* TPPeerTests.m in Sources */, @@ -34593,6 +34491,7 @@ DC0BCDAF1D8C6A1F00070CB0 /* SecAppleAnchor.c in Sources */, DC0BCDA41D8C6A1F00070CB0 /* iOSforOSX-SecAttr.c in Sources */, DC0BCD881D8C6A1E00070CB0 /* SecTrace.c in Sources */, + EB3FBC09232063A100DF52EA /* SecABC.m in Sources */, DC0BCD9A1D8C6A1F00070CB0 /* der_plist_internal.c in Sources */, DC0BCDAE1D8C6A1F00070CB0 /* SecSCTUtils.c in Sources */, DC0BCD971D8C6A1E00070CB0 /* der_number.c in Sources */, @@ -34611,7 +34510,7 @@ DC0BCD9C1D8C6A1F00070CB0 /* der_set.c in Sources */, DC36895821235F23003A3735 /* SecAKSWrappers.c in Sources */, EBB8528122F79F6E00424FD0 /* SecXPCHelper.m in Sources */, - DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.c in Sources */, + DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.m in Sources */, DC0BCD791D8C6A1E00070CB0 /* SecBuffer.c in Sources */, DC0BCDAB1D8C6A1F00070CB0 /* SecXPCError.c in Sources */, DA5B871D2065A8440093F083 /* SecAutorelease.m in Sources */, @@ -34645,6 +34544,7 @@ files = ( EB18A7BA2238C07600A0FC41 /* OTDeviceInformationAdapter.m in Sources */, DC74799E22272358001E0E8C /* CKKSSerializedKey.m in Sources */, + EB3FBB4F231F836500DF52EA /* CKKSListenerCollection.m in Sources */, DC74799D22272344001E0E8C /* CKKSSIV.m in Sources */, DC74799C22272331001E0E8C /* CKKSPeer.m in Sources */, DC74799A222722BC001E0E8C /* CKKSKeychainBackedKey.m in Sources */, @@ -34779,6 +34679,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1BB1CAB7232C05BD001D0C71 /* CuttlefishXPCWrapper.m in Sources */, + 1BB1CAB8232C05BD001D0C71 /* CuttlefishXPCWrapper.h in Sources */, DCE0778021ADEC4B002662FD /* CKKSSerializedKey.m in Sources */, DCE0777F21ADEC07002662FD /* OTAccountMetadataClassC.m in Sources */, 0C84D8351FCF43BB00B822E3 /* OTControlProtocol.m in Sources */, @@ -34789,7 +34691,6 @@ DC797E1A1DD3F9A400CC9E42 /* CKKSSQLDatabaseObject.m in Sources */, 6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */, DCD33D7C220B99CC000A390B /* EscrowRequestController.m in Sources */, - 0C5A8C1D200A9B0C004C771D /* OTPreflightInfo.m in Sources */, DC19484D21812EC5007C2260 /* OTDeviceInformationAdapter.m in Sources */, 6C4AEFA0218A189A0012C5DA /* SecAKSObjCWrappers.m in Sources */, DCFB12C71E95A4C000510F5F /* CKKSAccountStateTracker.m in Sources */, @@ -34800,7 +34701,6 @@ EBB407B31EBA46B200A541A5 /* CKKSPowerCollection.m in Sources */, 0C84D8391FCF43CA00B822E3 /* OTManager.m in Sources */, DCCD88EA1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */, - 0CD9E8001FE05B6600F66C38 /* OTContextRecord.m in Sources */, DC54DD0F1EA7D9E700108E92 /* CKKSManifestLeafRecord.m in Sources */, DCDCCB901DF7B8D4006E840E /* CKKSItem.m in Sources */, DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */, @@ -34808,10 +34708,7 @@ DC6D2C921DD2835A00BE372D /* CKKSOutgoingQueueEntry.m in Sources */, DC378B3D1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m in Sources */, 6C880FCB21C3351400D38D66 /* SecDbBackupMetadataClassKey.m in Sources */, - 0C8BBEA91FC9DBBF00580909 /* OTLocalStore.m in Sources */, 4733377B1FDAFBCC00E19F30 /* SFKeychainControlManager.m in Sources */, - 0C101F942053528700387951 /* OTBottledPeerState.m in Sources */, - 0CE1BCCE1FCE11680017230E /* OTBottledPeerSigned.m in Sources */, DC5BB4FA1E0C90DE0010F836 /* CKKSIncomingQueueOperation.m in Sources */, DC5BB5001E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */, 0CB8DC9A2194B14C0021A7C8 /* OTVouchWithBottleOperation.m in Sources */, @@ -34831,7 +34728,6 @@ DCE278DF1ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */, DC3D748E1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m in Sources */, DCC67E2F20DDC07900A70A31 /* OTPrepareOperation.m in Sources */, - 0C8BBEA51FC9DBB100580909 /* OTEscrowKeys.m in Sources */, DCB41DFC216D5E5B00F219E0 /* OTAccountMetadataClassC+KeychainSupport.m in Sources */, 6C880FCC21C3351400D38D66 /* SecDbBackupRecoverySet.m in Sources */, DCA4D1FF1E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */, @@ -34840,6 +34736,7 @@ DCFE1C531F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */, 47922D481FAA7C3C0008F7E0 /* SecDbKeychainSerializedMetadata.m in Sources */, DCD6C4B41EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */, + 0C29BF222323288C003C807E /* OTDefines.m in Sources */, DC378B2F1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m in Sources */, DC5681AB224DA05F008F8DEB /* OctagonFlags.m in Sources */, 0CD3D519224048A800024755 /* OTSetRecoveryKeyOperation.m in Sources */, @@ -34881,6 +34778,7 @@ DC52E7CC1D80BCDF00B0A59C /* SecDbQuery.c in Sources */, DC14478C1F5764C600236DB4 /* CKKSResultOperation.m in Sources */, 479DA1721EBBA8D10065C98F /* CKKSManifest.m in Sources */, + DC1E5AB723063A4E00918162 /* CKKSPeerProvider.m in Sources */, DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */, 0C2F337220DD64930031A92D /* OTRamping.m in Sources */, DCF12674218A757A000124C6 /* OTLeaveCliqueOperation.m in Sources */, @@ -34917,7 +34815,6 @@ DCE772672290712F005862B4 /* OctagonCheckTrustStateOperation.m in Sources */, 5A04BAF822973E7F001848A0 /* OTFollowup.m in Sources */, DCB837321ED5045000015C07 /* CKKSLockStateTracker.m in Sources */, - 0CE407AC1FD4769B00F59B31 /* OTCloudStoreState.m in Sources */, EB80DE162195EDA4005B10FA /* SecC2DeviceInfo.m in Sources */, 47922D4C1FAA7C4A0008F7E0 /* SecDbKeychainSerializedSecretData.m in Sources */, DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */, @@ -34925,7 +34822,6 @@ 0C4F4DE221153E9E007F7E20 /* OTEpochOperation.m in Sources */, 47922D561FAA7E0D0008F7E0 /* SecDbKeychainSerializedItemV7.m in Sources */, DC7A17EF1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */, - 0C48B377202E3EE700A0E1AA /* OTContext.m in Sources */, DC7341F51F8447AB00AB9BDF /* CKKSTLKShareRecord.m in Sources */, 0C5960811FB369C50095BA29 /* CKKSHealTLKSharesOperation.m in Sources */, DCD33D81220B9DC8000A390B /* OctagonStateMachineHelpers.m in Sources */, @@ -34937,16 +34833,12 @@ DCEA5D871E2F14810089CF55 /* OctagonAPSReceiver.m in Sources */, DC0BD4F521BB060F006B9154 /* CKKSKeychainBackedKey.m in Sources */, 6C880FC921C3351400D38D66 /* SecDbBackupBagIdentity.m in Sources */, - 0C8BBE9F1FC9DBA400580909 /* OTBottledPeer.m in Sources */, 6C869A751F50CAF400957298 /* SOSEnsureBackup.m in Sources */, DC754C722228B57C00A39C8E /* TrustedPeersHelperProtocol.m in Sources */, 0C12B1F12138D31600BE0A98 /* OTClientStateMachine.m in Sources */, - BE2AD2BA1FDA080800739F96 /* OTBottledPeerRecord.m in Sources */, - 0C770EC41FCF7E2000B5F0E2 /* OTCloudStore.m in Sources */, DCEA5D571E2826DB0089CF55 /* CKKSSIV.m in Sources */, EB7E911B2194849900B1FA21 /* SECC2MPDeviceInfo.m in Sources */, EB7E91192194849900B1FA21 /* SECC2MPCloudKitOperationGroupInfo.m in Sources */, - 0C48B371202E3ED800A0E1AA /* OTIdentity.m in Sources */, DC9082C41EA0277600D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */, 6C4AEF96218A127F0012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */, DCFE1C361F17ECE5007640C8 /* CKKSCondition.m in Sources */, @@ -35016,6 +34908,7 @@ DC59244D20E46F0E0073D284 /* SOSTransport.m in Sources */, DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.m in Sources */, DC59245020E46F800073D284 /* SOSRecoveryKeyBag.m in Sources */, + 48AC7B73232B1DA600F02B6F /* SOSIntervalEvent.m in Sources */, 0CB50A0E20AA4C2F00FE4675 /* SOSAccountTrustClassic+Circle.m in Sources */, DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.m in Sources */, DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.m in Sources */, @@ -36678,7 +36571,6 @@ EB6667C7204CD69F000B404F /* testPlistDER.m in Sources */, EBC73F29209966AF00AE3350 /* SFSQLite.m in Sources */, EB49B2D5202DF1D8003F34A0 /* SecTask.c in Sources */, - EB49B2D4202DF1C1003F34A0 /* client.c in Sources */, EB49B2D3202DF1AC003F34A0 /* SecdWatchdog.m in Sources */, EB49B2B1202D8780003F34A0 /* mockaksKeychain.m in Sources */, DC5B391B20C08BDC005B09F6 /* SecFramework.c in Sources */, @@ -40651,7 +40543,6 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", - "$(OTHER_LDFLAGS_AOSKIT_FRAMEWORK)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", @@ -40694,7 +40585,6 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", - "$(OTHER_LDFLAGS_AOSKIT_FRAMEWORK)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", @@ -40943,7 +40833,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -40999,7 +40889,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -41531,6 +41421,7 @@ CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_DYNAMIC_NO_PIC = NO; @@ -41563,6 +41454,7 @@ CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; @@ -41863,6 +41755,7 @@ MACH_O_TYPE = mh_execute; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "-ObjC", ); @@ -41903,6 +41796,7 @@ INSTALL_PATH = "$(SECURITY_FRAMEWORK_RESOURCES_DIR)"; MACH_O_TYPE = mh_execute; OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "-ObjC", ); @@ -42266,11 +42160,13 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_APPLEACCOUNT)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_CRASHREPORTER)", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainAnalyticsTests; @@ -42302,12 +42198,14 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_CRASHREPORTER)", "$(OTHER_LDFLAGS_APPLEACCOUNT)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainAnalyticsTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -43106,7 +43004,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -43157,7 +43055,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -43246,7 +43144,6 @@ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; @@ -43334,7 +43231,6 @@ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; @@ -43923,7 +43819,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/iOS/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -43947,7 +43843,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/iOS/entitlements.plist; ENABLE_NS_ASSERTIONS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", @@ -44788,7 +44684,6 @@ OTHER_LDFLAGS = ( "$(inherited)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", - "$(OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY)", "-framework", Security, ); @@ -44814,7 +44709,6 @@ OTHER_LDFLAGS = ( "$(inherited)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", - "$(OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY)", "-framework", Security, ); @@ -47143,7 +47037,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -47167,7 +47061,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -49448,7 +49342,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_DYNAMIC_NO_PIC = NO; @@ -49461,7 +49355,7 @@ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; + INFOPLIST_FILE = "keychain/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; MTL_ENABLE_DEBUG_INFO = YES; OTHER_CODE_SIGN_FLAGS = "$(OTHER_CODE_SIGN_FLAGS_LIBRARY_VALIDATION)"; @@ -49502,7 +49396,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; COPY_PHASE_STRIP = NO; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_NS_ASSERTIONS = NO; @@ -49516,7 +49410,7 @@ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; + INFOPLIST_FILE = "keychain/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CODE_SIGN_FLAGS = "$(OTHER_CODE_SIGN_FLAGS_LIBRARY_VALIDATION)"; @@ -49557,7 +49451,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/macOS/entitlements.plist; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -49601,7 +49495,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/macOS/entitlements.plist; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -51916,7 +51810,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -51939,6 +51833,7 @@ "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = "$(TARGET_NAME)"; REEXPORTED_LIBRARY_NAMES = ""; @@ -51957,7 +51852,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -51980,6 +51875,7 @@ "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = "$(TARGET_NAME)"; REEXPORTED_LIBRARY_NAMES = ""; @@ -52102,7 +51998,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -52122,6 +52018,7 @@ "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_UserManagement)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = recovery_securityd; REEXPORTED_LIBRARY_NAMES = ""; @@ -52140,7 +52037,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -52160,6 +52057,7 @@ "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_UserManagement)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = recovery_securityd; REEXPORTED_LIBRARY_NAMES = ""; diff --git a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme index 471ef0c5..30a0789a 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme @@ -41,6 +41,15 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -53,17 +62,6 @@ - - - - - - - - #include #include -#include +#include "keychain/securityd/Regressions/securityd_regressions.h" #include "keychain/SecureObjectSync/Regressions/SOSCircle_regressions.h" #include #include diff --git a/SecurityTool/sharedTool/SecurityTool.c b/SecurityTool/sharedTool/SecurityTool.c index 847c4e1a..d883eb4a 100644 --- a/SecurityTool/sharedTool/SecurityTool.c +++ b/SecurityTool/sharedTool/SecurityTool.c @@ -41,7 +41,7 @@ #include #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif /* Maximum length of an input line in interactive mode. */ diff --git a/dtlsEcho/dtlsEchoClient.c b/dtlsEcho/dtlsEchoClient.c index 7a2b553a..e714e043 100644 --- a/dtlsEcho/dtlsEchoClient.c +++ b/dtlsEcho/dtlsEchoClient.c @@ -40,7 +40,7 @@ #include #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif static diff --git a/dtlsEcho/dtlsEchoServer.c b/dtlsEcho/dtlsEchoServer.c index 1306b5a7..ed2d287a 100644 --- a/dtlsEcho/dtlsEchoServer.c +++ b/dtlsEcho/dtlsEchoServer.c @@ -40,7 +40,7 @@ #include #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #define PORT 23232 diff --git a/featureflags/Security.plist b/featureflags/Security.plist index 339077b2..1ffb729d 100644 --- a/featureflags/Security.plist +++ b/featureflags/Security.plist @@ -2,6 +2,11 @@ + EnableSecureObjectSync + + Enabled + + octagonTrust Enabled @@ -33,9 +38,9 @@ octagonUseDeviceName - - Enabled - - + + Enabled + + diff --git a/header_symlinks/Security/SecAccessControl.h b/header_symlinks/Security/SecAccessControl.h index cea7071f..8ae6a105 120000 --- a/header_symlinks/Security/SecAccessControl.h +++ b/header_symlinks/Security/SecAccessControl.h @@ -1 +1 @@ -./../keychain/SecAccessControl.h \ No newline at end of file +./../keychain/headers/SecAccessControl.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificate.h b/header_symlinks/Security/SecCertificate.h index abfc83ee..9fc0b655 120000 --- a/header_symlinks/Security/SecCertificate.h +++ b/header_symlinks/Security/SecCertificate.h @@ -1 +1 @@ -./../trust/SecCertificate.h \ No newline at end of file +./../trust/headers/SecCertificate.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificatePriv.h b/header_symlinks/Security/SecCertificatePriv.h index 9499f6f4..74110696 120000 --- a/header_symlinks/Security/SecCertificatePriv.h +++ b/header_symlinks/Security/SecCertificatePriv.h @@ -1 +1 @@ -./../trust/SecCertificatePriv.h \ No newline at end of file +./../trust/headers/SecCertificatePriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificateRequest.h b/header_symlinks/Security/SecCertificateRequest.h index 0ecfd8ea..0f06dc02 120000 --- a/header_symlinks/Security/SecCertificateRequest.h +++ b/header_symlinks/Security/SecCertificateRequest.h @@ -1 +1 @@ -./../trust/SecCertificateRequest.h \ No newline at end of file +./../trust/headers/SecCertificateRequest.h \ No newline at end of file diff --git a/header_symlinks/Security/SecIdentity.h b/header_symlinks/Security/SecIdentity.h index cf2695c1..e57ecc24 120000 --- a/header_symlinks/Security/SecIdentity.h +++ b/header_symlinks/Security/SecIdentity.h @@ -1 +1 @@ -./../keychain/SecIdentity.h \ No newline at end of file +./../keychain/headers/SecIdentity.h \ No newline at end of file diff --git a/header_symlinks/Security/SecIdentityPriv.h b/header_symlinks/Security/SecIdentityPriv.h index 68c25650..39bfc21b 120000 --- a/header_symlinks/Security/SecIdentityPriv.h +++ b/header_symlinks/Security/SecIdentityPriv.h @@ -1 +1 @@ -./../keychain/SecIdentityPriv.h \ No newline at end of file +./../keychain/headers/SecIdentityPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecImportExport.h b/header_symlinks/Security/SecImportExport.h index 5cf7eced..e1c951dc 120000 --- a/header_symlinks/Security/SecImportExport.h +++ b/header_symlinks/Security/SecImportExport.h @@ -1 +1 @@ -./../keychain/SecImportExport.h \ No newline at end of file +./../keychain/headers/SecImportExport.h \ No newline at end of file diff --git a/header_symlinks/Security/SecImportExportPriv.h b/header_symlinks/Security/SecImportExportPriv.h index fd3ad461..a9e8031d 120000 --- a/header_symlinks/Security/SecImportExportPriv.h +++ b/header_symlinks/Security/SecImportExportPriv.h @@ -1 +1 @@ -./../keychain/SecImportExportPriv.h \ No newline at end of file +./../keychain/headers/SecImportExportPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecItem.h b/header_symlinks/Security/SecItem.h index 9976098b..ab75d336 120000 --- a/header_symlinks/Security/SecItem.h +++ b/header_symlinks/Security/SecItem.h @@ -1 +1 @@ -./../keychain/SecItem.h \ No newline at end of file +./../keychain/headers/SecItem.h \ No newline at end of file diff --git a/header_symlinks/Security/SecItemPriv.h b/header_symlinks/Security/SecItemPriv.h index a8169111..e0c3c010 120000 --- a/header_symlinks/Security/SecItemPriv.h +++ b/header_symlinks/Security/SecItemPriv.h @@ -1 +1 @@ -./../keychain/SecItemPriv.h \ No newline at end of file +./../keychain/headers/SecItemPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKey.h b/header_symlinks/Security/SecKey.h index 0d7004f9..5dd0da10 120000 --- a/header_symlinks/Security/SecKey.h +++ b/header_symlinks/Security/SecKey.h @@ -1 +1 @@ -./../keychain/SecKey.h \ No newline at end of file +./../keychain/headers/SecKey.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKeyPriv.h b/header_symlinks/Security/SecKeyPriv.h index 34a07ffa..60e1bf56 120000 --- a/header_symlinks/Security/SecKeyPriv.h +++ b/header_symlinks/Security/SecKeyPriv.h @@ -1 +1 @@ -./../keychain/SecKeyPriv.h \ No newline at end of file +./../keychain/headers/SecKeyPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKeyProxy.h b/header_symlinks/Security/SecKeyProxy.h index 9356c2c8..c39f74b1 120000 --- a/header_symlinks/Security/SecKeyProxy.h +++ b/header_symlinks/Security/SecKeyProxy.h @@ -1 +1 @@ -./../keychain/SecKeyProxy.h \ No newline at end of file +./../keychain/headers/SecKeyProxy.h \ No newline at end of file diff --git a/header_symlinks/Security/SecPolicy.h b/header_symlinks/Security/SecPolicy.h index a9f75265..a606ce80 120000 --- a/header_symlinks/Security/SecPolicy.h +++ b/header_symlinks/Security/SecPolicy.h @@ -1 +1 @@ -./../trust/SecPolicy.h \ No newline at end of file +./../trust/headers/SecPolicy.h \ No newline at end of file diff --git a/header_symlinks/Security/SecPolicyPriv.h b/header_symlinks/Security/SecPolicyPriv.h index e429b0a9..b0894668 120000 --- a/header_symlinks/Security/SecPolicyPriv.h +++ b/header_symlinks/Security/SecPolicyPriv.h @@ -1 +1 @@ -./../trust/SecPolicyPriv.h \ No newline at end of file +./../trust/headers/SecPolicyPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecSharedCredential.h b/header_symlinks/Security/SecSharedCredential.h index f1b330cf..725e9a37 120000 --- a/header_symlinks/Security/SecSharedCredential.h +++ b/header_symlinks/Security/SecSharedCredential.h @@ -1 +1 @@ -./../keychain/SecSharedCredential.h \ No newline at end of file +./../keychain/headers/SecSharedCredential.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrust.h b/header_symlinks/Security/SecTrust.h index 44fb96fb..afd36555 120000 --- a/header_symlinks/Security/SecTrust.h +++ b/header_symlinks/Security/SecTrust.h @@ -1 +1 @@ -./../trust/SecTrust.h \ No newline at end of file +./../trust/headers/SecTrust.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustPriv.h b/header_symlinks/Security/SecTrustPriv.h index 8c596e1e..e4acf71b 120000 --- a/header_symlinks/Security/SecTrustPriv.h +++ b/header_symlinks/Security/SecTrustPriv.h @@ -1 +1 @@ -./../trust/SecTrustPriv.h \ No newline at end of file +./../trust/headers/SecTrustPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustSettings.h b/header_symlinks/Security/SecTrustSettings.h index 4950c4f4..1691d26d 120000 --- a/header_symlinks/Security/SecTrustSettings.h +++ b/header_symlinks/Security/SecTrustSettings.h @@ -1 +1 @@ -./../trust/SecTrustSettings.h \ No newline at end of file +./../trust/headers/SecTrustSettings.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustSettingsPriv.h b/header_symlinks/Security/SecTrustSettingsPriv.h index dc728bca..557202df 120000 --- a/header_symlinks/Security/SecTrustSettingsPriv.h +++ b/header_symlinks/Security/SecTrustSettingsPriv.h @@ -1 +1 @@ -./../trust/SecTrustSettingsPriv.h \ No newline at end of file +./../trust/headers/SecTrustSettingsPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/oids.h b/header_symlinks/Security/oids.h index d760f054..5297b828 120000 --- a/header_symlinks/Security/oids.h +++ b/header_symlinks/Security/oids.h @@ -1 +1 @@ -./../trust/oids.h \ No newline at end of file +./../trust/headers/oids.h \ No newline at end of file diff --git a/header_symlinks/utilities/SecCFRelease.h b/header_symlinks/utilities/SecCFRelease.h deleted file mode 120000 index c0522304..00000000 --- a/header_symlinks/utilities/SecCFRelease.h +++ /dev/null @@ -1 +0,0 @@ -./../OSX/utilities/src/SecCFRelease.h \ No newline at end of file diff --git a/keychain/KeychainSettings/KeychainSettings.m b/keychain/KeychainSettings/KeychainSettings.m index b27a1407..14f4635b 100644 --- a/keychain/KeychainSettings/KeychainSettings.m +++ b/keychain/KeychainSettings/KeychainSettings.m @@ -217,6 +217,7 @@ [[KeychainSettings sharedOTControl] resetAndEstablish:nil context:OTDefaultContext altDSID:[self primaryiCloudAccountAltDSID] + resetReason:CuttlefishResetReasonUserInitiatedReset reply:^(NSError * _Nullable error) { if(error) { diff --git a/keychain/SecAccessControl.h b/keychain/SecAccessControl.h deleted file mode 100644 index 5b66b242..00000000 --- a/keychain/SecAccessControl.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecAccessControl - SecAccessControl defines access rights for items. - */ - -#ifndef _SECURITY_SECACCESSCONTROL_H_ -#define _SECURITY_SECACCESSCONTROL_H_ - -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @function SecAccessControlGetTypeID - @abstract Returns the type identifier of SecAccessControl instances. - @result The CFTypeID of SecAccessControl instances. - */ -CFTypeID SecAccessControlGetTypeID(void) -__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); - -/*! - @typedef SecAccessControlCreateFlags - - @constant kSecAccessControlUserPresence - User presence policy using biometry or Passcode. Biometry does not have to be available or enrolled. Item is still - accessible by Touch ID even if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled. - - @constant kSecAccessControlBiometryAny - Constraint: Touch ID (any finger) or Face ID. Touch ID or Face ID must be available. With Touch ID - at least one finger must be enrolled. With Face ID user has to be enrolled. Item is still accessible by Touch ID even - if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled. - - @constant kSecAccessControlTouchIDAny - Deprecated, please use kSecAccessControlBiometryAny instead. - - @constant kSecAccessControlBiometryCurrentSet - Constraint: Touch ID from the set of currently enrolled fingers. Touch ID must be available and at least one finger must - be enrolled. When fingers are added or removed, the item is invalidated. When Face ID is re-enrolled this item is invalidated. - - @constant kSecAccessControlTouchIDCurrentSet - Deprecated, please use kSecAccessControlBiometryCurrentSet instead. - - @constant kSecAccessControlDevicePasscode - Constraint: Device passcode - - @constant kSecAccessControlWatch - Constraint: Watch - - @constant kSecAccessControlOr - Constraint logic operation: when using more than one constraint, at least one of them must be satisfied. - - @constant kSecAccessControlAnd - Constraint logic operation: when using more than one constraint, all must be satisfied. - - @constant kSecAccessControlPrivateKeyUsage - Create access control for private key operations (i.e. sign operation) - - @constant kSecAccessControlApplicationPassword - Security: Application provided password for data encryption key generation. This is not a constraint but additional item - encryption mechanism. -*/ -typedef CF_OPTIONS(CFOptionFlags, SecAccessControlCreateFlags) { - kSecAccessControlUserPresence = 1u << 0, - kSecAccessControlBiometryAny API_AVAILABLE(macos(10.13.4), ios(11.3)) = 1u << 1, - kSecAccessControlTouchIDAny API_DEPRECATED_WITH_REPLACEMENT("kSecAccessControlBiometryAny", macos(10.12.1, 10.13.4), ios(9.0, 11.3)) = 1u << 1, - kSecAccessControlBiometryCurrentSet API_AVAILABLE(macos(10.13.4), ios(11.3)) = 1u << 3, - kSecAccessControlTouchIDCurrentSet API_DEPRECATED_WITH_REPLACEMENT("kSecAccessControlBiometryCurrentSet", macos(10.12.1, 10.13.4), ios(9.0, 11.3)) = 1u << 3, - kSecAccessControlDevicePasscode API_AVAILABLE(macos(10.11), ios(9.0)) = 1u << 4, - kSecAccessControlWatch API_AVAILABLE(macos(10.15), ios(NA), iosmac(13.0)) = 1u << 5, - kSecAccessControlOr API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 14, - kSecAccessControlAnd API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 15, - kSecAccessControlPrivateKeyUsage API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 30, - kSecAccessControlApplicationPassword API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 31, -} __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); - -/*! - @function SecAccessControlCreateWithFlags - @abstract Creates new access control object based on protection type and additional flags. - @discussion Created access control object should be used as a value for kSecAttrAccessControl attribute in SecItemAdd, - SecItemUpdate or SecKeyGeneratePair functions. Accessing keychain items or performing operations on keys which are - protected by access control objects can block the execution because of UI which can appear to satisfy the access control - conditions, therefore it is recommended to either move those potentially blocking operations out of the main - application thread or use combination of kSecUseAuthenticationContext and kSecUseAuthenticationUI attributes to control - where the UI interaction can appear. - @param allocator Allocator to be used by this instance. - @param protection Protection class to be used for the item. One of kSecAttrAccessible constants. - @param flags If no flags are set then all operations are allowed. - @param error Additional error information filled in case of failure. - @result Newly created access control object. - */ -__nullable -SecAccessControlRef SecAccessControlCreateWithFlags(CFAllocatorRef __nullable allocator, CFTypeRef protection, - SecAccessControlCreateFlags flags, CFErrorRef *error) -API_AVAILABLE(macos(10.10), ios(8.0)); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif // _SECURITY_SECACCESSCONTROL_H_ diff --git a/keychain/SecIdentity.h b/keychain/SecIdentity.h deleted file mode 100644 index ea002f3e..00000000 --- a/keychain/SecIdentity.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2002-2011,2012-2013,2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecIdentity - The functions provided in SecIdentity.h implement a convenient way to - match private keys with certificates. -*/ - -#ifndef _SECURITY_SECIDENTITY_H_ -#define _SECURITY_SECIDENTITY_H_ - -#include -#include - -#include -#include - -#if SEC_OS_OSX -#include -#endif - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @function SecIdentityGetTypeID - @abstract Returns the type identifier of SecIdentity instances. - @result The CFTypeID of SecIdentity instances. -*/ -CFTypeID SecIdentityGetTypeID(void) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -#if SEC_OS_OSX -/*! - @function SecIdentityCreateWithCertificate - @abstract Creates a new identity reference for the given certificate, assuming the associated private key is in one of the specified keychains. - @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list. - @param certificateRef A certificate reference. - @param identityRef On return, an identity reference. You are responsible for releasing this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecIdentityCreateWithCertificate( - CFTypeRef __nullable keychainOrArray, - SecCertificateRef certificateRef, - SecIdentityRef * __nonnull CF_RETURNS_RETAINED identityRef) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); -#endif - -/*! - @function SecIdentityCopyCertificate - @abstract Returns a reference to a certificate for the given identity - reference. - @param identityRef An identity reference. - @param certificateRef On return, a pointer to the found certificate - reference. You are responsible for releasing this reference by calling - the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecIdentityCopyCertificate( - SecIdentityRef identityRef, - SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificateRef) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecIdentityCopyPrivateKey - @abstract Returns the private key associated with an identity. - @param identityRef An identity reference. - @param privateKeyRef On return, a pointer to the private key for the given - identity. On iOS, the private key must be of class type kSecAppleKeyItemClass. - You are responsible for releasing this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecIdentityCopyPrivateKey( - SecIdentityRef identityRef, - SecKeyRef * __nonnull CF_RETURNS_RETAINED privateKeyRef) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -#if SEC_OS_OSX -/*! - @function SecIdentityCopyPreference - @abstract Returns the preferred identity for the specified name and key usage, optionally limiting the result to an identity issued by a certificate whose subject is one of the distinguished names in validIssuers. If a preferred identity does not exist, NULL is returned. - @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies the service requiring an identity. - @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to ignore this parameter. - @param validIssuers (optional) An array of CFDataRef instances whose contents are the subject names of allowable issuers, as returned by a call to SSLCopyDistinguishedNames (SecureTransport.h). Pass NULL if any issuer is allowed. - @param identity On return, a reference to the preferred identity, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Please use the SecIdentityCopyPreferred API instead. -*/ -OSStatus SecIdentityCopyPreference(CFStringRef name, CSSM_KEYUSE keyUsage, CFArrayRef __nullable validIssuers, SecIdentityRef * __nonnull CF_RETURNS_RETAINED identity) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecIdentityCopyPreferred - @abstract Returns the preferred identity for the specified name and key usage, optionally limiting the result to an identity issued by a certificate whose subject is one of the distinguished names in validIssuers. If a preferred identity does not exist, NULL is returned. - @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies the service requiring an identity. - @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) - @param validIssuers (optional) An array of CFDataRef instances whose contents are the subject names of allowable issuers, as returned by a call to SSLCopyDistinguishedNames (SecureTransport.h). Pass NULL if any issuer is allowed. - @result An identity or NULL, if the preferred identity has not been set. Your code should then typically perform a search for possible identities using the SecItem APIs. - @discussion If a preferred identity has not been set for the supplied name, the returned identity reference will be NULL. Your code should then perform a search for possible identities, using the SecItemCopyMatching API. -*/ -__nullable -SecIdentityRef SecIdentityCopyPreferred(CFStringRef name, CFArrayRef __nullable keyUsage, CFArrayRef __nullable validIssuers) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecIdentitySetPreference - @abstract Sets the preferred identity for the specified name and key usage. - @param identity A reference to the identity which will be preferred. - @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies a service requiring this identity. - @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to specify any key usage. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Please use the SecIdentitySetPreferred API instead. -*/ -OSStatus SecIdentitySetPreference(SecIdentityRef identity, CFStringRef name, CSSM_KEYUSE keyUsage) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecIdentitySetPreferred - @abstract Sets the preferred identity for the specified name and key usage. - @param identity A reference to the identity which will be preferred. If NULL is passed, any existing preference for the specified name is cleared instead. - @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies a service requiring this identity. - @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to specify any key usage. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecIdentitySetPreferred(SecIdentityRef __nullable identity, CFStringRef name, CFArrayRef __nullable keyUsage) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecIdentityCopySystemIdentity - @abstract Obtain the system-wide SecIdentityRef associated with - a specified domain. - @param domain Identifies the SecIdentityRef to be obtained, typically - in the form "com.apple.subdomain...". - @param idRef On return, the system SecIdentityRef assicated with - the specified domain. Caller must CFRelease this when - finished with it. - @param actualDomain (optional) The actual domain name of the - the returned identity is returned here. This - may be different from the requested domain. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If no system SecIdentityRef exists for the specified - domain, a domain-specific alternate may be returned - instead, typically (but not exclusively) the - kSecIdentityDomainDefault SecIdentityRef. - */ -OSStatus SecIdentityCopySystemIdentity( - CFStringRef domain, - SecIdentityRef * __nonnull CF_RETURNS_RETAINED idRef, - CFStringRef * __nullable CF_RETURNS_RETAINED actualDomain) /* optional */ - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); - -/*! - @function SecIdentitySetSystemIdentity - @abstract Assign the supplied SecIdentityRef to the specified - domain. - @param domain Identifies the domain to which the specified - SecIdentityRef will be assigned. - @param idRef (optional) The identity to be assigned to the specified - domain. Pass NULL to delete a possible entry for the specified - domain; in this case, it is not an error if no identity - exists for the specified domain. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion The caller must be running as root. -*/ -OSStatus SecIdentitySetSystemIdentity( - CFStringRef domain, - SecIdentityRef __nullable idRef) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); - -/* - * Defined system identity domains. - */ - -/*! - @const kSecIdentityDomainDefault The system-wide default identity. - */ -extern const CFStringRef kSecIdentityDomainDefault __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); - -/*! - @const kSecIdentityDomainKerberosKDC Kerberos KDC identity. -*/ -extern const CFStringRef kSecIdentityDomainKerberosKDC __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); - -#endif // SEC_OS_OSX - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECIDENTITY_H_ */ diff --git a/keychain/SecIdentityPriv.h b/keychain/SecIdentityPriv.h deleted file mode 100644 index 99a62abb..00000000 --- a/keychain/SecIdentityPriv.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2002-2011,2012-2013,2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecIdentityPriv - The functions provided in SecIdentityPriv.h implement a convenient way to - match private keys with certificates. -*/ - -#ifndef _SECURITY_SECIDENTITYPRIV_H_ -#define _SECURITY_SECIDENTITYPRIV_H_ - -#include -#include -#include - -__BEGIN_DECLS - -/*! @function SecIdentityCreate - @abstract create a new identity object from the provided certificate and its associated private key. - @param allocator CFAllocator to allocate the identity object. Pass NULL to use the default allocator. - @param certificate A certificate reference. - @param privateKey A private key reference. - @result An identity reference. -*/ -SecIdentityRef SecIdentityCreate( - CFAllocatorRef allocator, - SecCertificateRef certificate, - SecKeyRef privateKey) - __SEC_MAC_AND_IOS_UNKNOWN; - //__OSX_AVAILABLE_STARTING(__MAC_10_3, __SEC_IPHONE_UNKNOWN); - -#if SEC_OS_OSX -/*! - @function SecIdentityCompare - @abstract Compares two SecIdentityRef instances for equality. - @param identity1 An identity reference. - @param identity2 An identity reference. - @param compareOptions A value containing option flags. Currently there are no compare options, so 0 should be passed for this parameter. - @result An enumerated value of type CFComparisonResult. See CFBase.h. - @discussion Two identities are considered equal if they contain identical certificate and private key components. - @deprecated in Mac OS X 10.5 and later; the CFEqual function should be used instead (CFBase.h). - */ -CFComparisonResult SecIdentityCompare( - SecIdentityRef identity1, - SecIdentityRef identity2, - CFOptionFlags compareOptions) - DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER; - -/*! - @function SecIdentityFindPreferenceItem - @abstract Returns an identity preference item, given an identity string. - @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list. - @param idString A string containing a URI, hostname, or email (RFC822) address. - @param itemRef On return, a reference to the keychain item which was found. The caller is responsible for releasing this reference. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string. - @deprecated in Mac OS X 10.7 and later; use SecIdentityCopyPreferred() instead (SecIdentity.h) - - WARNING: This function is based on an implementation detail and will go away - in a future release; its use should be avoided at all costs. It does not - provide a way to find a preference item based on key usage, and it can only - find preferences which are stored as keychain items, so it may fail to find - the item you expect. Please use the public API functions to manipulate - identity preferences. -*/ -OSStatus SecIdentityFindPreferenceItem( - CFTypeRef keychainOrArray, - CFStringRef idString, - SecKeychainItemRef *itemRef) - API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreferred", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/*! - @function SecIdentityAddPreferenceItem - @abstract Adds a new identity preference item to the specified keychain. - @param keychainRef A reference to the keychain in which to store the preference item. Pass NULL to specify the user's default keychain. - @param identityRef An identity reference. - @param idString A string containing a URI, hostname, or email (RFC822) address. - @param itemRef On return, a reference to the new keychain item. The caller is responsible for releasing this reference. Pass NULL if the reference is not needed. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string. - @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h). -*/ -OSStatus SecIdentityAddPreferenceItem( - SecKeychainRef keychainRef, - SecIdentityRef identityRef, - CFStringRef idString, - SecKeychainItemRef *itemRef) - API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/*! - @function SecIdentityUpdatePreferenceItem - @abstract Given an existing identity preference keychain item, update it with the provided identity. - @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem. - @param identityRef An identity reference. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is used to update an existing preference item when a different identity is preferred. - @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h). -*/ -OSStatus SecIdentityUpdatePreferenceItem( - SecKeychainItemRef itemRef, - SecIdentityRef identityRef) - API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/*! - @function SecIdentityCopyFromPreferenceItem - @abstract Given an existing identity preference keychain item, obtain a SecIdentityRef for the identity it specifies. - @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem. - @param identityRef On return, an identity reference. The caller is responsible for releasing this reference. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is used to obtain a SecIdentityRef from an existing preference item. - @deprecated in Mac OS X 10.5; use SecIdentityCopyPreference() instead (SecIdentity.h). -*/ -OSStatus SecIdentityCopyFromPreferenceItem( - SecKeychainItemRef itemRef, - SecIdentityRef *identityRef) - API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/*! - @function ConvertArrayToKeyUsage - @abstract Given an array of key usages defined in SecItem.h return the equivalent CSSM_KEYUSE - @param usage An CFArrayRef containing CFTypeRefs defined in SecItem.h - kSecAttrCanEncrypt, - kSecAttrCanDecrypt, - kSecAttrCanDerive, - kSecAttrCanSign, - kSecAttrCanVerify, - kSecAttrCanWrap, - kSecAttrCanUnwrap - If the CFArrayRef is NULL then the CSSM_KEYUSAGE will be CSSM_KEYUSE_ANY - @result A CSSM_KEYUSE. Derived from the passed in Array -*/ -CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage) - __SEC_MAC_ONLY_UNKNOWN; -#endif // SEC_OS_OSX - -__END_DECLS - -#endif /* _SECURITY_SECIDENTITYPRIV_H_ */ diff --git a/keychain/SecImportExport.h b/keychain/SecImportExport.h deleted file mode 100644 index c6c91c6a..00000000 --- a/keychain/SecImportExport.h +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Copyright (c) 2000-2011,2012-2014,2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecImportExport - contains import/export functionality for keys and certificates. -*/ -#ifndef _SECURITY_SECIMPORTEXPORT_H_ -#define _SECURITY_SECIMPORTEXPORT_H_ - -#include -#include -#include -#include -#include -#include - -#if SEC_OS_OSX -#include -#include -#include -#include -#endif /* SEC_OS_OSX */ - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -#if SEC_OS_OSX -/* - * Supported import/export Formats - */ -typedef CF_ENUM(uint32_t, SecExternalFormat) -{ - /* - * When importing: unknown format - * When exporting: default format for item - */ - kSecFormatUnknown = 0, - - /* - * Public and Private Key formats. - * Default for export is kSecFormatOpenSSL. - */ - kSecFormatOpenSSL, /* a.k.a. X509 for public keys */ - kSecFormatSSH, /* OpenSSH v.1 */ - kSecFormatBSAFE, - - /* Symmetric Key Formats */ - kSecFormatRawKey, /* raw unformatted key bits; default */ - - /* Formats for wrapped symmetric and private keys */ - kSecFormatWrappedPKCS8, - kSecFormatWrappedOpenSSL, /* traditional openssl */ - kSecFormatWrappedSSH, /* OpenSSH v.1 */ - kSecFormatWrappedLSH, - - /* Formats for certificates */ - kSecFormatX509Cert, /* DER encoded; default */ - - /* Aggregate Types */ - kSecFormatPEMSequence, /* sequence of certs and/or keys, implies PEM - * armour. Default format for multiple items */ - kSecFormatPKCS7, /* sequence of certs */ - kSecFormatPKCS12, /* set of certs and private keys */ - kSecFormatNetscapeCertSequence, /* sequence of certs, form netscape-cert-sequence */ - - /* Added in Mac OS X 10.5 */ - kSecFormatSSHv2 /* OpenSSH v.2. Note that OpenSSH v2 private keys - * are in format kSecFormatOpenSSL or - * kSecFormatWrappedOpenSSL. */ -}; - -/* - * Indication of basic item type when importing. - */ -typedef CF_ENUM(uint32_t, SecExternalItemType) { - kSecItemTypeUnknown, /* caller doesn't know what this is */ - kSecItemTypePrivateKey, - kSecItemTypePublicKey, - kSecItemTypeSessionKey, - kSecItemTypeCertificate, - kSecItemTypeAggregate /* PKCS7, PKCS12, kSecFormatPEMSequence, etc. */ -}; - -/* - * Flags passed to SecKeychainItemExport() and SecKeychainItemImport(). - */ -typedef CF_OPTIONS(uint32_t, SecItemImportExportFlags) -{ - kSecItemPemArmour = 0x00000001, /* exported blob is PEM formatted */ -}; - -/* - * SecKeyRef-specific flags, specified in SecKeyImportExportParameters.flags - */ -typedef CF_OPTIONS(uint32_t, SecKeyImportExportFlags) -{ - /* - * When true, prevents the importing of more than one private key - * in a given SecKeychainItemImport(). - */ - kSecKeyImportOnlyOne = 0x00000001, - - /* - * When true, passphrase for import/export is obtained by user prompt - * instead of by caller-supplied data (SecKeyImportExportParameters.passphrase). - * This is the preferred method for obtaining a user-supplied passphrase - * as it avoids having the cleartext passphrase appear in the app's - * address space at any time. - */ - kSecKeySecurePassphrase = 0x00000002, - - /* - * When true, imported private keys will have no Access Control List - * (ACL) attached to them. In the absence of both this bit and the accessRef - * field in SecKeyImportExportParameters (see below), imported private - * keys are given a default ACL. - */ - kSecKeyNoAccessControl = 0x00000004 -}; - -/* - * Version of a SecKeyImportExportParameters. - */ -#define SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION 0 - -/* - * Parameters specific to SecKeyRefs. - */ -typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) -{ - /* for import and export */ - uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ - SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ - CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* - * formats only. Legal types are - * CFStringRef and CFDataRef. */ - CFStringRef alertTitle; /* title of secure passphrase alert panel */ - CFStringRef alertPrompt; /* prompt in secure passphrase alert panel */ - - /* for import only */ - SecAccessRef __nullable accessRef; /* specifies the initial ACL of imported - * key(s) */ - CSSM_KEYUSE keyUsage; /* CSSM_KEYUSE_DECRYPT, CSSM_KEYUSE_SIGN, - * etc. */ - CSSM_KEYATTR_FLAGS keyAttributes; /* CSSM_KEYATTR_PERMANENT, etc. */ -} SecKeyImportExportParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - - -typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) -{ - /* for import and export */ - uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ - SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ - CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* - * formats only. Legal types are - * CFStringRef and CFDataRef. */ - CFStringRef __nullable alertTitle; /* title of secure passphrase alert panel */ - CFStringRef __nullable alertPrompt; /* prompt in secure passphrase alert panel */ - - /* for import only */ - SecAccessRef __nullable accessRef; /* specifies the initial ACL of imported - * key(s) */ - CFArrayRef __nullable keyUsage; /* An Array containing usage attributes from SecItem.h, e.g. - * kSecAttrCanEncrypt;, kSecAttrCanDecrypt, kSecAttrCanDerive, etc. - */ - CFArrayRef __nullable keyAttributes; /* An array containing zero or more key attributes - * for an imported key. Possible values (from SecItem.h): - * kSecAttrIsPermanent, kSecAttrIsSensitive, kSecAttrIsExtractable - * Pass NULL in this field to use default attributes: - * - kSecAttrIsPermanent if a keychain is specified - * - kSecAttrIsSensitive for private keys - * - kSecAttrIsExtractable by default - */ -} SecItemImportExportKeyParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/* - * SecKeychainItemExport() - * - * This function takes one or more SecKeychainItemRefs and creates an - * external representation of the item(s) in the form of a CFDataRef. - * Caller specifies the format of the external representation via a - * SecExternalFormat enum. Caller may specify kSecFormatUnknown for - * the format, in which case a the default format for the item - * being exported is used (as described in the SecExternalFormat enums). - * PEM armouring is optional and is specified by the kSecItemPemArmour - * flag in importFlags. - * - * If exactly one item is to be exported, the keychainItemOrArray argument - * can be a SecKeychainItem. Otherwise this argument is a CFArrayRef - * containing a number of SecKeychainItems. - * - * The exported item(s) is (are) returned to the caller via the - * CFDataRef *exportedData argument. Caller must CFRelease the result. - * - * The following SecKeychainItems may be exported: - * - * SecCertificateRef - * SecKeyRef - * SecIdentityRef - * - * - * Key-related SecKeyImportExportParameters fields - * ----------------------------------------------- - * - * When exporting SecKeyRefs in one of the wrapped formats - * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, - * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must - * either explicitly specify the passphrase field or set - * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. - * - * If kSecKeySecurePassphrase is selected, caller can optionally - * specify strings for the passphrase panel's title bar and for - * the prompt which appears in the panel via the alertTitle and - * alertPrompt fields in SecKeyImportExportParameters. - * - * If an explicit passphrase is specified, note that PKCS12 - * explicitly requires that passphrases are in Unicode format; - * passing in a CFStringRef as the passphrase is the safest way - * to ensure that this requirement is met (and that the result - * will be compatible with other implementations). If a CFDataRef - * is supplied as the passphrase for a PKCS12 export operation, - * the referent data is assumed to be in UTF8 form and will be - * converted as appropriate. - * - * If no key items are being exported, the keyParams argument may be NULL. - * @discussion This API has been deprecated. Please us the SecItemExport API instead. - */ -OSStatus SecKeychainItemExport( - CFTypeRef keychainItemOrArray, - SecExternalFormat outputFormat, - SecItemImportExportFlags flags, /* kSecItemPemArmour, etc. */ - const SecKeyImportExportParameters * __nullable keyParams, /* optional */ - CFDataRef * __nonnull CF_RETURNS_RETAINED exportedData) /* external representation returned here */ - API_DEPRECATED_WITH_REPLACEMENT("SecItemExport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/* - * SecItemExport() - * - * This function takes one or more SecItemRefs and creates an - * external representation of the item(s) in the form of a CFDataRef. - * Caller specifies the format of the external representation via a - * SecExternalFormat enum. Caller may specify kSecFormatUnknown for - * the format, in which case a the default format for the item - * being exported is used (as described in the SecExternalFormat enums). - * PEM armouring is optional and is specified by the kSecItemPemArmour - * flag in importFlags. - * - * If exactly one item is to be exported, the keychainItemOrArray argument - * can be a SecKeychainItem. Otherwise this argument is a CFArrayRef - * containing a number of SecKeychainItems. - * - * The exported item(s) is (are) returned to the caller via the - * CFDataRef *exportedData argument. Caller must CFRelease the result. - * - * The following SecKeychainItems may be exported: - * - * SecCertificateRef - * SecKeyRef - * SecIdentityRef - * - * - * Key-related SecItemExport fields - * ----------------------------------------------- - * - * When exporting SecKeyRefs in one of the wrapped formats - * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, - * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must - * either explicitly specify the passphrase field or set - * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. - * - * If kSecKeySecurePassphrase is selected, caller can optionally - * specify strings for the passphrase panel's title bar and for - * the prompt which appears in the panel via the alertTitle and - * alertPrompt fields in SecItemImportExportKeyParameters. - * - * If an explicit passphrase is specified, note that PKCS12 - * explicitly requires that passphrases are in Unicode format; - * passing in a CFStringRef as the passphrase is the safest way - * to ensure that this requirement is met (and that the result - * will be compatible with other implementations). If a CFDataRef - * is supplied as the passphrase for a PKCS12 export operation, - * the referent data is assumed to be in UTF8 form and will be - * converted as appropriate. - * - * If no key items are being exported, the keyParams argument may be NULL. - * - */ -OSStatus SecItemExport( - CFTypeRef secItemOrArray, - SecExternalFormat outputFormat, - SecItemImportExportFlags flags, /* kSecItemPemArmour, etc. */ - const SecItemImportExportKeyParameters * __nullable keyParams, /* optional */ - CFDataRef * __nonnull CF_RETURNS_RETAINED exportedData) /* external representation returned here */ - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -/* - * SecKeychainItemImport() - * - * This function takes a CFDataRef containing the external representation - * of one or more objects and creates SecKeychainItems corresponding to - * those objects and optionally imports those SecKeychainItems into a - * specified keychain. The format of the incoming representation is - * specified by one or more of the following: - * - * -- A SecExternalFormat. This optional in/out argument is used when - * the caller knows exactly what format the external representation - * is in. It's also used to return to the caller the format which the - * function actually determines the external representation to be in. - * A value of kSecFormatUnknown is specified on entry when the caller - * wishes to know the inferred format on return. - * - * -- A SecExternalItemType - optional, in/out. Used to specify what kind - * of item is in the incoming representation, if known by the caller. - * It's also used to return to the caller the item type which the - * function actually determines the external representation to contain. - * A value of kSecItemTypeUnknown is specified on entry when the caller - * wishes to know the inferred item type on return. - * - * -- fileNameOrExtension, a CFStringRef. This optional argument contains - * the name of the file from which the external representation was - * obtained; it can also be simply an extension like CFSTR(".p7r"). - * This is a convenience for apps like KeychainAccess which can import a - * number of different formats. - * - * The SecKeychainItemImport() call does its best to figure out what is - * in an incoming external item given the info provided by the above three - * arguments. In most cases, SecKeychainItemImport() can even figure out - * what's in an external item if none of these are specified, but it would - * be unwise for an application to count on that ability. - * - * PEM formatting is determined internally via inspection of the incoming - * data, so the kSecItemPemArmour in the flags field is ignored. - * - * Zero, one, or both of the following occurs upon successful completion - * of this function: - * - * -- The imported item(s) is (are) imported to the specified importKeychain. - * If importKeychain is NULL, this step does not occur. - * - * -- The imported item(s) is (are) returned to the caller via the - * CFArrayRef *outItems argument. If outItems is NULL, this step - * does not occur. If outItems is NON-NULL, then *outItems will be - * a CFArrayRef containing a number of SecKeychainItems upon return. - * Caller must CFRelease the result. - * - * The possible types of returned SecKeychainItems are: - * - * SecCertificateRef - * SecKeyRef - * SecIdentityRef - * - * Note that when importing a PKCS12 blob, typically one SecIdentityRef - * and zero or more additional SecCertificateRefs are returned in - * outItems. No SecKeyRefs will appear there unless a key - * is found in the incoming blob with does not have a matching - * certificate. - * - * A typical case in which an app specifies the outItems - * argument and a NULL for importKeychain is when the app wishes to - * perform some user interaction, perhaps on a per-item basis, before - * committing to actually import the item(s). In this case, if the app - * does wish to proceed with the import, the standard import calls - * (SecCertificateAddToKeychain(), SecKeyAddToKeychain (implementation - * TBD)) would be used. - * - * Passing in NULL for both outItems and importKeychain - * is a perfectly acceptable way of using this function to determine, - * in a non-intrusive way, what is inside a given data blob. No effect - * other than returning inputFormat and/or itemType occurs in this - * case. - - * - * Key-related SecKeyImportExportParameters fields - * ----------------------------------------------- - * - * If importKeychain is NULL, the kSecKeyImportOnlyOne bit in the flags - * argument is ignored. Otherwise, if the kSecKeyImportOnlyOne bit is set, and - * there is more than one key in the incoming external representation, no - * items will be imported to the specified keychain and errSecMultipleKeys will - * be returned. - * - * The accessRef field allows the caller to specify the initial SecAccessRef - * for imported private keys. If more than one private key is being imported, - * all private keys get the same initial SecAccessRef. If this field is NULL - * when private keys are being imported, then the ACL attached to imported - * private keys depends on the kSecKeyNoAccessControl bit in the specified - * keyParams->flags. If this bit is 0, or keyParams is NULL, the default ACL - * will be used. If this bit is 1, no ACL will be attached to imported - * private keys. - * - * keyUsage and keyAttributes specify the low-level usage and attribute flags - * of imported keys. Each is a word of bits. The default value for keyUsage - * (used when keyParams is NULL or if keyParams->keyUsage is zero) is - * CSSM_KEYUSE_ANY. The default value for keyAttributes defaults is - * CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE; the CSSM_KEYATTR_PERMANENT - * bit is also added to the default if a non-NULL importKeychain is provided. - * - * The following are valid bits in keyAttributes: - * - * CSSM_KEYATTR_PERMANENT - * CSSM_KEYATTR_SENSITIVE - * CSSM_KEYATTR_EXTRACTABLE - * - * If the CSSM_KEYATTR_PERMANENT is set then the importKeychain argument must - * be valid or errSecInvalidKeychain will be returned if in fact any keys are found - * in the external representation. - * - * Note that if the caller does not set the CSSM_KEYATTR_EXTRACTABLE, this key - * will never be able to be extracted from the keychain in any form, not even - * in wrapped form. The CSSM_KEYATTR_SENSITIVE indicates that the key can only - * be extracted in wrapped form. - * - * The CSSM_KEYATTR_RETURN_xxx bits are always forced to - * CSSM_KEYATTR_RETURN_REF regardless of the specified keyAttributes - * field. - * - * When importing SecKeyRefs in one of the wrapped formats - * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, - * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must - * either explicitly specify the passphrase field or set - * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. - * - * If kSecKeySecurePassphrase is selected, caller can optionally - * specify strings for the passphrase panel's title bar and for - * the prompt which appears in the panel via the alertTitle and - * alertPrompt fields in SecKeyImportExportParameters. - * - * If an explicit passphrase is specified, note that PKCS12 - * explicitly requires that passphrases are in Unicode format; - * passing in a CFStringRef as the passphrase is the safest way - * to ensure that this requirement is met (and that the result - * will be compatible with other implementations). If a CFDataRef - * is supplied as the passphrase for a PKCS12 export operation, - * the referent data is assumed to be in UTF8 form and will be - * converted as appropriate. - - * If no key items are being imported, the keyParams argument may be NULL. - * - * The SecItemImportExportFlags argument is currently unused; caller should pass - * in 0. - * - * @discussion This API has been deprecated. Please use the SecItemImport API instead. - */ -OSStatus SecKeychainItemImport( - CFDataRef importedData, - CFStringRef __nullable fileNameOrExtension, /* optional */ - SecExternalFormat * __nullable inputFormat, /* optional, IN/OUT */ - SecExternalItemType * __nullable itemType, /* optional, IN/OUT */ - SecItemImportExportFlags flags, - const SecKeyImportExportParameters * __nullable keyParams, /* optional */ - SecKeychainRef __nullable importKeychain, /* optional */ - CFArrayRef * __nullable CF_RETURNS_RETAINED outItems) /* optional */ - API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/* - * SecItemImport() - * - * This function takes a CFDataRef containing the external representation - * of one or more objects and creates SecKeychainItems corresponding to - * those objects and optionally imports those SecKeychainItems into a - * specified keychain. The format of the incoming representation is - * specified by one or more of the following: - * - * -- A SecExternalFormat. This optional in/out argument is used when - * the caller knows exactly what format the external representation - * is in. It's also used to return to the caller the format which the - * function actually determines the external representation to be in. - * A value of kSecFormatUnknown is specified on entry when the caller - * wishes to know the inferred format on return. - * - * -- A SecExternalItemType - optional, in/out. Used to specify what kind - * of item is in the incoming representation, if known by the caller. - * It's also used to return to the caller the item type which the - * function actually determines the external representation to contain. - * A value of kSecItemTypeUnknown is specified on entry when the caller - * wishes to know the inferred item type on return. - * - * -- fileNameOrExtension, a CFStringRef. This optional argument contains - * the name of the file from which the external representation was - * obtained; it can also be simply an extension like CFSTR(".p7r"). - * This is a convenience for apps like KeychainAccess which can import a - * number of different formats. - * - * The SecItemImport() call does its best to figure out what is - * in an incoming external item given the info provided by the above three - * arguments. In most cases, SecItemImport() can even figure out - * what's in an external item if none of these are specified, but it would - * be unwise for an application to count on that ability. - * - * PEM formatting is determined internally via inspection of the incoming - * data, so the kSecItemPemArmour in the flags field is ignored. - * - * Zero, one, or both of the following occurs upon successful completion - * of this function: - * - * -- The imported item(s) is (are) imported to the specified importKeychain. - * If importKeychain is NULL, this step does not occur. - * - * -- The imported item(s) is (are) returned to the caller via the - * CFArrayRef *outItems argument. If outItems is NULL, this step - * does not occur. If outItems is NON-NULL, then *outItems will be - * a CFArrayRef containing a number of SecKeychainItems upon return. - * Caller must CFRelease the result. - * - * The possible types of returned SecKeychainItems are: - * - * SecCertificateRef - * SecKeyRef - * SecIdentityRef - * - * Note that when importing a PKCS12 blob, typically one SecIdentityRef - * and zero or more additional SecCertificateRefs are returned in - * outItems. No SecKeyRefs will appear there unless a key - * is found in the incoming blob with does not have a matching - * certificate. - * - * A typical case in which an app specifies the outItems - * argument and a NULL for importKeychain is when the app wishes to - * perform some user interaction, perhaps on a per-item basis, before - * committing to actually import the item(s). In this case, if the app - * does wish to proceed with the import, the standard import calls - * (SecCertificateAddToKeychain(), SecKeyAddToKeychain (implementation - * TBD)) would be used. - * - * Passing in NULL for both outItems and importKeychain - * is a perfectly acceptable way of using this function to determine, - * in a non-intrusive way, what is inside a given data blob. No effect - * other than returning inputFormat and/or itemType occurs in this - * case. - - * - * Key-related SecItemImportExportKeyParameters fields - * ----------------------------------------------- - * - * If importKeychain is NULL, the kSecKeyImportOnlyOne bit in the flags - * argument is ignored. Otherwise, if the kSecKeyImportOnlyOne bit is set, and - * there is more than one key in the incoming external representation, no - * items will be imported to the specified keychain and errSecMultipleKeys will - * be returned. - * - * The accessRef field allows the caller to specify the initial SecAccessRef - * for imported private keys. If more than one private key is being imported, - * all private keys get the same initial SecAccessRef. If this field is NULL - * when private keys are being imported, then the ACL attached to imported - * private keys depends on the kSecKeyNoAccessControl bit in the specified - * keyParams->flags. If this bit is 0, or keyParams is NULL, the default ACL - * will be used. If this bit is 1, no ACL will be attached to imported - * private keys. - * - * keyUsage and keyAttributes specify the low-level usage and attribute flags - * of imported keys. These fields contain a CFArray whose values are constants - * from SecItem.h. - * - * Possible values in the keyUsage array: - * - * kSecAttrCanEncrypt - * kSecAttrCanDecrypt - * kSecAttrCanDerive - * kSecAttrCanSign - * kSecAttrCanVerify - * kSecAttrCanWrap - * kSecAttrCanUnwrap - * - * If keyUsage is set to NULL, then any key usage is permitted. - * - * Possible values in the keyAttributes array: - * - * kSecAttrIsPermanent - * kSecAttrIsSensitive - * kSecAttrIsExtractable - * - * If keyAttributes is set to NULL, then default values are used: - * kSecAttrIsPermanent if an import keychain is specified - * kSecAttrIsSensitive for non-public keys - * kSecAttrIsExtractable - * - * If the kSecAttrIsPermanent attribute is set, then the - * importKeychain argument must be valid or errSecInvalidKeychain - * will be returned even if keys were able to be imported. - * - * Note that if the caller provides a keyAttributes array but - * does not set kSecAttrIsExtractable, this key will never be - * able to be extracted from the keychain in any form, not even - * in wrapped form. kSecAttrIsSensitive indicates that the key - * can only be extracted in wrapped form. - * - * When importing SecKeyRefs in one of the wrapped formats - * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, - * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must - * either explicitly specify the passphrase field or set - * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. - * - * If kSecKeySecurePassphrase is selected, caller can optionally - * specify strings for the passphrase panel's title bar and for - * the prompt which appears in the panel via the alertTitle and - * alertPrompt fields in SecItemImportExportKeyParameters. - * - * If an explicit passphrase is specified, note that PKCS12 - * explicitly requires that passphrases are in Unicode format; - * passing in a CFStringRef as the passphrase is the safest way - * to ensure that this requirement is met (and that the result - * will be compatible with other implementations). If a CFDataRef - * is supplied as the passphrase for a PKCS12 export operation, - * the referent data is assumed to be in UTF8 form and will be - * converted as appropriate. - - * If no key items are being imported, the keyParams argument may be NULL. - * - * The SecItemImportExportFlags argument is currently unused; caller should pass - * in 0. - */ -OSStatus SecItemImport( - CFDataRef importedData, - CFStringRef __nullable fileNameOrExtension, /* optional */ - SecExternalFormat * __nullable inputFormat, /* optional, IN/OUT */ - SecExternalItemType * __nullable itemType, /* optional, IN/OUT */ - SecItemImportExportFlags flags, - const SecItemImportExportKeyParameters * __nullable keyParams, /* optional */ - SecKeychainRef __nullable importKeychain, /* optional */ - CFArrayRef * __nullable CF_RETURNS_RETAINED outItems) /* optional */ - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -#endif /* SEC_OS_OSX */ - -/*! - @enum Import/Export options - @discussion Predefined key constants used when passing dictionary-based arguments to import/export functions. - @constant kSecImportExportPassphrase Specifies a passphrase represented by a CFStringRef to be used when exporting to (or importing from) PKCS#12 format. - @constant kSecImportExportKeychain On OSX, specifies a keychain represented by a SecKeychainRef to be used as the target when importing from PKCS#12 format. - @constant kSecImportExportAccess On OSX, specifies an access represented by a SecAccessRef for the initial access (ACL) of a key imported from PKCS#12 format. -*/ -extern const CFStringRef kSecImportExportPassphrase - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecImportExportKeychain - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecImportExportAccess - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); - -/*! - @enum Import/Export item description - @discussion Predefined key constants used to pass back a CFArray with a - CFDictionary per item. - - @constant kSecImportItemLabel a CFStringRef representing the item label. - This implementation specific identifier cannot be expected to have - any format. - @constant kSecImportItemKeyID a CFDataRef representing the key id. Often - the SHA-1 digest of the public key. - @constant kSecImportItemIdentity a SecIdentityRef representing the identity. - @constant kSecImportItemTrust a SecTrustRef set up with all relevant - certificates. Not guaranteed to succesfully evaluate. - @constant kSecImportItemCertChain a CFArrayRef holding all relevant - certificates for this item's identity -*/ -extern const CFStringRef kSecImportItemLabel - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecImportItemKeyID - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecImportItemTrust - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecImportItemCertChain - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecImportItemIdentity - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @function SecPKCS12Import - @abstract Imports the contents of a PKCS12 formatted blob. - @param pkcs12_data The PKCS#12 formatted data to be imported. - @param options A dictionary containing import options. A - kSecImportExportPassphrase entry is required at minimum. Only password-based - PKCS12 blobs are currently supported. - @param items On return, an array containing a dictionary for every item - extracted. Use kSecImportItem constants to access specific elements of - these dictionaries. Your code must CFRelease the array when it is no longer - needed. - @result errSecSuccess in case of success. errSecDecode means either the - blob can't be read or it is malformed. errSecAuthFailed means an - incorrect password was supplied, or data in the container is damaged. -*/ -OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items) - API_AVAILABLE(macos(10.6), ios(2.0)); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECIMPORTEXPORT_H_ */ diff --git a/keychain/SecImportExportPriv.h b/keychain/SecImportExportPriv.h deleted file mode 100644 index 6d43101f..00000000 --- a/keychain/SecImportExportPriv.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _SECURITY_SECIMPORTEXPORTPRIV_H_ -#define _SECURITY_SECIMPORTEXPORTPRIV_H_ - -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -#if TARGET_OS_OSX -OSStatus SecPKCS12Import_ios(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items) - SPI_AVAILABLE(macos(10.15), iosmac(13.0)) API_UNAVAILABLE(ios, watchos, tvos); -#endif - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECIMPORTEXPORTPRIV_H_ */ diff --git a/keychain/SecItem.h b/keychain/SecItem.h deleted file mode 100644 index f39dabbc..00000000 --- a/keychain/SecItem.h +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItem - SecItem defines CoreFoundation-based constants and functions for - access to Security items (certificates, keys, identities, and - passwords.) -*/ - -#ifndef _SECURITY_SECITEM_H_ -#define _SECURITY_SECITEM_H_ - -#include -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @enum Class Key Constant - @discussion Predefined key constant used to get or set item class values in - a dictionary. Its value is one of the constants defined in the Value - Constants for kSecClass. - @constant kSecClass Specifies a dictionary key whose value is the item's - class code. You use this key to get or set a value of type CFTypeRef - that contains the item class code. -*/ -extern const CFStringRef kSecClass - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @enum Class Value Constants - @discussion Predefined item class constants used to get or set values in - a dictionary. The kSecClass constant is the key and its value is one - of the constants defined here. Note: on Mac OS X 10.6, only items - of class kSecClassInternetPassword are supported. - @constant kSecClassInternetPassword Specifies Internet password items. - @constant kSecClassGenericPassword Specifies generic password items. - @constant kSecClassCertificate Specifies certificate items. - @constant kSecClassKey Specifies key items. - @constant kSecClassIdentity Specifies identity items. -*/ -extern const CFStringRef kSecClassInternetPassword - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecClassGenericPassword - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecClassCertificate - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecClassKey - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecClassIdentity - API_AVAILABLE(macos(10.7), ios(2.0)); - -/*! - @enum Attribute Key Constants - @discussion Predefined item attribute keys used to get or set values in a - dictionary. Not all attributes apply to each item class. The table - below lists the currently defined attributes for each item class: - - kSecClassGenericPassword item attributes: - kSecAttrAccess (OS X only) - kSecAttrAccessControl - kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrCreationDate - kSecAttrModificationDate - kSecAttrDescription - kSecAttrComment - kSecAttrCreator - kSecAttrType - kSecAttrLabel - kSecAttrIsInvisible - kSecAttrIsNegative - kSecAttrAccount - kSecAttrService - kSecAttrGeneric - kSecAttrSynchronizable - - kSecClassInternetPassword item attributes: - kSecAttrAccess (OS X only) - kSecAttrAccessControl - kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrCreationDate - kSecAttrModificationDate - kSecAttrDescription - kSecAttrComment - kSecAttrCreator - kSecAttrType - kSecAttrLabel - kSecAttrIsInvisible - kSecAttrIsNegative - kSecAttrAccount - kSecAttrSecurityDomain - kSecAttrServer - kSecAttrProtocol - kSecAttrAuthenticationType - kSecAttrPort - kSecAttrPath - kSecAttrSynchronizable - - kSecClassCertificate item attributes: - kSecAttrAccessible (iOS only) - kSecAttrAccessControl (iOS only) - kSecAttrAccessGroup (iOS only) - kSecAttrCertificateType - kSecAttrCertificateEncoding - kSecAttrLabel - kSecAttrSubject - kSecAttrIssuer - kSecAttrSerialNumber - kSecAttrSubjectKeyID - kSecAttrPublicKeyHash - kSecAttrSynchronizable - - kSecClassKey item attributes: - kSecAttrAccess (OS X only) - kSecAttrAccessControl - kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) - kSecAttrKeyClass - kSecAttrLabel - kSecAttrApplicationLabel - kSecAttrIsPermanent - kSecAttrApplicationTag - kSecAttrKeyType - kSecAttrPRF (OS X only) - kSecAttrSalt (OS X only) - kSecAttrRounds (OS X only) - kSecAttrKeySizeInBits - kSecAttrEffectiveKeySize - kSecAttrCanEncrypt - kSecAttrCanDecrypt - kSecAttrCanDerive - kSecAttrCanSign - kSecAttrCanVerify - kSecAttrCanWrap - kSecAttrCanUnwrap - kSecAttrSynchronizable - - Note that the attributes kSecAttrCan* describe attributes of the - key itself at relatively high level. Some of these attributes are - mathematical -- for example, a DSA key cannot encrypt. Others are - key-level policy issues -- for example, it is good cryptographic - hygiene to use an RSA key either for encryption or signing but not - both. Compare these to the certificate-level policy values in - SecPolicy.h. - - kSecClassIdentity item attributes: - Since an identity is the combination of a private key and a - certificate, this class shares attributes of both kSecClassKey and - kSecClassCertificate. - - @constant kSecAttrAccessible Specifies a dictionary key whose value - indicates when your application needs access to an item's data. You - should choose the most restrictive option that meets your application's - needs to allow the system to protect that item in the best way possible. - See the "kSecAttrAccessible Value Constants" section for a list of - values which can be specified. - IMPORTANT: This attribute is currently not supported for OS X keychain - items, unless the kSecAttrSynchronizable attribute is also present. If - both attributes are specified on either OS X or iOS, the value for the - kSecAttrAccessible key may only be one whose name does not end with - "ThisDeviceOnly", as those cannot sync to another device. - - @constant kSecAttrAccessControl Specifies a dictionary key whose value - is SecAccessControl instance which contains access control conditions - for item. - IMPORTANT: This attribute is mutually exclusive with kSecAttrAccess - attribute. - - @constant kSecAttrAccess Specifies a dictionary key whose value - is a SecAccessRef describing the access control settings for this item. - This key is available on OS X only. - - @constant kSecAttrAccessGroup Specifies a dictionary key whose value is - a CFStringRef indicating which access group a item is in. The access - groups that a particular application has membership in are determined by - two entitlements for that application. The application-identifier - entitlement contains the application's single access group, unless - there is a keychain-access-groups entitlement present. The latter - has as its value a list of access groups; the first item in this list - is the default access group. Unless a specific access group is provided - as the value of kSecAttrAccessGroup when SecItemAdd is called, new items - are created in the application's default access group. Specifying this - attribute in SecItemCopyMatching, SecItemUpdate, or SecItemDelete calls - limits the search to the specified access group (of which the calling - application must be a member to obtain matching results.) To share - keychain items between multiple applications, each application must have - a common group listed in its keychain-access-groups entitlement, and each - must specify this shared access group name as the value for the - kSecAttrAccessGroup key in the dictionary passed to SecItem functions. - - @constant kSecAttrSynchronizable Specifies a dictionary key whose value is - a CFBooleanRef indicating whether the item in question can be synchronized. - To add a new item which can be synced to other devices, or to obtain - synchronizable results from a query, supply this key with a value of - kCFBooleanTrue. If the key is not supplied, or has a value of - kCFBooleanFalse, then no synchronizable items will be added or returned. - A predefined value, kSecAttrSynchronizableAny, may be provided instead of - kCFBooleanTrue if both synchronizable and non-synchronizable results are - desired. - - IMPORTANT: Specifying the kSecAttrSynchronizable key has several caveats: - - - Updating or deleting items using the kSecAttrSynchronizable key will - affect all copies of the item, not just the one on your local device. - Be sure that it makes sense to use the same password on all devices - before deciding to make a password synchronizable. - - Only password items can currently be synchronized. Keychain syncing - is not supported for certificates or cryptographic keys. - - Items stored or obtained using the kSecAttrSynchronizable key cannot - specify SecAccessRef-based access control with kSecAttrAccess. If a - password is intended to be shared between multiple applications, the - kSecAttrAccessGroup key must be specified, and each application - using this password must have a 'keychain-access-groups' entitlement - with the specified access group value. - - Items stored or obtained using the kSecAttrSynchronizable key may - not also specify a kSecAttrAccessible value which is incompatible - with syncing (namely, those whose names end with "ThisDeviceOnly".) - - Items stored or obtained using the kSecAttrSynchronizable key cannot - be specified by reference. You must pass kSecReturnAttributes and/or - kSecReturnData to retrieve results; kSecReturnRef is currently not - supported for synchronizable items. - - Persistent references to synchronizable items should be avoided; - while they may work locally, they cannot be moved between devices, - and may not resolve if the item is modified on some other device. - - When specifying a query that uses the kSecAttrSynchronizable key, - search keys are limited to the item's class and attributes. - The only search constant which may be used is kSecMatchLimit; other - constants using the kSecMatch prefix are not supported at this time. - - @constant kSecAttrSynchronizableAny Specifies that both synchronizable and - non-synchronizable results should be returned from this query. This may be - used as a value for the kSecAttrSynchronizable dictionary key in a call to - SecItemCopyMatching, SecItemUpdate, or SecItemDelete. - - @constant kSecAttrCreationDate (read-only) Specifies a dictionary key whose - value is the item's creation date. You use this key to get a value - of type CFDateRef that represents the date the item was created. - @constant kSecAttrModificationDate (read-only) Specifies a dictionary key - whose value is the item's modification date. You use this key to get - a value of type CFDateRef that represents the last time the item was - updated. - @constant kSecAttrDescription Specifies a dictionary key whose value is - the item's description attribute. You use this key to set or get a - value of type CFStringRef that represents a user-visible string - describing this particular kind of item (e.g., "disk image password"). - @constant kSecAttrComment Specifies a dictionary key whose value is the - item's comment attribute. You use this key to set or get a value of - type CFStringRef containing the user-editable comment for this item. - @constant kSecAttrCreator Specifies a dictionary key whose value is the - item's creator attribute. You use this key to set or get a value of - type CFNumberRef that represents the item's creator. This number is - the unsigned integer representation of a four-character code (e.g., - 'aCrt'). - @constant kSecAttrType Specifies a dictionary key whose value is the item's - type attribute. You use this key to set or get a value of type - CFNumberRef that represents the item's type. This number is the - unsigned integer representation of a four-character code (e.g., - 'aTyp'). - @constant kSecAttrLabel Specifies a dictionary key whose value is the - item's label attribute. You use this key to set or get a value of - type CFStringRef containing the user-visible label for this item. - @constant kSecAttrIsInvisible Specifies a dictionary key whose value is the - item's invisible attribute. You use this key to set or get a value - of type CFBooleanRef that indicates whether the item is invisible - (i.e., should not be displayed.) - @constant kSecAttrIsNegative Specifies a dictionary key whose value is the - item's negative attribute. You use this key to set or get a value of - type CFBooleanRef that indicates whether there is a valid password - associated with this keychain item. This is useful if your application - doesn't want a password for some particular service to be stored in - the keychain, but prefers that it always be entered by the user. - @constant kSecAttrAccount Specifies a dictionary key whose value is the - item's account attribute. You use this key to set or get a CFStringRef - that contains an account name. (Items of class - kSecClassGenericPassword, kSecClassInternetPassword have this - attribute.) - @constant kSecAttrService Specifies a dictionary key whose value is the - item's service attribute. You use this key to set or get a CFStringRef - that represents the service associated with this item. (Items of class - kSecClassGenericPassword have this attribute.) - @constant kSecAttrGeneric Specifies a dictionary key whose value is the - item's generic attribute. You use this key to set or get a value of - CFDataRef that contains a user-defined attribute. (Items of class - kSecClassGenericPassword have this attribute.) - @constant kSecAttrSecurityDomain Specifies a dictionary key whose value - is the item's security domain attribute. You use this key to set or - get a CFStringRef value that represents the Internet security domain. - (Items of class kSecClassInternetPassword have this attribute.) - @constant kSecAttrServer Specifies a dictionary key whose value is the - item's server attribute. You use this key to set or get a value of - type CFStringRef that contains the server's domain name or IP address. - (Items of class kSecClassInternetPassword have this attribute.) - @constant kSecAttrProtocol Specifies a dictionary key whose value is the - item's protocol attribute. You use this key to set or get a value of - type CFNumberRef that denotes the protocol for this item (see the - SecProtocolType enum in SecKeychainItem.h). (Items of class - kSecClassInternetPassword have this attribute.) - @constant kSecAttrAuthenticationType Specifies a dictionary key whose value - is the item's authentication type attribute. You use this key to set - or get a value of type CFNumberRef that denotes the authentication - scheme for this item (see the kSecAttrAuthenticationType value - constants below). - @constant kSecAttrPort Specifies a dictionary key whose value is the item's - port attribute. You use this key to set or get a CFNumberRef value - that represents an Internet port number. (Items of class - kSecClassInternetPassword have this attribute.) - @constant kSecAttrPath Specifies a dictionary key whose value is the item's - path attribute, typically this is the path component of the URL. You use - this key to set or get a CFStringRef value that represents a path. (Items - of class kSecClassInternetPassword have this attribute.) - @constant kSecAttrSubject (read-only) Specifies a dictionary key whose - value is the item's subject. You use this key to get a value of type - CFDataRef that contains the X.500 subject name of a certificate. - (Items of class kSecClassCertificate have this attribute.) - @constant kSecAttrIssuer (read-only) Specifies a dictionary key whose value - is the item's issuer. You use this key to get a value of type - CFDataRef that contains the X.500 issuer name of a certificate. (Items - of class kSecClassCertificate have this attribute.) - @constant kSecAttrSerialNumber (read-only) Specifies a dictionary key whose - value is the item's serial number. You use this key to get a value - of type CFDataRef that contains the serial number data of a - certificate. (Items of class kSecClassCertificate have this - attribute.) - @constant kSecAttrSubjectKeyID (read-only) Specifies a dictionary key whose - value is the item's subject key ID. You use this key to get a value - of type CFDataRef that contains the subject key ID of a certificate. - (Items of class kSecClassCertificate have this attribute.) - @constant kSecAttrPublicKeyHash (read-only) Specifies a dictionary key - whose value is the item's public key hash. You use this key to get a - value of type CFDataRef that contains the hash of a certificate's - public key. (Items of class kSecClassCertificate have this attribute.) - @constant kSecAttrCertificateType (read-only) Specifies a dictionary key - whose value is the item's certificate type. You use this key to get - a value of type CFNumberRef that denotes the certificate type - (On iOS, currently the value of this attribute must be equal to the - version of the X509 certificate. So, 1 for v1, 2 for v2, and 3 for v3 - certificates). (On OSX, see the CSSM_CERT_TYPE enum in cssmtype.h). - Only items of class kSecClassCertificate have this attribute. - @constant kSecAttrCertificateEncoding (read-only) Specifies a dictionary - key whose value is the item's certificate encoding. You use this key - to get a value of type CFNumberRef that denotes the certificate - encoding (On iOS, currently only the value 3 meaning - kSecAttrCertificateEncodingDER is supported). On OSX, see the - CSSM_CERT_ENCODING enum in cssmtype.h. Only items of class - kSecClassCertificate have this attribute. - @constant kSecAttrKeyClass (read only) Specifies a dictionary key whose - value is one of kSecAttrKeyClassPublic, kSecAttrKeyClassPrivate or - kSecAttrKeyClassSymmetric. - @constant kSecAttrApplicationLabel Specifies a dictionary key whose value - is the key's application label attribute. This is different from the - kSecAttrLabel (which is intended to be human-readable). This attribute - is used to look up a key programmatically; in particular, for keys of - class kSecAttrKeyClassPublic and kSecAttrKeyClassPrivate, the value of - this attribute is the hash of the public key. This item is a type of CFDataRef. - Legacy keys may contain a UUID in this field as a CFStringRef. - @constant kSecAttrIsPermanent Specifies a dictionary key whose value is a - CFBooleanRef indicating whether the key in question will be stored - permanently. - @constant kSecAttrIsSensitive Specifies a dictionary key whose value is a - CFBooleanRef indicating that the key in question can only be exported - in a wrapped (encrypted) format. OS X only. - @constant kSecAttrIsExtractable Specifies a dictionary key whose value is a - CFBooleanRef indicating whether the key in question can be exported from - its keychain container. OS X only. - @constant kSecAttrApplicationTag Specifies a dictionary key whose value is a - CFDataRef containing private tag data. - @constant kSecAttrKeyType Specifies a dictionary key whose value is a - CFNumberRef indicating the algorithm associated with this key - (On iOS, currently only the value 42 is supported, alternatively you can use - kSecAttrKeyTypeRSA). (On OSX, see the CSSM_ALGORITHMS enum in cssmtype.h). - - @constant kSecAttrPRF Specifies a dictionary key whose value is the PRF - (pseudo-random function) for this key (see "kSecAttrPRF Value Constants".) - OS X only. - @constant kSecAttrSalt Specifies a dictionary key whose value is a - CFData containing the salt to use for this key. OS X only. - @constant kSecAttrRounds Specifies a dictionary key whose value is the - number of rounds for the pseudo-random function specified by kSecAttrPRF. - OS X only. - @constant kSecAttrKeySizeInBits Specifies a dictionary key whose value - is a CFNumberRef indicating the number of bits in this key. - @constant kSecAttrEffectiveKeySize Specifies a dictionary key whose value - is a CFNumberRef indicating the effective number of bits in this key. - For example, a DES key has a kSecAttrKeySizeInBits of 64, but a - kSecAttrEffectiveKeySize of 56 bits. - @constant kSecAttrCanEncrypt Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - encrypt data. - @constant kSecAttrCanDecrypt Specifies a dictionary key whose value is a - CFBooleanRef indicating whether the key in question can be used to - decrypt data. - @constant kSecAttrCanDerive Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - derive another key. - @constant kSecAttrCanSign Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - create a digital signature. - @constant kSecAttrCanVerify Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - verify a digital signature. - @constant kSecAttrCanWrap Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - wrap another key. - @constant kSecAttrCanUnwrap Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - unwrap another key. - @constant kSecAttrSyncViewHint Specifies a dictionary key whose value is - a CFStringRef. This value is part of the primary key of each item, and - can be used to help distiguish Sync Views when defining their - queries. iOS and sychronizable items only. - @constant kSecAttrTokenID Specifies a dictionary key whose presence - indicates that item is backed by external token. Value of this attribute - is CFStringRef uniquely identifying containing token. When this attribute - is not present, item is stored in internal keychain database. - Note that once item is created, this attribute cannot be changed - in other - words it is not possible to migrate existing items to, from or between tokens. - Currently the only available value for this attribute is - kSecAttrTokenIDSecureEnclave, which indicates that item (private key) is - backed by device's Secure Enclave. - */ -extern const CFStringRef kSecAttrAccessible - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrAccess - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrAccessControl - API_AVAILABLE(macos(10.10), ios(8.0)); -extern const CFStringRef kSecAttrAccessGroup - API_AVAILABLE(macos(10.9), ios(3.0)); -extern const CFStringRef kSecAttrSynchronizable - API_AVAILABLE(macos(10.9), ios(7.0)); -extern const CFStringRef kSecAttrSynchronizableAny - API_AVAILABLE(macos(10.9), ios(7.0)); -extern const CFStringRef kSecAttrCreationDate - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrModificationDate - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrDescription - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrComment - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCreator - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrType - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrLabel - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIsInvisible - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIsNegative - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAccount - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrService - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrGeneric - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrSecurityDomain - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrServer - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocol - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationType - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrPort - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrPath - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrSubject - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIssuer - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrSerialNumber - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrSubjectKeyID - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrPublicKeyHash - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCertificateType - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCertificateEncoding - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrKeyClass - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrApplicationLabel - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIsPermanent - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIsSensitive - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrIsExtractable - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrApplicationTag - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrKeyType - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrPRF - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrSalt - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrRounds - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeySizeInBits - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrEffectiveKeySize - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanEncrypt - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanDecrypt - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanDerive - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanSign - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanVerify - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanWrap - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrCanUnwrap - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrSyncViewHint - API_AVAILABLE(macos(10.11), ios(9.0)); -extern const CFStringRef kSecAttrTokenID - API_AVAILABLE(macos(10.12), ios(9.0)); -extern const CFStringRef kSecAttrPersistantReference - API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); -extern const CFStringRef kSecAttrPersistentReference - API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); - -/*! - @enum kSecAttrAccessible Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecAttrAccessible constant is the key and its - value is one of the constants defined here. - When asking SecItemCopyMatching to return the item's data, the error - errSecInteractionNotAllowed will be returned if the item's data is not - available until a device unlock occurs. - @constant kSecAttrAccessibleWhenUnlocked Item data can only be accessed - while the device is unlocked. This is recommended for items that only - need be accesible while the application is in the foreground. Items - with this attribute will migrate to a new device when using encrypted - backups. - @constant kSecAttrAccessibleAfterFirstUnlock Item data can only be - accessed once the device has been unlocked after a restart. This is - recommended for items that need to be accesible by background - applications. Items with this attribute will migrate to a new device - when using encrypted backups. - @constant kSecAttrAccessibleAlways Item data can always be accessed - regardless of the lock state of the device. This is not recommended - for anything except system use. Items with this attribute will migrate - to a new device when using encrypted backups. - @constant kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly Item data can - only be accessed while the device is unlocked. This is recommended for - items that only need to be accessible while the application is in the - foreground and requires a passcode to be set on the device. Items with - this attribute will never migrate to a new device, so after a backup - is restored to a new device, these items will be missing. This - attribute will not be available on devices without a passcode. Disabling - the device passcode will cause all previously protected items to - be deleted. - @constant kSecAttrAccessibleWhenUnlockedThisDeviceOnly Item data can only - be accessed while the device is unlocked. This is recommended for items - that only need be accesible while the application is in the foreground. - Items with this attribute will never migrate to a new device, so after - a backup is restored to a new device, these items will be missing. - @constant kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly Item data can - only be accessed once the device has been unlocked after a restart. - This is recommended for items that need to be accessible by background - applications. Items with this attribute will never migrate to a new - device, so after a backup is restored to a new device these items will - be missing. - @constant kSecAttrAccessibleAlwaysThisDeviceOnly Item data can always - be accessed regardless of the lock state of the device. This option - is not recommended for anything except system use. Items with this - attribute will never migrate to a new device, so after a backup is - restored to a new device, these items will be missing. -*/ -extern const CFStringRef kSecAttrAccessibleWhenUnlocked - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrAccessibleAfterFirstUnlock - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrAccessibleAlways - API_DEPRECATED("Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlock", macos(10.9, 10.14), ios(4.0, 12.0)); -extern const CFStringRef kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly - API_AVAILABLE(macos(10.10), ios(8.0)); -extern const CFStringRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrAccessibleAlwaysThisDeviceOnly - API_DEPRECATED("Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly", macos(10.9, 10.14), ios(4.0, 12.0)); - -/*! - @enum kSecAttrProtocol Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecAttrProtocol constant is the key and its - value is one of the constants defined here. - @constant kSecAttrProtocolFTP. - @constant kSecAttrProtocolFTPAccount. - @constant kSecAttrProtocolHTTP. - @constant kSecAttrProtocolIRC. - @constant kSecAttrProtocolNNTP. - @constant kSecAttrProtocolPOP3. - @constant kSecAttrProtocolSMTP. - @constant kSecAttrProtocolSOCKS. - @constant kSecAttrProtocolIMAP. - @constant kSecAttrProtocolLDAP. - @constant kSecAttrProtocolAppleTalk. - @constant kSecAttrProtocolAFP. - @constant kSecAttrProtocolTelnet. - @constant kSecAttrProtocolSSH. - @constant kSecAttrProtocolFTPS. - @constant kSecAttrProtocolHTTPS. - @constant kSecAttrProtocolHTTPProxy. - @constant kSecAttrProtocolHTTPSProxy. - @constant kSecAttrProtocolFTPProxy. - @constant kSecAttrProtocolSMB. - @constant kSecAttrProtocolRTSP. - @constant kSecAttrProtocolRTSPProxy. - @constant kSecAttrProtocolDAAP. - @constant kSecAttrProtocolEPPC. - @constant kSecAttrProtocolIPP. - @constant kSecAttrProtocolNNTPS. - @constant kSecAttrProtocolLDAPS. - @constant kSecAttrProtocolTelnetS. - @constant kSecAttrProtocolIMAPS. - @constant kSecAttrProtocolIRCS. - @constant kSecAttrProtocolPOP3S. -*/ -extern const CFStringRef kSecAttrProtocolFTP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolFTPAccount - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolHTTP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolIRC - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolNNTP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolPOP3 - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolSMTP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolSOCKS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolIMAP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolLDAP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolAppleTalk - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolAFP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolTelnet - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolSSH - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolFTPS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolHTTPS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolHTTPProxy - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolHTTPSProxy - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolFTPProxy - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolSMB - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolRTSP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolRTSPProxy - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolDAAP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolEPPC - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolIPP - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolNNTPS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolLDAPS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolTelnetS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolIMAPS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolIRCS - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrProtocolPOP3S - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @enum kSecAttrAuthenticationType Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecAttrAuthenticationType constant is the key - and its value is one of the constants defined here. - @constant kSecAttrAuthenticationTypeNTLM. - @constant kSecAttrAuthenticationTypeMSN. - @constant kSecAttrAuthenticationTypeDPA. - @constant kSecAttrAuthenticationTypeRPA. - @constant kSecAttrAuthenticationTypeHTTPBasic. - @constant kSecAttrAuthenticationTypeHTTPDigest. - @constant kSecAttrAuthenticationTypeHTMLForm. - @constant kSecAttrAuthenticationTypeDefault. -*/ -extern const CFStringRef kSecAttrAuthenticationTypeNTLM - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeMSN - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeDPA - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeRPA - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeHTTPBasic - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeHTTPDigest - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeHTMLForm - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecAttrAuthenticationTypeDefault - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @enum kSecAttrKeyClass Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecAttrKeyClass constant is the key - and its value is one of the constants defined here. - @constant kSecAttrKeyClassPublic. - @constant kSecAttrKeyClassPrivate. - @constant kSecAttrKeyClassSymmetric. -*/ -extern const CFStringRef kSecAttrKeyClassPublic - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecAttrKeyClassPrivate - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecAttrKeyClassSymmetric - API_AVAILABLE(macos(10.7), ios(2.0)); - -/*! - @enum kSecAttrKeyType Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecAttrKeyType constant is the key - and its value is one of the constants defined here. - @constant kSecAttrKeyTypeECSECPrimeRandom. - @constant kSecAttrKeyTypeEC This is the legacy name for kSecAttrKeyTypeECSECPrimeRandom, new applications should not use it. - @constant kSecAttrKeyTypeDSA (OSX only) - @constant kSecAttrKeyTypeAES (OSX only) - @constant kSecAttrKeyType3DES (OSX only) - @constant kSecAttrKeyTypeRC4 (OSX only) - @constant kSecAttrKeyTypeRC2 (OSX only) - @constant kSecAttrKeyTypeCAST (OSX only) - @constant kSecAttrKeyTypeECDSA (deprecated; use kSecAttrKeyTypeECSECPrimeRandom instead.) (OSX only) -*/ -extern const CFStringRef kSecAttrKeyTypeRSA - API_AVAILABLE(macos(10.7), ios(2.0)); -extern const CFStringRef kSecAttrKeyTypeDSA - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeAES - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeDES - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyType3DES - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeRC4 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeRC2 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeCAST - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeECDSA - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrKeyTypeEC - API_AVAILABLE(macos(10.9), ios(4.0)); -extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandom - API_AVAILABLE(macos(10.12), ios(10.0)); - -/* - @enum kSecAttrPRF Value Constants - @discussion Predefined item attribute constants used to specify the PRF - to use with SecKeyDeriveFromPassword. OS X only. - @constant kSecAttrPRFHmacAlgSHA1 - @constant kSecAttrPRFHmacAlgSHA224 - @constant kSecAttrPRFHmacAlgSHA256 - @constant kSecAttrPRFHmacAlgSHA384 - @constant kSecAttrPRFHmacAlgSHA512 -*/ -extern const CFStringRef kSecAttrPRFHmacAlgSHA1 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrPRFHmacAlgSHA224 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrPRFHmacAlgSHA256 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrPRFHmacAlgSHA384 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecAttrPRFHmacAlgSHA512 - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); - - -/*! - @enum Search Constants - @discussion Predefined search constants used to set values in a query - dictionary. You can specify a combination of search attributes and - item attributes when looking for matching items with the - SecItemCopyMatching function. - @constant kSecMatchPolicy Specifies a dictionary key whose value is a - SecPolicyRef. If provided, returned certificates or identities must - verify with this policy. - @constant kSecMatchItemList OS X only. Specifies a dictionary key whose value is a - CFArray of SecKeychainItemRef items. If provided, returned items will be - limited to the subset which are contained in this list. - @constant kSecMatchSearchList Specifies a dictionary key whose value is a - CFArray of SecKeychainRef items. If provided, the search will be limited - to the keychains contained in this list. - @constant kSecMatchIssuers Specifies a dictionary key whose value is a - CFArray of X.500 names (of type CFDataRef). If provided, returned - certificates or identities will be limited to those whose - certificate chain contains one of the issuers provided in this list. - @constant kSecMatchEmailAddressIfPresent Specifies a dictionary key whose - value is a CFStringRef containing an RFC822 email address. If - provided, returned certificates or identities will be limited to those - that contain the address, or do not contain any email address. - @constant kSecMatchSubjectContains Specifies a dictionary key whose value - is a CFStringRef. If provided, returned certificates or identities - will be limited to those containing this string in the subject. - @constant kSecMatchSubjectStartsWith OS X only. Specifies a dictionary key whose value - is a CFStringRef. If provided, returned certificates or identities - will be limited to those with subject names that start with this string. - @constant kSecMatchSubjectEndsWith OS X only. Specifies a dictionary key whose value - is a CFStringRef. If provided, returned certificates or identities - will be limited to those with subject names that end with this string. - @constant kSecMatchSubjectWholeString OS X only. Specifies a dictionary key whose - value is a CFStringRef. If provided, returned certificates or identities - will be limited to those matching this string exactly in the subject. - @constant kSecMatchCaseInsensitive Specifies a dictionary key whose value - is a CFBooleanRef. If this value is kCFBooleanFalse, or is not - provided, then case-sensitive string matching is performed. - @constant kSecMatchDiacriticInsensitive OS X only. Specifies a dictionary key whose - value is a CFBooleanRef. If this value is kCFBooleanFalse, or is not - provided, then diacritic-sensitive string matching is performed. - @constant kSecMatchWidthInsensitive OS X only. Specifies a dictionary key whose - value is a CFBooleanRef. If this value is kCFBooleanFalse, or is not - provided, then string matching is width-sensitive (e.g. 'a' != 0xFF41). - @constant kSecMatchTrustedOnly Specifies a dictionary key whose value is - a CFBooleanRef. If provided with a value of kCFBooleanTrue, only - certificates which can be verified back to a trusted anchor will be - returned. If this value is kCFBooleanFalse, or is not provided, then - both trusted and untrusted certificates may be returned. - @constant kSecMatchValidOnDate Specifies a dictionary key whose value is - of type CFDateRef. If provided, returned keys, certificates or - identities will be limited to those which are valid for the given date. - Pass a value of kCFNull to indicate the current date. - @constant kSecMatchLimit Specifies a dictionary key whose value is a - CFNumberRef. If provided, this value specifies the maximum number of - results to return. If not provided, results are limited to the first - item found. Predefined values are provided for a single item - (kSecMatchLimitOne) and all matching items (kSecMatchLimitAll). - @constant kSecMatchLimitOne Specifies that results are limited to the first - item found; used as a value for the kSecMatchLimit dictionary key. - @constant kSecMatchLimitAll Specifies that an unlimited number of results - may be returned; used as a value for the kSecMatchLimit dictionary - key. -*/ -extern const CFStringRef kSecMatchPolicy - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchItemList - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchSearchList - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchIssuers - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchEmailAddressIfPresent - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchSubjectContains - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchSubjectStartsWith - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecMatchSubjectEndsWith - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecMatchSubjectWholeString - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecMatchCaseInsensitive - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchDiacriticInsensitive - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecMatchWidthInsensitive - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecMatchTrustedOnly - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchValidOnDate - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchLimit - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchLimitOne - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecMatchLimitAll - API_AVAILABLE(macos(10.6), ios(2.0)); - - -/*! - @enum Return Type Key Constants - @discussion Predefined return type keys used to set values in a dictionary. - You use these keys to specify the type of results which should be - returned by the SecItemCopyMatching or SecItemAdd function. You can - specify zero or more of these return types. If more than one of these - result types is specified, the result is returned as a CFDictionaryRef - whose keys are the result types and values are the requested data. - @constant kSecReturnData Specifies a dictionary key whose value is of type - CFBooleanRef. A value of kCFBooleanTrue indicates that the data of - an item (CFDataRef) should be returned. For keys and password - items, data is secret (encrypted) and may require the user to enter - a password for access. - @constant kSecReturnAttributes Specifies a dictionary key whose value is - of type CFBooleanRef. A value of kCFBooleanTrue indicates that the - (non-encrypted) attributes of an item (CFDictionaryRef) should be - returned. - @constant kSecReturnRef Specifies a dictionary key whose value is a - CFBooleanRef. A value of kCFBooleanTrue indicates that a reference - should be returned. Depending on the item class requested, the - returned reference(s) may be of type SecKeychainItemRef, SecKeyRef, - SecCertificateRef, or SecIdentityRef. - @constant kSecReturnPersistentRef Specifies a dictionary key whose value - is of type CFBooleanRef. A value of kCFBooleanTrue indicates that a - persistent reference to an item (CFDataRef) should be returned. -*/ -extern const CFStringRef kSecReturnData - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecReturnAttributes - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecReturnRef - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecReturnPersistentRef - API_AVAILABLE(macos(10.6), ios(2.0)); - - -/*! - @enum Value Type Key Constants - @discussion Predefined value type keys used to pass values in a dictionary. - You can specify zero or more of these types depending on the function - you are calling. For SecItemCopyMatching or SecItemAdd these are - used as keys in the results dictionary. - @constant kSecValueData Specifies a dictionary key whose value is of type - CFDataRef. For keys and password items, data is secret (encrypted) - and may require the user to enter a password for access. - @constant kSecValueRef Specifies a dictionary key whose value, depending - on the item class requested, is of type SecKeychainItemRef, SecKeyRef, - SecCertificateRef, or SecIdentityRef. - @constant kSecValuePersistentRef Specifies a dictionary key whose value - is of type CFDataRef. The bytes in this CFDataRef can be stored by - the caller and used on a subsequent invocation of the application (or - even a different application) to retrieve the item referenced by it. -*/ -extern const CFStringRef kSecValueData - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecValueRef - API_AVAILABLE(macos(10.6), ios(2.0)); -extern const CFStringRef kSecValuePersistentRef - API_AVAILABLE(macos(10.6), ios(2.0)); - - -/*! - @enum Other Constants - @discussion Predefined constants used to set values in a dictionary. - @constant kSecUseItemList Specifies a dictionary key whose value is a - CFArray of items. If provided, this array is treated as the set of - all possible items to search, or add if the API being called is - SecItemAdd. The items in this array may be of type SecKeyRef, - SecCertificateRef, SecIdentityRef, or CFDataRef (for a persistent - item reference.) The items in the array must all be of the same - type. When this attribute is provided, no keychains are searched. - @constant kSecUseKeychain OS X only. Specifies a dictionary key whose value is a - keychain reference. You use this key to specify a value of type - SecKeychainRef to which SecItemAdd will add the provided item(s). - @constant kSecUseOperationPrompt Specifies a dictionary key whose value - is a CFStringRef that represents a user-visible string describing - the operation for which the application is attempting to authenticate. - The application is responsible for the text localization. - @constant kSecUseNoAuthenticationUI OS X only. Specifies a dictionary key whose value - is a CFBooleanRef. If provided with a value of kCFBooleanTrue, the error - errSecInteractionNotAllowed will be returned if the item is attempting - to authenticate with UI. - @constant kSecUseAuthenticationUI Specifies a dictionary key whose value - is one of kSecUseAuthenticationUIAllow, kSecUseAuthenticationUIFail, kSecUseAuthenticationUISkip. - @constant kSecUseAuthenticationContext Specifies a dictionary key whose value - is LAContext to be used for keychain item authentication. - * If the item requires authentication and this key is omitted, a new context - will be created just for the purpose of the single call. - * If the specified context has been previously authenticated, the operation - will succeed without asking user for authentication. - * If the specified context has not been previously authenticated, the new - authentication will be started on this context, allowing caller to - eventually reuse the successfully authenticated context in subsequent - keychain operations. - @constant kSecUseDataProtectionKeychain Specifies a dictionary key whose value - is a CFBooleanRef. Set to kCFBooleanTrue to use kSecAttrAccessGroup and/or - kSecAttrAccessible on macOS without requiring the item to be marked synchronizable. -*/ -extern const CFStringRef kSecUseItemList - API_AVAILABLE(macos(10.6)) - API_DEPRECATED("Not implemented on this platform", ios(2.0, 12.0), tvos(9.0, 12.0), watchos(1.0, 5.0)) - API_UNAVAILABLE(bridgeos, iosmac); -extern const CFStringRef kSecUseKeychain - API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); -extern const CFStringRef kSecUseOperationPrompt - API_AVAILABLE(macos(10.10), ios(8.0)); -extern const CFStringRef kSecUseNoAuthenticationUI - API_DEPRECATED("Use kSecUseAuthenticationUI instead.", macos(10.10, 10.11), ios(8.0, 9.0)); -extern const CFStringRef kSecUseAuthenticationUI - API_AVAILABLE(macos(10.11), ios(9.0)); -extern const CFStringRef kSecUseAuthenticationContext - API_AVAILABLE(macos(10.11), ios(9.0)); -extern const CFStringRef kSecUseDataProtectionKeychain - API_AVAILABLE(macos(10.15), ios(13.0)); - -/*! - @enum kSecUseAuthenticationUI Value Constants - @discussion Predefined item attribute constants used to get or set values - in a dictionary. The kSecUseAuthenticationUI constant is the key and its - value is one of the constants defined here. - If the key kSecUseAuthenticationUI not provided then kSecUseAuthenticationUIAllow - is used as default. - @constant kSecUseAuthenticationUIAllow Specifies that authenticate UI can appear. - @constant kSecUseAuthenticationUIFail Specifies that the error - errSecInteractionNotAllowed will be returned if an item needs - to authenticate with UI - @constant kSecUseAuthenticationUIAllowSkip Specifies that all items which need - to authenticate with UI will be silently skipped. This value can be used - only with SecItemCopyMatching. -*/ -extern const CFStringRef kSecUseAuthenticationUIAllow - API_AVAILABLE(macos(10.11), ios(9.0)); -extern const CFStringRef kSecUseAuthenticationUIFail - API_AVAILABLE(macos(10.11), ios(9.0)); -extern const CFStringRef kSecUseAuthenticationUISkip - API_AVAILABLE(macos(10.11), ios(9.0)); - -/*! - @enum kSecAttrTokenID Value Constants - @discussion Predefined item attribute constant used to get or set values - in a dictionary. The kSecAttrTokenID constant is the key and its value - can be kSecAttrTokenIDSecureEnclave. - @constant kSecAttrTokenIDSecureEnclave Specifies well-known identifier of the - token implemented using device's Secure Enclave. The only keychain items - supported by the Secure Enclave token are 256-bit elliptic curve keys - (kSecAttrKeyTypeECSecPrimeRandom). Keys must be generated on the secure enclave using - SecKeyGenerateKeyPair call with kSecAttrTokenID set to - kSecAttrTokenIDSecureEnclave in the parameters dictionary, it is not - possible to import pregenerated keys to kSecAttrTokenIDSecureEnclave token. -*/ -extern const CFStringRef kSecAttrTokenIDSecureEnclave - API_AVAILABLE(macos(10.12), ios(9.0)); - -/*! - @enum kSecAttrAccessGroup Value Constants - @constant kSecAttrAccessGroupToken Represents well-known access group - which contains items provided by external token (typically smart card). - This may be used as a value for kSecAttrAccessGroup attribute. Every - application has access to this access group so it is not needed to - explicitly list it in keychain-access-groups entitlement, but application - must explicitly state this access group in keychain queries in order to - be able to access items from external tokens. -*/ -extern const CFStringRef kSecAttrAccessGroupToken - API_AVAILABLE(macos(10.12), ios(10.0)); - -/*! - @function SecItemCopyMatching - @abstract Returns one or more items which match a search query. - @param query A dictionary containing an item class specification and - optional attributes for controlling the search. See the "Keychain - Search Attributes" section for a description of currently defined - search attributes. - @param result On return, a CFTypeRef reference to the found item(s). The - exact type of the result is based on the search attributes supplied - in the query, as discussed below. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Attributes defining a search are specified by adding key/value - pairs to the query dictionary. - - A typical query consists of: - - * a kSecClass key, whose value is a constant from the Class - Constants section that specifies the class of item(s) to be searched - * one or more keys from the "Attribute Key Constants" section, whose value - is the attribute data to be matched - * one or more keys from the "Search Constants" section, whose value is - used to further refine the search - * a key from the "Return Type Key Constants" section, specifying the type of - results desired - - Result types are specified as follows: - - * To obtain the data of a matching item (CFDataRef), specify - kSecReturnData with a value of kCFBooleanTrue. - * To obtain the attributes of a matching item (CFDictionaryRef), specify - kSecReturnAttributes with a value of kCFBooleanTrue. - * To obtain a reference to a matching item (SecKeychainItemRef, - SecKeyRef, SecCertificateRef, or SecIdentityRef), specify kSecReturnRef - with a value of kCFBooleanTrue. - * To obtain a persistent reference to a matching item (CFDataRef), - specify kSecReturnPersistentRef with a value of kCFBooleanTrue. Note - that unlike normal references, a persistent reference may be stored - on disk or passed between processes. - * If more than one of these result types is specified, the result is - returned as a CFDictionaryRef containing all the requested data. - * If a result type is not specified, no results are returned. - - By default, this function returns only the first match found. To obtain - more than one matching item at a time, specify kSecMatchLimit with a value - greater than 1. The result will be a CFArrayRef containing up to that - number of matching items; the items' types are described above. - - To filter a provided list of items down to those matching the query, - specify a kSecMatchItemList whose value is a CFArray of SecKeychainItemRef, - SecKeyRef, SecCertificateRef, or SecIdentityRef items. The objects in the - provided array must be of the same type. - - On iOS, to convert from a persistent item reference to a normal item reference, - specify a kSecValuePersistentRef whose value a CFDataRef (the persistent - reference), and a kSecReturnRef whose value is kCFBooleanTrue. - - On OSX, to convert from persistent item references to normal item references, - specify a kSecMatchItemList whose value is a CFArray containing one or - more CFDataRef elements (the persistent reference), and a kSecReturnRef - whose value is kCFBooleanTrue. The objects in the provided array must be - of the same type. -*/ -OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result) - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @function SecItemAdd - @abstract Add one or more items to a keychain. - @param attributes A dictionary containing an item class specification and - optional entries specifying the item's attribute values. See the - "Attribute Key Constants" section for a description of currently defined - attributes. - @param result On return, a CFTypeRef reference to the newly added item(s). - The exact type of the result is based on the values supplied - in attributes, as discussed below. Pass NULL if this result is not - required. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Attributes defining an item are specified by adding key/value - pairs to the attributes dictionary. To add multiple items to a keychain - at once use the kSecUseItemList key with an array of items as its value. - This is currently only supported for non password items. - - On OSX, To add an item to a particular keychain, supply kSecUseKeychain - with a SecKeychainRef as its value. - - Result types are specified as follows: - - * To obtain the data of the added item (CFDataRef), specify - kSecReturnData with a value of kCFBooleanTrue. - * To obtain all the attributes of the added item (CFDictionaryRef), - specify kSecReturnAttributes with a value of kCFBooleanTrue. - * To obtain a reference to the added item (SecKeychainItemRef, SecKeyRef, - SecCertiicateRef, or SecIdentityRef), specify kSecReturnRef with a - value of kCFBooleanTrue. - * To obtain a persistent reference to the added item (CFDataRef), specify - kSecReturnPersistentRef with a value of kCFBooleanTrue. Note that - unlike normal references, a persistent reference may be stored on disk - or passed between processes. - * If more than one of these result types is specified, the result is - returned as a CFDictionaryRef containing all the requested data. - * On iOS, if a result type is not specified, no results are returned. - On OSX, the added item is returned. -*/ -OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result) - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @function SecItemUpdate - @abstract Modify zero or more items which match a search query. - @param query A dictionary containing an item class specification and - optional attributes for controlling the search. See the "Attribute - Constants" and "Search Constants" sections for a description of - currently defined search attributes. - @param attributesToUpdate A dictionary containing one or more attributes - whose values should be set to the ones specified. Only real keychain - attributes are permitted in this dictionary (no "meta" attributes are - allowed.) See the "Attribute Key Constants" section for a description of - currently defined value attributes. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Attributes defining a search are specified by adding key/value - pairs to the query dictionary. -*/ -OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) - API_AVAILABLE(macos(10.6), ios(2.0)); - -/*! - @function SecItemDelete - @abstract Delete zero or more items which match a search query. - @param query A dictionary containing an item class specification and - optional attributes for controlling the search. See the "Attribute - Constants" and "Search Constants" sections for a description of - currently defined search attributes. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Attributes defining a search are specified by adding key/value - pairs to the query dictionary. - - By default, this function deletes all items matching the specified query. - You can change this behavior by specifying one of the follow keys: - - * To delete an item identified by a transient reference, on iOS, specify - kSecValueRef with a item reference. On OS X, give a kSecMatchItemList - containing an item reference. - * To delete an item identified by a persistent reference, on iOS, specify - kSecValuePersistentRef with a persistent reference returned by - using the kSecReturnPersistentRef key to SecItemCopyMatching or - SecItemAdd. on OSX, use kSecMatchItemList with a persistent reference - returned by using the kSecReturnPersistentRef key with - SecItemCopyMatching or SecItemAdd. - * To delete multiple items specify kSecMatchItemList with an array - of references. - * If more than one of these result keys is specified, the behavior is - undefined. -*/ -OSStatus SecItemDelete(CFDictionaryRef query) - API_AVAILABLE(macos(10.6), ios(2.0)); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECITEM_H_ */ diff --git a/keychain/SecItemPriv.h b/keychain/SecItemPriv.h deleted file mode 100644 index c458816d..00000000 --- a/keychain/SecItemPriv.h +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecItemPriv - SecItemPriv defines private constants and SPI functions for access to - Security items (certificates, identities, keys, and keychain items.) -*/ - -#ifndef _SECURITY_SECITEMPRIV_H_ -#define _SECURITY_SECITEMPRIV_H_ - -#include -#include -#include -#include -#include -#include - -#if TARGET_OS_OSX -#include -#endif - -#if __OBJC__ -#import -#endif - -__BEGIN_DECLS - -/*! - @enum Class Value Constants (Private) - @discussion Predefined item class constants used to get or set values in - a dictionary. The kSecClass constant is the key and its value is one - of the constants defined here. - @constant kSecClassAppleSharePassword Specifies AppleShare password items. -*/ -extern const CFStringRef kSecClassAppleSharePassword; - - -/*! - @enum Attribute Key Constants (Private) - @discussion Predefined item attribute keys used to get or set values in a - dictionary. Not all attributes apply to each item class. The table - below lists the currently defined attributes for each item class: - - kSecClassGenericPassword item attributes: - kSecAttrAccessGroup - kSecAttrCreationDate - kSecAttrModificationDate - kSecAttrDescription - kSecAttrComment - kSecAttrCreator - kSecAttrType - kSecAttrScriptCode (private) - kSecAttrLabel - kSecAttrAlias (private) - kSecAttrIsInvisible - kSecAttrIsNegative - kSecAttrHasCustomIcon (private) - kSecAttrProtected (private) - kSecAttrAccount - kSecAttrService - kSecAttrGeneric - kSecAttrSynchronizable - kSecAttrSyncViewHint - - kSecClassInternetPassword item attributes: - kSecAttrAccessGroup - kSecAttrCreationDate - kSecAttrModificationDate - kSecAttrDescription - kSecAttrComment - kSecAttrCreator - kSecAttrType - kSecAttrScriptCode (private) - kSecAttrLabel - kSecAttrAlias (private) - kSecAttrIsInvisible - kSecAttrIsNegative - kSecAttrHasCustomIcon (private) - kSecAttrProtected (private) - kSecAttrAccount - kSecAttrSecurityDomain - kSecAttrServer - kSecAttrProtocol - kSecAttrAuthenticationType - kSecAttrPort - kSecAttrPath - kSecAttrSynchronizable - kSecAttrSyncViewHint - - kSecClassAppleSharePassword item attributes: - kSecAttrAccessGroup - kSecAttrCreationDate - kSecAttrModificationDate - kSecAttrDescription - kSecAttrComment - kSecAttrCreator - kSecAttrType - kSecAttrScriptCode (private) - kSecAttrLabel - kSecAttrAlias (private) - kSecAttrIsInvisible - kSecAttrIsNegative - kSecAttrHasCustomIcon (private) - kSecAttrProtected (private) - kSecAttrAccount - kSecAttrVolume - kSecAttrAddress - kSecAttrAFPServerSignature - kSecAttrSynchronizable - kSecAttrSyncViewHint - - kSecClassCertificate item attributes: - kSecAttrAccessGroup - kSecAttrCertificateType - kSecAttrCertificateEncoding - kSecAttrLabel - kSecAttrAlias (private) - kSecAttrSubject - kSecAttrIssuer - kSecAttrSerialNumber - kSecAttrSubjectKeyID - kSecAttrPublicKeyHash - kSecAttrSynchronizable - kSecAttrSyncViewHint - - kSecClassKey item attributes: - kSecAttrAccessGroup - kSecAttrKeyClass - kSecAttrLabel - kSecAttrAlias (private) - kSecAttrApplicationLabel - kSecAttrIsPermanent - kSecAttrIsPrivate (private) - kSecAttrIsModifiable (private) - kSecAttrApplicationTag - kSecAttrKeyCreator (private) - kSecAttrKeyType - kSecAttrKeySizeInBits - kSecAttrEffectiveKeySize - kSecAttrStartDate (private) - kSecAttrEndDate (private) - kSecAttrIsSensitive (private) - kSecAttrWasAlwaysSensitive (private) - kSecAttrIsExtractable (private) - kSecAttrWasNeverExtractable (private) - kSecAttrCanEncrypt - kSecAttrCanDecrypt - kSecAttrCanDerive - kSecAttrCanSign - kSecAttrCanVerify - kSecAttrCanSignRecover (private) - kSecAttrCanVerifyRecover (private) - kSecAttrCanWrap - kSecAttrCanUnwrap - kSecAttrSynchronizable - kSecAttrSyncViewHint - - kSecClassIdentity item attributes: - Since an identity is the combination of a private key and a - certificate, this class shares attributes of both kSecClassKey and - kSecClassCertificate. - - @constant kSecAttrScriptCode Specifies a dictionary key whose value is the - item's script code attribute. You use this tag to set or get a value - of type CFNumberRef that represents a script code for this item's - strings. (Note: use of this attribute is deprecated; string attributes - should always be stored in UTF-8 encoding. This is currently private - for use by syncing; new code should not ever access this attribute.) - @constant kSecAttrAlias Specifies a dictionary key whose value is the - item's alias. You use this key to get or set a value of type CFDataRef - which represents an alias. For certificate items, the alias is either - a single email address, an array of email addresses, or the common - name of the certificate if it does not contain any email address. - (Items of class kSecClassCertificate have this attribute.) - @constant kSecAttrHasCustomIcon Specifies a dictionary key whose value is the - item's custom icon attribute. You use this tag to set or get a value - of type CFBooleanRef that indicates whether the item should have an - application-specific icon. (Note: use of this attribute is deprecated; - custom item icons are not supported in Mac OS X. This is currently - private for use by syncing; new code should not use this attribute.) - @constant kSecAttrVolume Specifies a dictionary key whose value is the - item's volume attribute. You use this key to set or get a CFStringRef - value that represents an AppleShare volume name. (Items of class - kSecClassAppleSharePassword have this attribute.) - @constant kSecAttrAddress Specifies a dictionary key whose value is the - item's address attribute. You use this key to set or get a CFStringRef - value that contains the AppleTalk zone name, or the IP or domain name - that represents the server address. (Items of class - kSecClassAppleSharePassword have this attribute.) - @constant kSecAttrAFPServerSignature Specifies a dictionary key whose value - is the item's AFP server signature attribute. You use this key to set - or get a CFDataRef value containing 16 bytes that represents the - server's signature block. (Items of class kSecClassAppleSharePassword - have this attribute.) - @constant kSecAttrCRLType (read-only) Specifies a dictionary key whose - value is the item's certificate revocation list type. You use this - key to get a value of type CFNumberRef that denotes the CRL type (see - the CSSM_CRL_TYPE enum in cssmtype.h). (Items of class - kSecClassCertificate have this attribute.) - @constant kSecAttrCRLEncoding (read-only) Specifies a dictionary key whose - value is the item's certificate revocation list encoding. You use - this key to get a value of type CFNumberRef that denotes the CRL - encoding (see the CSSM_CRL_ENCODING enum in cssmtype.h). (Items of - class kSecClassCertificate have this attribute.) - @constant kSecAttrKeyCreator Specifies a dictionary key whose value is a - CFDataRef containing a CSSM_GUID structure representing the module ID of - the CSP that owns this key. - @constant kSecAttrIsPrivate Specifies a dictionary key whose value is a - CFBooleanRef indicating whether the raw key material of the key in - question is private. - @constant kSecAttrIsModifiable Specifies a dictionary key whose value is a - CFBooleanRef indicating whether any of the attributes of this key are - modifiable. - @constant kSecAttrStartDate Specifies a dictionary key whose value is a - CFDateRef indicating the earliest date on which this key may be used. - If kSecAttrStartDate is not present, the restriction does not apply. - @constant kSecAttrEndDate Specifies a dictionary key whose value is a - CFDateRef indicating the last date on which this key may be used. - If kSecAttrEndDate is not present, the restriction does not apply. - @constant kSecAttrIsSensitive Specifies a dictionary key whose value - is a CFBooleanRef indicating whether the key in question must be wrapped - with an algorithm other than CSSM_ALGID_NONE. - @constant kSecAttrWasAlwaysSensitive Specifies a dictionary key whose value - is a CFBooleanRef indicating that the key in question has always been - marked as sensitive. - @constant kSecAttrIsExtractable Specifies a dictionary key whose value - is a CFBooleanRef indicating whether the key in question may be wrapped. - @constant kSecAttrWasNeverExtractable Specifies a dictionary key whose value - is a CFBooleanRef indicating that the key in question has never been - marked as extractable. - @constant kSecAttrCanSignRecover Specifies a dictionary key whole value is a - CFBooleanRef indicating whether the key in question can be used to - perform sign recovery. - @constant kSecAttrCanVerifyRecover Specifies a dictionary key whole value is - a CFBooleanRef indicating whether the key in question can be used to - perform verify recovery. - @constant kSecAttrTombstone Specifies a dictionary key whose value is - a CFBooleanRef indicating that the item in question is a tombstone. - @constant kSecAttrNoLegacy Specifies a dictionary key whose - value is a CFBooleanRef indicating that the query must be run on the - syncable backend even for non syncable items. This attribute is deprecated - in favor of the kSecUseDataProtectionKeychain API attribute. -*/ -extern const CFStringRef kSecAttrScriptCode; -extern const CFStringRef kSecAttrAlias; -extern const CFStringRef kSecAttrHasCustomIcon; -extern const CFStringRef kSecAttrVolume; -extern const CFStringRef kSecAttrAddress; -extern const CFStringRef kSecAttrAFPServerSignature; -extern const CFStringRef kSecAttrCRLType; -extern const CFStringRef kSecAttrCRLEncoding; -extern const CFStringRef kSecAttrKeyCreator; -extern const CFStringRef kSecAttrIsPrivate; -extern const CFStringRef kSecAttrIsModifiable; -extern const CFStringRef kSecAttrStartDate; -extern const CFStringRef kSecAttrEndDate; -extern const CFStringRef kSecAttrIsSensitive; -extern const CFStringRef kSecAttrWasAlwaysSensitive; -extern const CFStringRef kSecAttrIsExtractable; -extern const CFStringRef kSecAttrWasNeverExtractable; -extern const CFStringRef kSecAttrCanSignRecover; -extern const CFStringRef kSecAttrCanVerifyRecover; -extern const CFStringRef kSecAttrTombstone; -extern const CFStringRef kSecAttrNoLegacy - __API_DEPRECATED_WITH_REPLACEMENT("kSecUseDataProtectionKeychain", macos(10.11, 10.15), ios(9.3, 13.0), tvos(9.3, 13.0), watchos(2.3, 6.0)); -extern const CFStringRef kSecAttrSyncViewHint - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecAttrMultiUser - __OSX_AVAILABLE(10.11.5) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); - -/* This will force the syncing system to derive an item's plaintext synchronization id from its primary key. - * This might leak primary key information, but will cause syncing devices to discover sync conflicts sooner. - * Protected by the kSecEntitlementPrivateCKKSPlaintextFields entitlement. - * - * Will only be respected during a SecItemAdd. - */ -extern const CFStringRef kSecAttrDeriveSyncIDFromItemAttributes -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrPCSPlaintextServiceIdentifier - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrPCSPlaintextPublicKey - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrPCSPlaintextPublicIdentity - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -// ObjectID of item stored on the token. Token-type specific BLOB. -// For kSecAttrTokenIDSecureEnclave and kSecAttrTokenIDAppleKeyStore, ObjectID is libaks's blob representation of encoded key. -extern const CFStringRef kSecAttrTokenOID - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const CFStringRef kSecAttrUUID - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrSysBound - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrSHA1 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -#define kSecSecAttrSysBoundNot 0 -#define kSecSecAttrSysBoundPreserveDuringRestore 1 - - -extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandomPKA - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecAttrKeyTypeSecureEnclaveAttestation - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -// Should not be used, use kSecAttrTokenOID instead. -extern const CFStringRef kSecAttrSecureEnclaveKeyBlob - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @enum kSecAttrAccessible Value Constants (Private) - @constant kSecAttrAccessibleAlwaysPrivate Private alias for kSecAttrAccessibleAlways, - which is going to be deprecated for 3rd party use. - @constant kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate for kSecAttrAccessibleAlwaysThisDeviceOnly, - which is going to be deprecated for 3rd party use. - @constant kSecAttrAccessibleUntilReboot Not usable for keychain item. Can be used only - for generating non-permanent SEP-based SecKey. Such key does not need any keybag loaded and - is valid only until next reboot. Also known as class F protection. -*/ -extern const CFStringRef kSecAttrAccessibleAlwaysPrivate -;//%%% __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate -;//%%% __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecAttrAccessibleUntilReboot -API_AVAILABLE(macos(10.14.1), ios(12.1), tvos(12.1), watchos(5.1)); - -/* View Hint Constants */ - -extern const CFStringRef kSecAttrViewHintPCSMasterKey; -extern const CFStringRef kSecAttrViewHintPCSiCloudDrive; -extern const CFStringRef kSecAttrViewHintPCSPhotos; -extern const CFStringRef kSecAttrViewHintPCSCloudKit; -extern const CFStringRef kSecAttrViewHintPCSEscrow; -extern const CFStringRef kSecAttrViewHintPCSFDE; -extern const CFStringRef kSecAttrViewHintPCSMailDrop; -extern const CFStringRef kSecAttrViewHintPCSiCloudBackup; -extern const CFStringRef kSecAttrViewHintPCSNotes; -extern const CFStringRef kSecAttrViewHintPCSiMessage; -extern const CFStringRef kSecAttrViewHintPCSFeldspar; -extern const CFStringRef kSecAttrViewHintPCSSharing; - -extern const CFStringRef kSecAttrViewHintAppleTV; -extern const CFStringRef kSecAttrViewHintHomeKit; -extern const CFStringRef kSecAttrViewHintContinuityUnlock; -extern const CFStringRef kSecAttrViewHintAccessoryPairing; -extern const CFStringRef kSecAttrViewHintNanoRegistry; -extern const CFStringRef kSecAttrViewHintWatchMigration; -extern const CFStringRef kSecAttrViewHintEngram; -extern const CFStringRef kSecAttrViewHintManatee; -extern const CFStringRef kSecAttrViewHintAutoUnlock; -extern const CFStringRef kSecAttrViewHintHealth; -extern const CFStringRef kSecAttrViewHintApplePay; -extern const CFStringRef kSecAttrViewHintHome; -extern const CFStringRef kSecAttrViewHintLimitedPeersAllowed; - - -extern const CFStringRef kSecUseSystemKeychain - __TVOS_AVAILABLE(9.2) - __WATCHOS_AVAILABLE(3.0) - __OSX_AVAILABLE(10.11.4) - __IOS_AVAILABLE(9.3); - -extern const CFStringRef kSecUseSyncBubbleKeychain - __TVOS_AVAILABLE(9.2) - __WATCHOS_AVAILABLE(3.0) - __OSX_AVAILABLE(10.11.4) - __IOS_AVAILABLE(9.3); - -/*! - @enum Other Constants (Private) - @discussion Predefined constants used to set values in a dictionary. - @constant kSecUseTombstones Specifies a dictionary key whose value is a - CFBooleanRef if present this overrides the default behaviour for when - we make tombstones. The default being we create tombstones for - synchronizable items unless we are explicitly deleting or updating a - tombstone. Setting this to false when calling SecItemDelete or - SecItemUpdate will ensure no tombstones are created. Setting it to - true will ensure we create tombstones even when deleting or updating non - synchronizable items. - @constant kSecUseKeychain Specifies a dictionary key whose value is a - keychain reference. You use this key to specify a value of type - SecKeychainRef that indicates the keychain to which SecItemAdd - will add the provided item(s). - @constant kSecUseKeychainList Specifies a dictionary key whose value is - either an array of keychains to search (CFArrayRef), or a single - keychain (SecKeychainRef). If not provided, the user's default - keychain list is searched. kSecUseKeychainList is ignored if an - explicit kSecUseItemList is also provided. This key can be used - for the SecItemCopyMatching, SecItemUpdate and SecItemDelete calls. - @constant kSecUseCredentialReference Specifies a CFDataRef containing - AppleCredentialManager reference handle to be used when authorizing access - to the item. - @constant kSecUseCallerName Specifies a dictionary key whose value - is a CFStringRef that represents a user-visible string describing - the caller name for which the application is attempting to authenticate. - The caller must have 'com.apple.private.LocalAuthentication.CallerName' - entitlement set to YES to use this feature, otherwise it is ignored. - @constant kSecUseTokenRawItems If set to true, token-based items (i.e. those - which have non-empty kSecAttrTokenID are not going through client-side - postprocessing, only raw form stored in the database is listed. This - flag is ignored in other operations than SecItemCopyMatching(). - @constant kSecUseCertificatesWithMatchIssuers If set to true, - SecItemCopyMatching allows to return certificates when kSecMatchIssuers is specified. -*/ -extern const CFStringRef kSecUseTombstones - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecUseCredentialReference - __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); -extern const CFStringRef kSecUseCallerName - __OSX_AVAILABLE(10.11.4) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); -extern const CFStringRef kSecUseTokenRawItems - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecUseCertificatesWithMatchIssuers - __OSX_AVAILABLE(10.14) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); - -extern const CFStringRef kSOSInternalAccessGroup - __OSX_AVAILABLE(10.9) __IOS_AVAILABLE(7.0) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); - -/*! - @enum kSecAttrTokenID Value Constants - @discussion Predefined item attribute constant used to get or set values - in a dictionary. The kSecAttrTokenID constant is the key and its value - can be kSecAttrTokenIDSecureEnclave. - @constant kSecAttrTokenIDKeyAppleStore Specifies well-known identifier of - the token implemented using libaks (AppleKeyStore). This token is identical to - kSecAttrTokenIDSecureEnclave for devices which support Secure Enclave and - silently falls back to in-kernel emulation for those devices which do not - have Secure Enclave support. - */ -extern const CFStringRef kSecAttrTokenIDAppleKeyStore - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(3.0); - - -extern const CFStringRef kSecNetworkExtensionAccessGroupSuffix; - -/*! - @function SecItemCopyDisplayNames - @abstract Returns an array containing unique display names for each of the - certificates, keys, identities, or passwords in the provided items - array. - @param items An array containing items of type SecKeychainItemRef, - SecKeyRef, SecCertificateRef, or SecIdentityRef. All items in the - array should be of the same type. - @param displayNames On return, an array of CFString references containing - unique names for the supplied items. You are responsible for releasing - this array reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Use this function to obtain item names which are suitable for - display in a menu or list view. The returned names are guaranteed to - be unique across the set of provided items. -*/ -OSStatus SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames); - -/*! - @function SecItemDeleteAll - @abstract Removes all items from the keychain. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecItemDeleteAll(void); - -/*! - @function _SecItemAddAndNotifyOnSync - @abstract Adds an item to the keychain, and calls syncCallback when the item has synced - @param attributes Attributes dictionary to be passed to SecItemAdd - @param result Result reference to be passed to SecItemAdd - @param syncCallback Block to be executed after the item has synced or failed to sync - @result The result code returned from SecItemAdd - */ -OSStatus _SecItemAddAndNotifyOnSync(CFDictionaryRef attributes, CFTypeRef * CF_RETURNS_RETAINED result, void (^syncCallback)(bool didSync, CFErrorRef error)); - -/*! - @function SecItemSetCurrentItemAcrossAllDevices - @abstract Sets 'new current item' to be the 'current' item in CloudKit for the given identifier. - */ -void SecItemSetCurrentItemAcrossAllDevices(CFStringRef accessGroup, - CFStringRef identifier, - CFStringRef viewHint, - CFDataRef newCurrentItemReference, - CFDataRef newCurrentItemHash, - CFDataRef oldCurrentItemReference, - CFDataRef oldCurrentItemHash, - void (^complete)(CFErrorRef error)); - -/*! - @function SecItemFetchCurrentItemAcrossAllDevices - @abstract Fetches the locally cached idea of which keychain item is 'current' across this iCloud account - for the given access group and identifier. - @param accessGroup The accessGroup of your process and the expected current item - @param identifier Which 'current' item you're interested in. Freeform, but should match the ID given to - SecItemSetCurrentItemAcrossAllDevices. - @param viewHint The keychain view hint for your items. - @param fetchCloudValue If false, will return the local machine's cached idea of which item is current. If true, - performs a CloudKit operation to determine the most up-to-date version. - @param complete Called to return values: a persistent ref to the current item, if such an item exists. Otherwise, error. - */ -void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup, - CFStringRef identifier, - CFStringRef viewHint, - bool fetchCloudValue, - void (^complete)(CFDataRef persistentRef, CFErrorRef error)); - -#if __OBJC__ -/*! - @function SecItemVerifyBackupIntegrity - @abstract Verifies the presence and integrity of all key material required - to restore a backup of the keychain. - @param lightweight Only verify the item keys wrapped by backup keys instead - of the default rigorous pass. This mode can be run in any - security class. - @param completion Called to indicate results: a dictionary containing information about the the infrastructure - and of the backup state of keychain items. Error is set when at least one failure occurred. - */ -void SecItemVerifyBackupIntegrity(BOOL lightweight, - void(^completion)(NSDictionary* resultsPerKeyclass, NSError* error)); -void _SecItemFetchDigests(NSString *itemClass, NSString *accessGroup, void (^complete)(NSArray *, NSError *)); -void _SecKeychainDeleteMultiUser(NSString *musrUUID, void (^complete)(bool, NSError *)); -#endif - -/*! - @function SecItemDeleteAllWithAccessGroups - @abstract Deletes all items for each class for the given access groups - @param accessGroups An array of access groups for the items - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Provided for use by MobileInstallation to allow cleanup after uninstall - Requires entitlement "com.apple.private.uninstall.deletion" - */ -bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error); - -/* - Ensure the escrow keybag has been used to unlock the system keybag before - calling either of these APIs. - The password argument is optional, passing NULL implies no backup password - was set. We're assuming there will always be a backup keybag, except in - the OTA case where the loaded OTA backup bag will be used. - */ -CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password); -CFDataRef _SecKeychainCopyOTABackup(void); -OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag, - CFDataRef password); -/* - EMCS backups are similar to regular backups but we do not want to unlock the keybag - */ -CFDataRef _SecKeychainCopyEMCSBackup(CFDataRef backupKeybag); - -bool -_SecKeychainWriteBackupToFileDescriptor(CFDataRef backupKeybag, CFDataRef password, int fd, CFErrorRef *error); - -bool -_SecKeychainRestoreBackupFromFileDescriptor(int fd, CFDataRef backupKeybag, CFDataRef password, CFErrorRef *error); - -CFStringRef -_SecKeychainCopyKeybagUUIDFromFileDescriptor(int fd, CFErrorRef *error); - -OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out); -OSStatus _SecKeychainRestoreSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in); - -/* Called by clients to push sync circle and message changes to us. - Requires caller to have the kSecEntitlementKeychainSyncUpdates entitlement. */ -CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error); - -#if !TARGET_OS_IPHONE -CFDataRef _SecItemGetPersistentReference(CFTypeRef raw_item); -#endif - -/* Returns an OSStatus value for the given CFErrorRef, returns errSecInternal if the - domain of the provided error is not recognized. Passing NULL returns errSecSuccess (0). */ -OSStatus SecErrorGetOSStatus(CFErrorRef error); - -bool _SecKeychainRollKeys(bool force, CFErrorRef *error); - -CFDictionaryRef _SecSecuritydCopyWhoAmI(CFErrorRef *error); -XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error); -XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopySFKeychainEndpoint(CFErrorRef* error); -XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyKeychainControlEndpoint(CFErrorRef* error); - -bool _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error); - -bool _SecSystemKeychainTransfer(CFErrorRef *error); -bool _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error); - - - -OSStatus SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes); - -#if SEC_OS_OSX -CFTypeRef SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes); -#endif - -/*! - * @function SecCopyLastError - * @abstract return the last CFErrorRef for this thread - * @param status the error code returned from the API call w/o CFErrorRef or 0 - * @result NULL or a retained CFError of the matching error code - * - * @discussion There are plenty of API calls in Security.framework that - * doesn't return an CFError in case of an error, many of them actually have - * a CFErrorRef internally, but throw it away at the last moment. - * This might be your chance to get hold of it. The status code pass in is there - * to avoid stale copies of CFErrorRef. - - * Note, not all interfaces support returning a CFErrorRef on the thread local - * storage. This is especially true when going though old CDSA style API. - */ - -CFErrorRef -SecCopyLastError(OSStatus status) - __TVOS_AVAILABLE(10.0) - __WATCHOS_AVAILABLE(3.0) - __IOS_AVAILABLE(10.0); - - -bool -SecItemUpdateWithError(CFDictionaryRef inQuery, - CFDictionaryRef inAttributesToUpdate, - CFErrorRef *error) - __TVOS_AVAILABLE(10.0) - __WATCHOS_AVAILABLE(3.0) - __IOS_AVAILABLE(10.0); - -#if SEC_OS_OSX -/*! - @function SecItemParentCachePurge - @abstract Clear the cache of parent certificates used in SecItemCopyParentCertificates_osx. - */ -void SecItemParentCachePurge(void); -#endif - - -#if SEC_OS_OSX_INCLUDES -/*! - @function SecItemCopyParentCertificates_osx - @abstract Retrieve an array of possible issuing certificates for a given certificate. - @param certificate A reference to a certificate whose issuers are being sought. - @param context Pass NULL in this parameter to indicate that the default certificate - source(s) should be searched. The default is to search all available keychains. - Values of context other than NULL are currently ignored. - @result An array of zero or more certificates whose normalized subject matches the - normalized issuer of the provided certificate. Note that no cryptographic validation - of the signature is performed by this function; its purpose is only to provide a list - of candidate certificates. - */ -CFArrayRef SecItemCopyParentCertificates_osx(SecCertificateRef certificate, void *context) -__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); - -/*! - @function SecItemCopyStoredCertificate - @abstract Retrieve the first stored instance of a given certificate. - @param certificate A reference to a certificate. - @param context Pass NULL in this parameter to indicate that the default certificate - source(s) should be searched. The default is to search all available keychains. - Values of context other than NULL are currently ignored. - @result Returns a certificate reference if the given certificate exists in a keychain, - or NULL if the certificate cannot be found in any keychain. The caller is responsible - for releasing the returned certificate reference when finished with it. - */ -SecCertificateRef SecItemCopyStoredCertificate(SecCertificateRef certificate, void *context) -__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); -#endif /* SEC_OS_OSX */ - -/*! - @enum kSecAttrTokenID Value Constants - @discussion Predefined item attribute constant used to get or set values - in a dictionary. The kSecAttrTokenID constant is the key and its value - can be kSecAttrTokenIDSecureEnclave or kSecAttrTokenIDSecureElement. - @constant kSecAttrTokenIDSecureElement Specifies well-known identifier of the - token implemented using device's Secure Element. The only keychain items - supported by the Secure Element token are 256-bit elliptic curve keys - (kSecAttrKeyTypeECSecPrimeRandom). Keys must be generated on the secure element using - SecKeyCreateRandomKey call with kSecAttrTokenID set to - kSecAttrTokenIDSecureElement in the parameters dictionary, it is not - possible to import pregenerated keys to kSecAttrTokenIDSecureElement token. - */ -extern const CFStringRef kSecAttrTokenIDSecureElement -SPI_AVAILABLE(ios(10.13)); - -__END_DECLS - -#endif /* !_SECURITY_SECITEMPRIV_H_ */ diff --git a/keychain/SecKey.h b/keychain/SecKey.h deleted file mode 100644 index 021a672a..00000000 --- a/keychain/SecKey.h +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * Copyright (c) 2006-2014,2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecKey - The functions provided in SecKey.h implement and manage a particular - type of keychain item that represents a key. A key can be stored in a - keychain, but a key can also be a transient object. - - On OSX, you can use a SecKey as a SecKeychainItem in most functions. -*/ - -#ifndef _SECURITY_SECKEY_H_ -#define _SECURITY_SECKEY_H_ - -#include -#include -#include -#include -#include - -#if SEC_OS_OSX -#include -#include -#endif /* SEC_OS_OSX */ - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -#if SEC_OS_OSX -/*! - @enum KeyItemAttributeConstants - @abstract Specifies keychain item attributes for keys. - @constant kSecKeyKeyClass type uint32 (CSSM_KEYCLASS), value - is one of CSSM_KEYCLASS_PUBLIC_KEY, CSSM_KEYCLASS_PRIVATE_KEY - or CSSM_KEYCLASS_SESSION_KEY. - @constant kSecKeyPrintName type blob, human readable name of - the key. Same as kSecLabelItemAttr for normal keychain items. - @constant kSecKeyAlias type blob, currently unused. - @constant kSecKeyPermanent type uint32, value is nonzero iff - this key is permanent (stored in some keychain). This is always - 1. - @constant kSecKeyPrivate type uint32, value is nonzero iff this - key is protected by a user login or a password, or both. - @constant kSecKeyModifiable type uint32, value is nonzero iff - attributes of this key can be modified. - @constant kSecKeyLabel type blob, for private and public keys - this contains the hash of the public key. This is used to - associate certificates and keys. Its value matches the value - of the kSecPublicKeyHashItemAttr of a certificate and it's used - to construct an identity from a certificate and a key. - For symmetric keys this is whatever the creator of the key - passed in during the generate key call. - @constant kSecKeyApplicationTag type blob, currently unused. - @constant kSecKeyKeyCreator type data, the data points to a - CSSM_GUID structure representing the moduleid of the csp owning - this key. - @constant kSecKeyKeyType type uint32, value is a CSSM_ALGORITHMS - representing the algorithm associated with this key. - @constant kSecKeyKeySizeInBits type uint32, value is the number - of bits in this key. - @constant kSecKeyEffectiveKeySize type uint32, value is the - effective number of bits in this key. For example a des key - has a kSecKeyKeySizeInBits of 64 but a kSecKeyEffectiveKeySize - of 56. - @constant kSecKeyStartDate type CSSM_DATE. Earliest date from - which this key may be used. If the value is all zeros or not - present, no restriction applies. - @constant kSecKeyEndDate type CSSM_DATE. Latest date at - which this key may be used. If the value is all zeros or not - present, no restriction applies. - @constant kSecKeySensitive type uint32, iff value is nonzero - this key cannot be wrapped with CSSM_ALGID_NONE. - @constant kSecKeyAlwaysSensitive type uint32, value is nonzero - iff this key has always been marked sensitive. - @constant kSecKeyExtractable type uint32, value is nonzero iff - this key can be wrapped. - @constant kSecKeyNeverExtractable type uint32, value is nonzero - iff this key was never marked extractable. - @constant kSecKeyEncrypt type uint32, value is nonzero iff this - key can be used in an encrypt operation. - @constant kSecKeyDecrypt type uint32, value is nonzero iff this - key can be used in a decrypt operation. - @constant kSecKeyDerive type uint32, value is nonzero iff this - key can be used in a deriveKey operation. - @constant kSecKeySign type uint32, value is nonzero iff this - key can be used in a sign operation. - @constant kSecKeyVerify type uint32, value is nonzero iff this - key can be used in a verify operation. - @constant kSecKeySignRecover type uint32. - @constant kSecKeyVerifyRecover type uint32. - key can unwrap other keys. - @constant kSecKeyWrap type uint32, value is nonzero iff this - key can wrap other keys. - @constant kSecKeyUnwrap type uint32, value is nonzero iff this - key can unwrap other keys. - @discussion - The use of these enumerations has been deprecated. Please - use the equivalent items defined in SecItem.h - @@@. -*/ -CF_ENUM(int) -{ - kSecKeyKeyClass = 0, - kSecKeyPrintName = 1, - kSecKeyAlias = 2, - kSecKeyPermanent = 3, - kSecKeyPrivate = 4, - kSecKeyModifiable = 5, - kSecKeyLabel = 6, - kSecKeyApplicationTag = 7, - kSecKeyKeyCreator = 8, - kSecKeyKeyType = 9, - kSecKeyKeySizeInBits = 10, - kSecKeyEffectiveKeySize = 11, - kSecKeyStartDate = 12, - kSecKeyEndDate = 13, - kSecKeySensitive = 14, - kSecKeyAlwaysSensitive = 15, - kSecKeyExtractable = 16, - kSecKeyNeverExtractable = 17, - kSecKeyEncrypt = 18, - kSecKeyDecrypt = 19, - kSecKeyDerive = 20, - kSecKeySign = 21, - kSecKeyVerify = 22, - kSecKeySignRecover = 23, - kSecKeyVerifyRecover = 24, - kSecKeyWrap = 25, - kSecKeyUnwrap = 26 -}; - - /*! - @enum SecCredentialType - @abstract Determines the type of credential returned by SecKeyGetCredentials. - @constant kSecCredentialTypeWithUI Operations with this key are allowed to present UI if required. - @constant kSecCredentialTypeNoUI Operations with this key are not allowed to present UI, and will fail if UI is required. - @constant kSecCredentialTypeDefault The default setting for determining whether to present UI is used. This setting can be changed with a call to SecKeychainSetUserInteractionAllowed. -*/ -typedef CF_ENUM(uint32, SecCredentialType) -{ - kSecCredentialTypeDefault = 0, - kSecCredentialTypeWithUI, - kSecCredentialTypeNoUI -}; -#endif /* SEC_OS_OSX */ - -/*! - @typedef SecPadding - @abstract Supported padding types. -*/ -typedef CF_OPTIONS(uint32_t, SecPadding) -{ - kSecPaddingNone = 0, - kSecPaddingPKCS1 = 1, - kSecPaddingOAEP = 2, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0), - - /* For SecKeyRawSign/SecKeyRawVerify only, - ECDSA signature is raw byte format {r,s}, big endian. - First half is r, second half is s */ - kSecPaddingSigRaw = 0x4000, - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD2 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1MD2 = 0x8000, // __OSX_DEPRECATED(10.0, 10.12, "MD2 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD2 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE, - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD5 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1MD5 = 0x8001, // __OSX_DEPRECATED(10.0, 10.12, "MD5 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD5 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE, - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA1 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1SHA1 = 0x8002, - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA224 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1SHA224 = 0x8003, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA256 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1SHA256 = 0x8004, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA384 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1SHA384 = 0x8005, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), - - /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA512 - hash; standard ASN.1 padding will be done, as well as PKCS1 padding - of the underlying RSA operation. */ - kSecPaddingPKCS1SHA512 = 0x8006, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), -}; - -#if SEC_OS_OSX -/*! - @typedef SecKeySizes - @abstract Supported key lengths. -*/ -typedef CF_ENUM(uint32_t, SecKeySizes) -{ - kSecDefaultKeySize = 0, - - // Symmetric Keysizes - default is currently kSecAES128 for AES. - kSec3DES192 = 192, - kSecAES128 = 128, - kSecAES192 = 192, - kSecAES256 = 256, - - // Supported ECC Keys for Suite-B from RFC 4492 section 5.1.1. - // default is currently kSecp256r1 - kSecp192r1 = 192, - kSecp256r1 = 256, - kSecp384r1 = 384, - kSecp521r1 = 521, // Yes, 521 - - // Boundaries for RSA KeySizes - default is currently 2048 - // RSA keysizes must be multiples of 8 - kSecRSAMin = 1024, - kSecRSAMax = 4096 -}; -#endif /* SEC_OS_OSX */ - -/*! - @enum Key Parameter Constants - @discussion Predefined key constants used to get or set values in a dictionary. - These are used to provide explicit parameters to key generation functions - when non-default values are desired. See the description of the - SecKeyGeneratePair API for usage information. - @constant kSecPrivateKeyAttrs The value for this key is a CFDictionaryRef - containing attributes specific for the private key to be generated. - @constant kSecPublicKeyAttrs The value for this key is a CFDictionaryRef - containing attributes specific for the public key to be generated. -*/ -extern const CFStringRef kSecPrivateKeyAttrs - __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_2_0); -extern const CFStringRef kSecPublicKeyAttrs - __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_2_0); - -/*! - @function SecKeyGetTypeID - @abstract Returns the type identifier of SecKey instances. - @result The CFTypeID of SecKey instances. -*/ -CFTypeID SecKeyGetTypeID(void) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - - -#if SEC_OS_OSX -/*! - @function SecKeyCreatePair - @abstract Creates an asymmetric key pair and stores it in a specified keychain. - @param keychainRef A reference to the keychain in which to store the private and public key items. Specify NULL for the default keychain. - @param algorithm An algorithm for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. - @param keySizeInBits A key size for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. - @param contextHandle (optional) A CSSM_CC_HANDLE, or 0. If this argument is supplied, the algorithm and keySizeInBits parameters are ignored. If extra parameters are needed to generate a key (some algorithms require this), you should create a context using CSSM_CSP_CreateKeyGenContext, using the CSPHandle obtained by calling SecKeychainGetCSPHandle. Then use CSSM_UpdateContextAttributes to add parameters, and dispose of the context using CSSM_DeleteContext after calling this function. - @param publicKeyUsage A bit mask indicating all permitted uses for the new public key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. - @param publicKeyAttr A bit mask defining attribute values for the new public key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. - @param privateKeyUsage A bit mask indicating all permitted uses for the new private key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. - @param privateKeyAttr A bit mask defining attribute values for the new private key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. - @param initialAccess (optional) A SecAccess object that determines the initial access rights to the private key. The public key is given "any/any" access rights by default. - @param publicKey (optional) On return, the keychain item reference of the generated public key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. Pass NULL if a reference to this key is not required. - @param privateKey (optional) On return, the keychain item reference of the generated private key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. Pass NULL if a reference to this key is not required. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated for 10.7. Please use the SecKeyGeneratePair API instead. -*/ -OSStatus SecKeyCreatePair( - SecKeychainRef _Nullable keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE publicKeyUsage, - uint32 publicKeyAttr, - CSSM_KEYUSE privateKeyUsage, - uint32 privateKeyAttr, - SecAccessRef _Nullable initialAccess, - SecKeyRef* _Nullable CF_RETURNS_RETAINED publicKey, - SecKeyRef* _Nullable CF_RETURNS_RETAINED privateKey) - CSSM_DEPRECATED; - -/*! - @function SecKeyGenerate - @abstract Creates a symmetric key and optionally stores it in a specified keychain. - @param keychainRef (optional) A reference to the keychain in which to store the generated key. Specify NULL to generate a transient key. - @param algorithm An algorithm for the symmetric key. This parameter is ignored if a valid (non-zero) contextHandle is supplied. - @param keySizeInBits A key size for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. - @param contextHandle (optional) A CSSM_CC_HANDLE, or 0. If this argument is supplied, the algorithm and keySizeInBits parameters are ignored. If extra parameters are needed to generate a key (some algorithms require this), you should create a context using CSSM_CSP_CreateKeyGenContext, using the CSPHandle obtained by calling SecKeychainGetCSPHandle. Then use CSSM_UpdateContextAttributes to add parameters, and dispose of the context using CSSM_DeleteContext after calling this function. - @param keyUsage A bit mask indicating all permitted uses for the new key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. - @param keyAttr A bit mask defining attribute values for the new key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. - @param initialAccess (optional) A SecAccess object that determines the initial access rights for the key. This parameter is ignored if the keychainRef is NULL. - @param keyRef On return, a reference to the generated key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated for 10.7. Please use the SecKeyGenerateSymmetric API instead. -*/ -OSStatus SecKeyGenerate( - SecKeychainRef _Nullable keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE keyUsage, - uint32 keyAttr, - SecAccessRef _Nullable initialAccess, - SecKeyRef* _Nullable CF_RETURNS_RETAINED keyRef) - CSSM_DEPRECATED; - -/*! - @function SecKeyGetCSSMKey - @abstract Returns a pointer to the CSSM_KEY for the given key item reference. - @param key A keychain key item reference. The key item must be of class type kSecPublicKeyItemClass, kSecPrivateKeyItemClass, or kSecSymmetricKeyItemClass. - @param cssmKey On return, a pointer to a CSSM_KEY structure for the given key. This pointer remains valid until the key reference is released. The caller should not attempt to modify or free this data. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion The CSSM_KEY is valid until the key item reference is released. This API is deprecated in 10.7. Its use should no longer be needed. -*/ -OSStatus SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY * _Nullable * __nonnull cssmKey) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;; - -/*! - @function SecKeyGetCSPHandle - @abstract Returns the CSSM_CSP_HANDLE for the given key reference. The handle is valid until the key reference is released. - @param keyRef A key reference. - @param cspHandle On return, the CSSM_CSP_HANDLE for the given keychain. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Its use should no longer be needed. -*/ -OSStatus SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecKeyGetCredentials - @abstract For a given key, return a pointer to a CSSM_ACCESS_CREDENTIALS structure which will allow the key to be used. - @param keyRef The key for which a credential is requested. - @param operation The type of operation to be performed with this key. See "Authorization tag type" for defined operations (cssmtype.h). - @param credentialType The type of credential requested. - @param outCredentials On return, a pointer to a CSSM_ACCESS_CREDENTIALS structure. This pointer remains valid until the key reference is released. The caller should not attempt to modify or free this data. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecKeyGetCredentials( - SecKeyRef keyRef, - CSSM_ACL_AUTHORIZATION_TAG operation, - SecCredentialType credentialType, - const CSSM_ACCESS_CREDENTIALS * _Nullable * __nonnull outCredentials) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecKeyGenerateSymmetric - @abstract Generates a random symmetric key with the specified length - and algorithm type. - - @param parameters A dictionary containing one or more key-value pairs. - See the discussion sections below for a complete overview of options. - @param error An optional pointer to a CFErrorRef. This value is set - if an error occurred. If not NULL, the caller is responsible for - releasing the CFErrorRef. - @result On return, a SecKeyRef reference to the symmetric key, or - NULL if the key could not be created. - - @discussion In order to generate a symmetric key, the parameters dictionary - must at least contain the following keys: - - * kSecAttrKeyType with a value of kSecAttrKeyTypeAES or any other - kSecAttrKeyType defined in SecItem.h - * kSecAttrKeySizeInBits with a value being a CFNumberRef containing - the requested key size in bits. Example sizes for AES keys are: - 128, 192, 256, 512. - - To store the generated symmetric key in a keychain, set these keys: - * kSecUseKeychain (value is a SecKeychainRef) - * kSecAttrLabel (a user-visible label whose value is a CFStringRef, - e.g. "My App's Encryption Key") - * kSecAttrApplicationLabel (a label defined by your application, whose - value is a CFDataRef and which can be used to find this key in a - subsequent call to SecItemCopyMatching, e.g. "ID-1234567890-9876-0151") - - To specify the generated key's access control settings, set this key: - * kSecAttrAccess (value is a SecAccessRef) - - The keys below may be optionally set in the parameters dictionary - (with a CFBooleanRef value) to override the default usage values: - - * kSecAttrCanEncrypt (defaults to true if not explicitly specified) - * kSecAttrCanDecrypt (defaults to true if not explicitly specified) - * kSecAttrCanWrap (defaults to true if not explicitly specified) - * kSecAttrCanUnwrap (defaults to true if not explicitly specified) - -*/ -_Nullable CF_RETURNS_RETAINED -SecKeyRef SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecKeyCreateFromData - @abstract Creates a symmetric key with the given data and sets the - algorithm type specified. - - @param parameters A dictionary containing one or more key-value pairs. - See the discussion sections below for a complete overview of options. - @result On return, a SecKeyRef reference to the symmetric key. - - @discussion In order to generate a symmetric key the parameters dictionary must - at least contain the following keys: - - * kSecAttrKeyType with a value of kSecAttrKeyTypeAES or any other - kSecAttrKeyType defined in SecItem.h - - The keys below may be optionally set in the parameters dictionary - (with a CFBooleanRef value) to override the default usage values: - - * kSecAttrCanEncrypt (defaults to true if not explicitly specified) - * kSecAttrCanDecrypt (defaults to true if not explicitly specified) - * kSecAttrCanWrap (defaults to true if not explicitly specified) - * kSecAttrCanUnwrap (defaults to true if not explicitly specified) - -*/ -_Nullable -SecKeyRef SecKeyCreateFromData(CFDictionaryRef parameters, - CFDataRef keyData, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - - -#ifdef __BLOCKS__ -/*! - @typedef SecKeyGeneratePairBlock - @abstract Delivers the result from an asynchronous key pair generation. - @param publicKey - the public key generated. You must retain publicKey if you wish to use it after your block returns. - @param privateKey - the private key generated. You must retain publicKey if you wish to use it after your block returns. - @param error - Any errors returned. You must retain error if you wish to use it after your block returns. - */ - -typedef void (^SecKeyGeneratePairBlock)(SecKeyRef publicKey, SecKeyRef privateKey, CFErrorRef error); - -/*! - @function SecKeyGeneratePairAsync - @abstract Generate a private/public keypair returning the values in a callback. - @param parameters A dictionary containing one or more key-value pairs. - @param deliveryQueue A dispatch queue to be used to deliver the results. - @param result A callback function to result when the operation has completed. - - @discussion In order to generate a keypair the parameters dictionary must - at least contain the following keys: - - * kSecAttrKeyType with a value being kSecAttrKeyTypeRSA or any other - kSecAttrKeyType defined in SecItem.h - * kSecAttrKeySizeInBits with a value being a CFNumberRef or CFStringRef - containing the requested key size in bits. Example sizes for RSA - keys are: 512, 768, 1024, 2048. - - Setting the following attributes explicitly will override the defaults below. - See SecItem.h for detailed information on these attributes including the types - of the values. - - * kSecAttrLabel default NULL - * kSecAttrIsPermanent if this key is present and has a Boolean - value of true, the key or key pair will be added to the default - keychain. - * kSecAttrApplicationTag default NULL - * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits - * kSecAttrCanEncrypt default false for private keys, true for public keys - * kSecAttrCanDecrypt default true for private keys, false for public keys - * kSecAttrCanDerive default true - * kSecAttrCanSign default true for private keys, false for public keys - * kSecAttrCanVerify default false for private keys, true for public keys - * kSecAttrCanWrap default false for private keys, true for public keys - * kSecAttrCanUnwrap default true for private keys, false for public keys - -*/ -void SecKeyGeneratePairAsync(CFDictionaryRef parameters, - dispatch_queue_t deliveryQueue, SecKeyGeneratePairBlock result) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -#endif /* __BLOCKS__ */ - -// Derive, Wrap, and Unwrap - -/*! - @function SecKeyDeriveFromPassword - @abstract Derives a symmetric key from a password. - - @param password The password from which the keyis to be derived. - @param parameters A dictionary containing one or more key-value pairs. - @param error If the call fails this will contain the error code. - - @discussion In order to derive a key the parameters dictionary must contain at least contain the following keys: - * kSecAttrSalt - a CFData for the salt value for mixing in the pseudo-random rounds. - * kSecAttrPRF - the algorithm to use for the pseudo-random-function. - If 0, this defaults to kSecAttrPRFHmacAlgSHA1. Possible values are: - - * kSecAttrPRFHmacAlgSHA1 - * kSecAttrPRFHmacAlgSHA224 - * kSecAttrPRFHmacAlgSHA256 - * kSecAttrPRFHmacAlgSHA384 - * kSecAttrPRFHmacAlgSHA512 - - * kSecAttrRounds - the number of rounds to call the pseudo random function. - If 0, a count will be computed to average 1/10 of a second. - * kSecAttrKeySizeInBits with a value being a CFNumberRef - containing the requested key size in bits. Example sizes for RSA keys are: - 512, 768, 1024, 2048. - - @result On success a SecKeyRef is returned. On failure this result is NULL and the - error parameter contains the reason. - -*/ -_Nullable CF_RETURNS_RETAINED -SecKeyRef SecKeyDeriveFromPassword(CFStringRef password, - CFDictionaryRef parameters, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecKeyWrapSymmetric - @abstract Wraps a symmetric key with a symmetric key. - - @param keyToWrap The key which is to be wrapped. - @param wrappingKey The key wrapping key. - @param parameters The parameter list to use for wrapping the key. - @param error If the call fails this will contain the error code. - - @result On success a CFDataRef is returned. On failure this result is NULL and the - error parameter contains the reason. - - @discussion In order to wrap a key the parameters dictionary may contain the following key: - * kSecSalt - a CFData for the salt value for the encrypt. - -*/ -_Nullable -CFDataRef SecKeyWrapSymmetric(SecKeyRef keyToWrap, - SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecKeyUnwrapSymmetric - @abstract Unwrap a wrapped symmetric key. - - @param keyToUnwrap The wrapped key to unwrap. - @param unwrappingKey The key unwrapping key. - @param parameters The parameter list to use for unwrapping the key. - @param error If the call fails this will contain the error code. - - @result On success a SecKeyRef is returned. On failure this result is NULL and the - error parameter contains the reason. - - @discussion In order to unwrap a key the parameters dictionary may contain the following key: - * kSecSalt - a CFData for the salt value for the decrypt. - -*/ -_Nullable -SecKeyRef SecKeyUnwrapSymmetric(CFDataRef _Nullable * __nonnull keyToUnwrap, - SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -#endif /* SEC_OS_OSX */ - -/*! - @function SecKeyGeneratePair - @abstract Generate a private/public keypair. - @param parameters A dictionary containing one or more key-value pairs. - See the discussion sections below for a complete overview of options. - @param publicKey On return, a SecKeyRef reference to the public key. - @param privateKey On return, a SecKeyRef reference to the private key. - @result A result code. See "Security Error Codes" (SecBase.h). - - @discussion In order to generate a keypair the parameters dictionary must - at least contain the following keys: - - * kSecAttrKeyType with a value of kSecAttrKeyTypeRSA or any other - kSecAttrKeyType defined in SecItem.h - * kSecAttrKeySizeInBits with a value being a CFNumberRef containing - the requested key size in bits. Example sizes for RSA keys are: - 512, 768, 1024, 2048. - - The values below may be set either in the top-level dictionary or in a - dictionary that is the value of the kSecPrivateKeyAttrs or - kSecPublicKeyAttrs key in the top-level dictionary. Setting these - attributes explicitly will override the defaults below. See SecItem.h - for detailed information on these attributes including the types of - the values. - - * kSecAttrLabel default NULL - * kSecUseKeychain default NULL, which specifies the default keychain - * kSecAttrIsPermanent default false - if this key is present and has a Boolean value of true, the key or - key pair will be added to the keychain. - * kSecAttrTokenID default NULL - The CFStringRef ID of the token to generate the key or keypair on. This - attribute can contain CFStringRef and can be present only in the top-level - parameters dictionary. - * kSecAttrApplicationTag default NULL - * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits - * kSecAttrCanEncrypt default false for private keys, true for public keys - * kSecAttrCanDecrypt default true for private keys, false for public keys - * kSecAttrCanDerive default true - * kSecAttrCanSign default true for private keys, false for public keys - * kSecAttrCanVerify default false for private keys, true for public keys - * kSecAttrCanWrap default false for private keys, true for public keys - * kSecAttrCanUnwrap default true for private keys, false for public keys - - NOTE: The function always saves keys in the keychain on macOS and as such attribute - kSecAttrIsPermanent is ignored. The function respects attribute kSecAttrIsPermanent - on iOS, tvOS and watchOS. - It is recommended to use SecKeyCreateRandomKey() which respects kSecAttrIsPermanent - on all platforms. -*/ -OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, - SecKeyRef * _Nullable CF_RETURNS_RETAINED publicKey, SecKeyRef * _Nullable CF_RETURNS_RETAINED privateKey) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - - -#if SEC_OS_IPHONE -/*! - @function SecKeyRawSign - @abstract Given a private key and data to sign, generate a digital - signature. - @param key Private key with which to sign. - @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. - @param dataToSign The data to be signed, typically the digest of the - actual data. - @param dataToSignLen Length of dataToSign in bytes. - @param sig Pointer to buffer in which the signature will be returned. - @param sigLen IN/OUT maximum length of sig buffer on input, actualy - length of sig on output. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be performed prior to signing. If this argument is kSecPaddingNone, - the incoming data will be signed "as is". - - When PKCS1 padding is performed, the maximum length of data that can - be signed is the value returned by SecKeyGetBlockSize() - 11. - - NOTE: The behavior this function with kSecPaddingNone is undefined if the - first byte of dataToSign is zero; there is no way to verify leading zeroes - as they are discarded during the calculation. - - If you want to generate a proper PKCS1 style signature with DER encoding - of the digest type - and the dataToSign is a SHA1 digest - use - kSecPaddingPKCS1SHA1. - */ -OSStatus SecKeyRawSign( - SecKeyRef key, - SecPadding padding, - const uint8_t *dataToSign, - size_t dataToSignLen, - uint8_t *sig, - size_t *sigLen) -__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - - -/*! - @function SecKeyRawVerify - @abstract Given a public key, data which has been signed, and a signature, - verify the signature. - @param key Public key with which to verify the signature. - @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. - @param signedData The data over which sig is being verified, typically - the digest of the actual data. - @param signedDataLen Length of signedData in bytes. - @param sig Pointer to the signature to verify. - @param sigLen Length of sig in bytes. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be checked during verification. If this argument is kSecPaddingNone, - the incoming data will be compared directly to sig. - - If you are verifying a proper PKCS1-style signature, with DER encoding - of the digest type - and the signedData is a SHA1 digest - use - kSecPaddingPKCS1SHA1. - */ -OSStatus SecKeyRawVerify( - SecKeyRef key, - SecPadding padding, - const uint8_t *signedData, - size_t signedDataLen, - const uint8_t *sig, - size_t sigLen) -__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - - -/*! - @function SecKeyEncrypt - @abstract Encrypt a block of plaintext. - @param key Public key with which to encrypt the data. - @param padding See Padding Types above, typically kSecPaddingPKCS1. - @param plainText The data to encrypt. - @param plainTextLen Length of plainText in bytes, this must be less - or equal to the value returned by SecKeyGetBlockSize(). - @param cipherText Pointer to the output buffer. - @param cipherTextLen On input, specifies how much space is available at - cipherText; on return, it is the actual number of cipherText bytes written. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP, - PKCS1 (respectively kSecPaddingOAEP) padding will be performed prior to encryption. - If this argument is kSecPaddingNone, the incoming data will be encrypted "as is". - kSecPaddingOAEP is the recommended value. Other value are not recommended - for security reason (Padding attack or malleability). - - When PKCS1 padding is performed, the maximum length of data that can - be encrypted is the value returned by SecKeyGetBlockSize() - 11. - - When memory usage is a critical issue, note that the input buffer - (plainText) can be the same as the output buffer (cipherText). - */ -OSStatus SecKeyEncrypt( - SecKeyRef key, - SecPadding padding, - const uint8_t *plainText, - size_t plainTextLen, - uint8_t *cipherText, - size_t *cipherTextLen) -__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - - -/*! - @function SecKeyDecrypt - @abstract Decrypt a block of ciphertext. - @param key Private key with which to decrypt the data. - @param padding See Padding Types above, typically kSecPaddingPKCS1. - @param cipherText The data to decrypt. - @param cipherTextLen Length of cipherText in bytes, this must be less - or equal to the value returned by SecKeyGetBlockSize(). - @param plainText Pointer to the output buffer. - @param plainTextLen On input, specifies how much space is available at - plainText; on return, it is the actual number of plainText bytes written. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP, - the corresponding padding will be removed after decryption. - If this argument is kSecPaddingNone, the decrypted data will be returned "as is". - - When memory usage is a critical issue, note that the input buffer - (plainText) can be the same as the output buffer (cipherText). - */ -OSStatus SecKeyDecrypt( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingNone, - kSecPaddingPKCS1, - kSecPaddingOAEP */ - const uint8_t *cipherText, - size_t cipherTextLen, /* length of cipherText */ - uint8_t *plainText, - size_t *plainTextLen) /* IN/OUT */ -__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - -#endif // SEC_OS_IPHONE - -/*! - @function SecKeyCreateRandomKey - @abstract Generates a new public/private key pair. - @param parameters A dictionary containing one or more key-value pairs. - See the discussion sections below for a complete overview of options. - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @return Newly generated private key. To get associated public key, use SecKeyCopyPublicKey(). - @discussion In order to generate a keypair the parameters dictionary must - at least contain the following keys: - - * kSecAttrKeyType with a value being kSecAttrKeyTypeRSA or any other - kSecAttrKeyType defined in SecItem.h - * kSecAttrKeySizeInBits with a value being a CFNumberRef or CFStringRef - containing the requested key size in bits. Example sizes for RSA - keys are: 512, 768, 1024, 2048. - - The values below may be set either in the top-level dictionary or in a - dictionary that is the value of the kSecPrivateKeyAttrs or - kSecPublicKeyAttrs key in the top-level dictionary. Setting these - attributes explicitly will override the defaults below. See SecItem.h - for detailed information on these attributes including the types of - the values. - - * kSecAttrLabel default NULL - * kSecAttrIsPermanent if this key is present and has a Boolean value of true, - the key or key pair will be added to the default keychain. - * kSecAttrTokenID if this key should be generated on specified token. This - attribute can contain CFStringRef and can be present only in the top-level - parameters dictionary. - * kSecAttrApplicationTag default NULL - * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits - * kSecAttrCanEncrypt default false for private keys, true for public keys - * kSecAttrCanDecrypt default true for private keys, false for public keys - * kSecAttrCanDerive default true - * kSecAttrCanSign default true for private keys, false for public keys - * kSecAttrCanVerify default false for private keys, true for public keys - * kSecAttrCanWrap default false for private keys, true for public keys - * kSecAttrCanUnwrap default true for private keys, false for public keys - */ -SecKeyRef _Nullable SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCreateWithData - @abstract Create a SecKey from a well-defined external representation. - @param keyData CFData representing the key. The format of the data depends on the type of key being created. - @param attributes Dictionary containing attributes describing the key to be imported. The keys in this dictionary - are kSecAttr* constants from SecItem.h. Mandatory attributes are: - * kSecAttrKeyType - * kSecAttrKeyClass - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result A SecKey object representing the key, or NULL on failure. - @discussion This function does not add keys to any keychain, but the SecKey object it returns can be added - to keychain using the SecItemAdd function. - The requested data format depend on the type of key (kSecAttrKeyType) being created: - * kSecAttrKeyTypeRSA PKCS#1 format, public key can be also in x509 public key format - * kSecAttrKeyTypeECSECPrimeRandom ANSI X9.63 format (04 || X || Y [ || K]) - */ -SecKeyRef _Nullable SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef attributes, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyGetBlockSize - @abstract Returns block length of the key in bytes. - @param key The key for which the block length is requested. - @result The block length of the key in bytes. - @discussion If for example key is an RSA key the value returned by - this function is the size of the modulus. - */ -size_t SecKeyGetBlockSize(SecKeyRef key) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecKeyCopyExternalRepresentation - @abstract Create an external representation for the given key suitable for the key's type. - @param key The key to be exported. - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result A CFData representing the key in a format suitable for that key type. - @discussion This function may fail if the key is not exportable (e.g., bound to a smart card or Secure Enclave). - The format in which the key will be exported depends on the type of key: - * kSecAttrKeyTypeRSA PKCS#1 format - * kSecAttrKeyTypeECSECPrimeRandom ANSI X9.63 format (04 || X || Y [ || K]) - */ -CFDataRef _Nullable SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCopyAttributes - @abstract Retrieve keychain attributes of a key. - @param key The key whose attributes are to be retrieved. - @result Dictionary containing attributes of the key. The keys that populate this dictionary are defined - and discussed in SecItem.h. - @discussion The attributes provided by this function are: - * kSecAttrCanEncrypt - * kSecAttrCanDecrypt - * kSecAttrCanDerive - * kSecAttrCanSign - * kSecAttrCanVerify - * kSecAttrKeyClass - * kSecAttrKeyType - * kSecAttrKeySizeInBits - * kSecAttrTokenID - * kSecAttrApplicationLabel - Other values returned in that dictionary are RFU. - */ -CFDictionaryRef _Nullable SecKeyCopyAttributes(SecKeyRef key) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCopyPublicKey - @abstract Retrieve the public key from a key pair or private key. - @param key The key from which to retrieve a public key. - @result The public key or NULL if public key is not available for specified key. - @discussion Fails if key does not contain a public key or no public key can be computed from it. - */ -SecKeyRef _Nullable SecKeyCopyPublicKey(SecKeyRef key) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @enum SecKeyAlgorithm - @abstract Available algorithms for performing cryptographic operations with SecKey object. String representation - of constant can be used for logging or debugging purposes, because they contain human readable names of the algorithm. - - @constant kSecKeyAlgorithmRSASignatureRaw - Raw RSA sign/verify operation, size of input data must be the same as value returned by SecKeyGetBlockSize(). - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw - RSA sign/verify operation, assumes that input data is digest and OID and digest algorithm as specified in PKCS# v1.5. - This algorithm is typically not used directly, instead use algorithm with specified digest, like - kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256. - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 - RSA signature with PKCS#1 padding, input data must be SHA-1 generated digest. - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 - RSA signature with PKCS#1 padding, input data must be SHA-224 generated digest. - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 - RSA signature with PKCS#1 padding, input data must be SHA-256 generated digest. - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 - RSA signature with PKCS#1 padding, input data must be SHA-384 generated digest. - - @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 - RSA signature with PKCS#1 padding, input data must be SHA-512 generated digest. - - @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 - RSA signature with PKCS#1 padding, SHA-1 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 - RSA signature with PKCS#1 padding, SHA-224 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 - RSA signature with PKCS#1 padding, SHA-256 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 - RSA signature with PKCS#1 padding, SHA-384 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 - RSA signature with PKCS#1 padding, SHA-512 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA1 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-1 generated digest. - PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size). - - @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA224 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-224 generated digest. - PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size). - - @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA256 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-256 generated digest. - PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size). - - @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA384 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-384 generated digest. - PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size). - - @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA512 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-512 generated digest. - PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size). - - @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA1 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-1 digest is generated from input data of any size. - PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size). - - @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA224 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-224 digest is generated from input data of any size. - PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size). - - @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA256 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-256 digest is generated from input data of any size. - PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size). - - @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA384 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-384 digest is generated from input data of any size. - PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size). - - @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA512 - RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-512 digest is generated from input data of any size. - PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size). - - @constant kSecKeyAlgorithmECDSASignatureRFC4754 - ECDSA algorithm, signature is concatenated r and s, big endian, data is message digest. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA1 algorithm. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA224 algorithm. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA256 algorithm. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA384 algorithm. - - @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA512 algorithm. - - @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA1 - ECDSA algorithm, signature is in DER x9.62 encoding, SHA-1 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA224 - ECDSA algorithm, signature is in DER x9.62 encoding, SHA-224 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA256 - ECDSA algorithm, signature is in DER x9.62 encoding, SHA-256 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA384 - ECDSA algorithm, signature is in DER x9.62 encoding, SHA-384 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA512 - ECDSA algorithm, signature is in DER x9.62 encoding, SHA-512 digest is generated from input data of any size. - - @constant kSecKeyAlgorithmRSAEncryptionRaw - Raw RSA encryption or decryption, size of data must match RSA key modulus size. Note that direct - use of this algorithm without padding is cryptographically very weak, it is important to always introduce - some kind of padding. Input data size must be less or equal to the key block size and returned block has always - the same size as block size, as returned by SecKeyGetBlockSize(). - - @constant kSecKeyAlgorithmRSAEncryptionPKCS1 - RSA encryption or decryption, data is padded using PKCS#1 padding scheme. This algorithm should be used only for - backward compatibility with existing protocols and data. New implementations should choose cryptographically - stronger algorithm instead (see kSecKeyAlgorithmRSAEncryptionOAEP). Input data must be at most - "key block size - 11" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA1 - RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA1. Input data must be at most - "key block size - 42" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM to be able to encrypt and decrypt arbitrary long data. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA224 - RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA224. Input data must be at most - "key block size - 58" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM to be able to encrypt and decrypt arbitrary long data. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA256 - RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA256. Input data must be at most - "key block size - 66" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM to be able to encrypt and decrypt arbitrary long data. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA384 - RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA384. Input data must be at most - "key block size - 98" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM to be able to encrypt and decrypt arbitrary long data. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA512 - RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA512. Input data must be at most - "key block size - 130" bytes long and returned block has always the same size as block size, as returned - by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM to be able to encrypt and decrypt arbitrary long data. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM - Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM - mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. - 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used - as authentication data for AES-GCM encryption. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM - Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM - mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. - 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used - as authentication data for AES-GCM encryption. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM - Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM - mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. - 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used - as authentication data for AES-GCM encryption. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM - Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM - mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. - 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used - as authentication data for AES-GCM encryption. - - @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM - Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM - mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. - 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used - as authentication data for AES-GCM encryption. - - @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM - Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM in new code. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). - - @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size - is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. - AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half - of KDF output. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactor - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys. - This algorithm does not accept any parameters, length of output raw shared secret is given by the length of the key. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1 - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA1 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224 - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA224 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256 - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384 - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA384 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512 - Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA512 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandard - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys. - This algorithm does not accept any parameters, length of output raw shared secret is given by the length of the key. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA1 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224 - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA224 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256 - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384 - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA384 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - - @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512 - Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys - and apply ANSI X9.63 KDF with SHA512 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows - kSecKeyKeyExchangeParameterSharedInfo parameters to be used. - */ - -typedef CFStringRef SecKeyAlgorithm CF_STRING_ENUM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureRaw -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA1 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA224 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA256 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA384 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA512 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA1 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA224 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA256 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA384 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA512 -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureRFC4754 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionRaw -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionPKCS1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM -__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandard -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactor -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512 -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCreateSignature - @abstract Given a private key and data to sign, generate a digital signature. - @param key Private key with which to sign. - @param algorithm One of SecKeyAlgorithm constants suitable to generate signature with this key. - @param dataToSign The data to be signed, typically the digest of the actual data. - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result The signature over dataToSign represented as a CFData, or NULL on failure. - @discussion Computes digital signature using specified key over input data. The operation algorithm - further defines the exact format of input data, operation to be performed and output signature. - */ -CFDataRef _Nullable SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyVerifySignature - @abstract Given a public key, data which has been signed, and a signature, verify the signature. - @param key Public key with which to verify the signature. - @param algorithm One of SecKeyAlgorithm constants suitable to verify signature with this key. - @param signedData The data over which sig is being verified, typically the digest of the actual data. - @param signature The signature to verify. - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result True if the signature was valid, False otherwise. - @discussion Verifies digital signature operation using specified key and signed data. The operation algorithm - further defines the exact format of input data, signature and operation to be performed. - */ -Boolean SecKeyVerifySignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef signedData, CFDataRef signature, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCreateEncryptedData - @abstract Encrypt a block of plaintext. - @param key Public key with which to encrypt the data. - @param algorithm One of SecKeyAlgorithm constants suitable to perform encryption with this key. - @param plaintext The data to encrypt. The length and format of the data must conform to chosen algorithm, - typically be less or equal to the value returned by SecKeyGetBlockSize(). - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result The ciphertext represented as a CFData, or NULL on failure. - @discussion Encrypts plaintext data using specified key. The exact type of the operation including the format - of input and output data is specified by encryption algorithm. - */ -CFDataRef _Nullable SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, - CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCreateDecryptedData - @abstract Decrypt a block of ciphertext. - @param key Private key with which to decrypt the data. - @param algorithm One of SecKeyAlgorithm constants suitable to perform decryption with this key. - @param ciphertext The data to decrypt. The length and format of the data must conform to chosen algorithm, - typically be less or equal to the value returned by SecKeyGetBlockSize(). - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result The plaintext represented as a CFData, or NULL on failure. - @discussion Decrypts ciphertext data using specified key. The exact type of the operation including the format - of input and output data is specified by decryption algorithm. - */ -CFDataRef _Nullable SecKeyCreateDecryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, - CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @enum SecKeyKeyExchangeParameter SecKey Key Exchange parameters - @constant kSecKeyKeyExchangeParameterRequestedSize Contains CFNumberRef with requested result size in bytes. - @constant kSecKeyKeyExchangeParameterSharedInfo Contains CFDataRef with additional shared info - for KDF (key derivation function). - */ -typedef CFStringRef SecKeyKeyExchangeParameter CF_STRING_ENUM -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyKeyExchangeParameter kSecKeyKeyExchangeParameterRequestedSize -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); -extern const SecKeyKeyExchangeParameter kSecKeyKeyExchangeParameterSharedInfo -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyCopyKeyExchangeResult - @abstract Perform Diffie-Hellman style of key exchange operation, optionally with additional key-derivation steps. - @param algorithm One of SecKeyAlgorithm constants suitable to perform this operation. - @param publicKey Remote party's public key. - @param parameters Dictionary with parameters, see SecKeyKeyExchangeParameter constants. Used algorithm - determines the set of required and optional parameters to be used. - @param error Pointer to an error object on failure. - See "Security Error Codes" (SecBase.h). - @result Result of key exchange operation as a CFDataRef, or NULL on failure. - */ -CFDataRef _Nullable SecKeyCopyKeyExchangeResult(SecKeyRef privateKey, SecKeyAlgorithm algorithm, SecKeyRef publicKey, CFDictionaryRef parameters, CFErrorRef *error) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @enum SecKeyOperationType - @abstract Defines types of cryptographic operations available with SecKey instance. - - @constant kSecKeyOperationTypeSign - Represents SecKeyCreateSignature() - - @constant kSecKeyOperationTypeVerify - Represents SecKeyVerifySignature() - - @constant kSecKeyOperationTypeEncrypt - Represents SecKeyCreateEncryptedData() - - @constant kSecKeyOperationTypeDecrypt - Represents SecKeyCreateDecryptedData() - - @constant kSecKeyOperationTypeKeyExchange - Represents SecKeyCopyKeyExchangeResult() - */ -typedef CF_ENUM(CFIndex, SecKeyOperationType) { - kSecKeyOperationTypeSign = 0, - kSecKeyOperationTypeVerify = 1, - kSecKeyOperationTypeEncrypt = 2, - kSecKeyOperationTypeDecrypt = 3, - kSecKeyOperationTypeKeyExchange = 4, -} __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecKeyIsAlgorithmSupported - @abstract Checks whether key supports specified algorithm for specified operation. - @param key Key to query - @param operation Operation type for which the key is queried - @param algorithm Algorithm which is queried - @return True if key supports specified algorithm for specified operation, False otherwise. - */ -Boolean SecKeyIsAlgorithmSupported(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm) -__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECKEY_H_ */ diff --git a/keychain/SecKeyPriv.h b/keychain/SecKeyPriv.h deleted file mode 100644 index 1f22315a..00000000 --- a/keychain/SecKeyPriv.h +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Copyright (c) 2006-2010,2012-2015 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecKeyPriv - The functions provided in SecKeyPriv.h implement and manage a particular - type of keychain item that represents a key. A key can be stored in a - keychain, but a key can also be a transient object. - - You can use a key as a keychain item in most functions. -*/ - -#ifndef _SECURITY_SECKEYPRIV_H_ -#define _SECURITY_SECKEYPRIV_H_ - -#include -#include -#include -#include - -#if TARGET_OS_OSX -#include -#endif - -#if SEC_OS_OSX -#include -#include -#endif - -__BEGIN_DECLS - -typedef struct __SecDERKey { - uint8_t *oid; - CFIndex oidLength; - - uint8_t *parameters; - CFIndex parametersLength; - - /* Contents of BIT STRING in DER Encoding */ - uint8_t *key; - CFIndex keyLength; -} SecDERKey; - -typedef struct SecRSAPublicKeyParams { - uint8_t *modulus; /* modulus */ - CFIndex modulusLength; - uint8_t *exponent; /* public exponent */ - CFIndex exponentLength; -} SecRSAPublicKeyParams; - -typedef uint32_t SecKeyEncoding; -enum { - /* Typically only used for symmetric keys. */ - kSecKeyEncodingRaw = 0, - - /* RSA keys are DER-encoded according to PKCS1. */ - kSecKeyEncodingPkcs1 = 1, - - /* RSA keys are DER-encoded according to PKCS1 with Apple Extensions. */ - kSecKeyEncodingApplePkcs1 = 2, - - /* RSA public key in SecRSAPublicKeyParams format. keyData is a pointer - to a SecRSAPublicKeyParams and keyDataLength is - sizeof(SecRSAPublicKeyParams). */ - kSecKeyEncodingRSAPublicParams = 3, - - /* RSA public key in SecRSAPublicKeyParams format. keyData is a pointer - to a SecRSAPublicKeyParams and keyDataLength is - sizeof(SecRSAPublicKeyParams). */ - kSecDERKeyEncoding = 4, - - /* Internal "encodings to send other data" */ - kSecGenerateKey = 5, - kSecExtractPublicFromPrivate = 6, - - /* Encoding came from SecKeyCopyPublicBytes for a public key, - or internally from a private key */ - kSecKeyEncodingBytes = 7, - - /* Handing in a private key from corecrypto directly. */ - kSecKeyCoreCrypto = 8, - -}; - -typedef uint32_t SecKeyWrapType; -enum { - /* wrap key in RFC3394 (AESWrap) */ - kSecKeyWrapRFC3394 = 0, - - /* wrap key in PGP style (support EC keys only right now) */ - kSecKeyWrapPublicKeyPGP = 1, - -}; - -typedef CF_ENUM(CFIndex, SecKeyOperationMode) { - kSecKeyOperationModePerform = 0, - kSecKeyOperationModeCheckIfSupported = 1, -}; - -typedef OSStatus (*SecKeyInitMethod)(SecKeyRef, const uint8_t *, CFIndex, - SecKeyEncoding); -typedef void (*SecKeyDestroyMethod)(SecKeyRef); -typedef OSStatus (*SecKeyRawSignMethod)(SecKeyRef key, SecPadding padding, - const uint8_t *dataToSign, size_t dataToSignLen, - uint8_t *sig, size_t *sigLen); -typedef OSStatus (*SecKeyRawVerifyMethod)( - SecKeyRef key, SecPadding padding, const uint8_t *signedData, - size_t signedDataLen, const uint8_t *sig, size_t sigLen); -typedef OSStatus (*SecKeyEncryptMethod)(SecKeyRef key, SecPadding padding, - const uint8_t *plainText, size_t plainTextLen, - uint8_t *cipherText, size_t *cipherTextLen); -typedef OSStatus (*SecKeyDecryptMethod)(SecKeyRef key, SecPadding padding, - const uint8_t *cipherText, size_t cipherTextLen, - uint8_t *plainText, size_t *plainTextLen); -typedef OSStatus (*SecKeyComputeMethod)(SecKeyRef key, - const uint8_t *pub_key, size_t pub_key_len, - uint8_t *computed_key, size_t *computed_key_len); -typedef size_t (*SecKeyBlockSizeMethod)(SecKeyRef key); -typedef CFDictionaryRef (*SecKeyCopyDictionaryMethod)(SecKeyRef key); -typedef CFIndex (*SecKeyGetAlgorithmIDMethod)(SecKeyRef key); -typedef OSStatus (*SecKeyCopyPublicBytesMethod)(SecKeyRef key, CFDataRef *serialization); -typedef CFDataRef (*SecKeyCopyWrapKeyMethod)(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error); -typedef CFDataRef (*SecKeyCopyUnwrapKeyMethod)(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error); -typedef CFStringRef (*SecKeyDescribeMethod)(SecKeyRef key); - -typedef CFDataRef (*SecKeyCopyExternalRepresentationMethod)(SecKeyRef key, CFErrorRef *error); -typedef SecKeyRef (*SecKeyCopyPublicKeyMethod)(SecKeyRef key); -typedef Boolean (*SecKeyIsEqualMethod)(SecKeyRef key1, SecKeyRef key2); -typedef SecKeyRef (*SecKeyCreateDuplicateMethod)(SecKeyRef key); -typedef Boolean (*SecKeySetParameterMethod)(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error); - -/*! - @abstract Performs cryptographic operation with the key. - @param key Key to perform the operation on. - @param operation Type of operation to be performed. - @param algorithm Algorithm identifier for the operation. Determines format of input and output data. - @param allAlgorithms Array of algorithms which were traversed until we got to this operation. The last member of this array is always the same as @c algorithm parameter. - @param mode Mode in which the operation is performed. Two available modes are checking only if the operation can be performed or actually performing the operation. - @param in1 First input parameter for the operation, meaningful only in ModePerform. - @param in2 Second input parameter for the operation, meaningful only in ModePerform. - @param error Error details when NULL is returned. - @return NULL if some failure occured. kCFNull if operation/algorithm/key combination is not supported, otherwise the result of the operation or kCFBooleanTrue in ModeCheckIfSupported. - */ -typedef CFTypeRef(*SecKeyCopyOperationResultMethod)(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, CFArrayRef allAlgorithms, SecKeyOperationMode mode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error); - -#define kSecKeyDescriptorVersion (4) - -typedef struct __SecKeyDescriptor { - /* Version of this SecKeyDescriptor. Must be kSecKeyDescriptorVersion. */ - uint32_t version; - - /* Name of this key class for use by SecKeyShow(). */ - const char *name; - - /* If nonzero, SecKeyCreate will allocate this many bytes for the key - field in the SecKeyRef it creates. If zero key is NULL and the - implementor can choose to dynamically allocate it in the init - function and free it in the destroy function. */ - uint32_t extraBytes; - - /* Called by SecKeyCreate(). */ - SecKeyInitMethod init; - /* Called by destructor (final CFRelease() or gc if using). */ - SecKeyDestroyMethod destroy; - /* Called by SecKeyRawSign(). */ - SecKeyRawSignMethod rawSign; - /* Called by SecKeyRawVerify(). */ - SecKeyRawVerifyMethod rawVerify; - /* Called by SecKeyEncrypt(). */ - SecKeyEncryptMethod encrypt; - /* Called by SecKeyDecrypt(). */ - SecKeyDecryptMethod decrypt; - /* Reserved for future use. */ - SecKeyComputeMethod compute; - /* Called by SecKeyGetBlockSize(). */ - SecKeyBlockSizeMethod blockSize; - /* Called by SecKeyCopyAttributeDictionary(), which is private. */ - SecKeyCopyDictionaryMethod copyDictionary; - /* Called by SecKeyDescribeMethod(). */ - SecKeyDescribeMethod describe; -#if kSecKeyDescriptorVersion > 0 - /* Called by SecKeyCopyAttributeDictionary(), which is private. */ - SecKeyGetAlgorithmIDMethod getAlgorithmID; -#endif -#if kSecKeyDescriptorVersion > 1 - SecKeyCopyPublicBytesMethod copyPublic; -#endif -#if kSecKeyDescriptorVersion > 2 - SecKeyCopyWrapKeyMethod copyWrapKey; - SecKeyCopyUnwrapKeyMethod copyUnwrapKey; -#endif -#if kSecKeyDescriptorVersion > 3 - SecKeyCopyExternalRepresentationMethod copyExternalRepresentation; - SecKeyCopyPublicKeyMethod copyPublicKey; - SecKeyCopyOperationResultMethod copyOperationResult; - SecKeyIsEqualMethod isEqual; - SecKeyCreateDuplicateMethod createDuplicate; - SecKeySetParameterMethod setParameter; -#endif -} SecKeyDescriptor; - -struct __SecKey { - CFRuntimeBase _base; - - const SecKeyDescriptor *key_class; - - /* The actual key handled by class. */ - void *key; -}; - -/* Create a public key from a CFData containing a SubjectPublicKeyInfo in DER format. */ -SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, - CFDataRef subjectPublicKeyInfoData); - -/* Crete a SubjectPublicKeyInfo in DER format from a SecKey */ -CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key); - - -/*! - @function SecKeyCreate - @abstract Given a private key and data to sign, generate a digital signature. - @param allocator allocator to use when allocating this key instance. - @param key_class pointer to a SecKeyDescriptor. - @param keyData The second argument to the init() function in the key_class. - @param keyDataLength The third argument to the init() function in the key_class. - @param encoding The fourth argument to the init() function in the key_class. - @result A newly allocated SecKeyRef. - */ -SecKeyRef SecKeyCreate(CFAllocatorRef allocator, - const SecKeyDescriptor *key_class, const uint8_t *keyData, - CFIndex keyDataLength, SecKeyEncoding encoding); - -/* Create a public key from an oid, params and keyData all in DER format. */ -SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, - const SecAsn1Oid *oid1, const SecAsn1Item *params, - const SecAsn1Item *keyData); - -/* Create public key from private key */ -SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); - -/* Get Private Key (if present) by publicKey. */ -SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error); - -OSStatus SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey, CFErrorRef *error); -CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error); - -/* Return an attribute dictionary used to find a private key by public key hash */ -CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef); - -/* Return a key from an attribute dictionary that was used to store this item - in a keychain. */ -SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes); - -// SecAsn1AlgId is deprecated, but we still need to use it. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -OSStatus SecKeyDigestAndVerify( - SecKeyRef key, /* Public key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *dataToDigest, /* signature over this data */ - size_t dataToDigestLen,/* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen); /* length of sig */ - -/* Return an attribute dictionary used to store this item in a keychain. */ -CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key); - -OSStatus SecKeyDigestAndSign( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *dataToDigest, /* signature over this data */ - size_t dataToDigestLen,/* length of dataToDigest */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen); /* IN/OUT */ - -OSStatus SecKeyVerifyDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen,/* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen); /* length of sig */ - -OSStatus SecKeySignDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen,/* length of digestData */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen); /* IN/OUT */ - -#pragma clang diagnostic pop - -OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic); -SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength); -SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized); -CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key); - -/* This function directly creates an iOS-format SecKeyRef from public key bytes. */ -SecKeyRef SecKeyCreateRSAPublicKey_ios(CFAllocatorRef allocator, - const uint8_t *keyData, CFIndex keyDataLength, - SecKeyEncoding encoding); - - -CF_RETURNS_RETAINED -CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, - CFTypeRef keyType, - CFDataRef privateBlob); -CF_RETURNS_RETAINED -CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType); - -enum { - kSecNullAlgorithmID = 0, - kSecRSAAlgorithmID = 1, - kSecDSAAlgorithmID = 2, /* unsupported, just here for reference. */ - kSecECDSAAlgorithmID = 3, -}; - -/*! - @function SecKeyGetAlgorithmId - @abstract Returns an enumerated constant value which identifies the algorithm for the given key. - @param key A key reference. - @result An algorithm identifier. - */ -CFIndex SecKeyGetAlgorithmId(SecKeyRef key) -SPI_AVAILABLE(macos(10.8), ios(9.0)); - -#if TARGET_OS_IPHONE -/*! - @function SecKeyGetAlgorithmID - @abstract Returns an enumerated constant value which identifies the algorithm for the given key. - @param key A key reference. - @result An algorithm identifier. - @discussion Deprecated in iOS 9.0. Note that SecKeyGetAlgorithmID also exists on OS X - with different arguments for CDSA-based SecKeyRefs, and returns different values. - For compatibility, your code should migrate to use SecKeyGetAlgorithmId instead. -*/ -CFIndex SecKeyGetAlgorithmID(SecKeyRef key) -API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", ios(5.0, 9.0)) API_UNAVAILABLE(iosmac); -#endif // TARGET_OS_IPHONE - -#if TARGET_OS_OSX -/*! - @function SecKeyGetAlgorithmID - @abstract Returns a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure for the given key. - @param key A key reference. - @param algid On return, a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Deprecated in OS X 10.8 and later. Continued use is strongly discouraged, - since there is a naming conflict with a similar function (also deprecated) on iOS that - had different arguments and a different return value. Use SecKeyGetAlgorithmId instead. - */ -OSStatus SecKeyGetAlgorithmID(SecKeyRef key, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) -API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", macos(10.2, 10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); -#endif - -#if !SEC_OS_OSX -typedef CF_ENUM(int, SecKeySize) { - kSecKeyKeySizeInBits = 0, - kSecKeySignatureSize = 1, - kSecKeyEncryptedDataSize = 2, - // More might belong here, but we aren't settled on how - // to take into account padding and/or digest types. -}; - -/*! - @function SecKeyGetSize - @abstract Returns a size in bytes. - @param key The key for which the block length is requested. - @param whichSize The size that you want evaluated. - @result The block length of the key in bytes. - @discussion If for example key is an RSA key the value returned by - this function is the size of the modulus. - */ -size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) -__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_0); -#endif - -/*! - @function SecKeyLookupPersistentRef - @abstract Looks up a SecKeyRef via persistent ref. - @param persistentRef The persistent ref data for looking up. - @param lookedUpData retained SecKeyRef for the found object. - @result Errors when using SecItemFind for the persistent ref. - */ -OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) -__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecKeyCopyPersistentRef - @abstract Gets a persistent reference for a key. - @param key Key to make a persistent ref for. - @param persistentRef Allocated data representing the persistent ref. - @result Errors when using SecItemFind for the persistent ref. - */ -OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) -__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -extern const CFStringRef _kSecKeyWrapPGPSymAlg; /* CFNumber */ -extern const CFStringRef _kSecKeyWrapPGPFingerprint; /* CFDataRef, at least 20 bytes */ -extern const CFStringRef _kSecKeyWrapPGPWrapAlg; /* kSecKeyWrapRFC6637WrapNNN, or any of the other PGP wrap algs */ -extern const CFStringRef _kSecKeyWrapRFC6637Flags; -extern const CFStringRef _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128; -extern const CFStringRef _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256; - -enum { kSecKeyWrapPGPFingerprintMinSize = 20 }; -/*! - @function _SecKeyCopyWrapKey - @abstract Wrap a key - */ - -CFDataRef -_SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) -__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); - -/*! - @function _SecKeyWrapKey - @abstract Unwrap a key - */ - -CFDataRef -_SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) -__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); - -#if SEC_OS_OSX_INCLUDES -/*! - @function SecKeyGetStrengthInBits - @abstract Returns key strength in bits for the given key. - @param key A key reference. - @param algid A pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure, as returned from a call to SecKeyGetAlgorithmID. - @param strength On return, the key strength in bits. - @result A result code. See "Security Error Codes" (SecBase.h). -*/ -OSStatus SecKeyGetStrengthInBits(SecKeyRef key, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength) API_DEPRECATED("CSSM_X509_ALGORITHM_IDENTIFIER is deprecated", macos(10.4, 10.14)); - -/*! - @function SecKeyImportPair - @abstract Takes an asymmetric key pair and stores it in the keychain specified by the keychain parameter. - @param keychainRef A reference to the keychain in which to store the private and public key items. Specify NULL for the default keychain. - @param publicCssmKey A CSSM_KEY which is valid for the CSP returned by SecKeychainGetCSPHandle(). This may be a normal key or reference key. - @param privateCssmKey A CSSM_KEY which is valid for the CSP returned by SecKeychainGetCSPHandle(). This may be a normal key or reference key. - @param initialAccess A SecAccess object that determines the initial access rights to the private key. The public key is given an any/any acl by default. - @param publicKey Optional output pointer to the keychain item reference of the imported public key. The caller must call CFRelease on this value if it is returned. - @param privateKey Optional output pointer to the keychain item reference of the imported private key. The caller must call CFRelease on this value if it is returned. - @result A result code. See "Security Error Codes" (SecBase.h). - @deprecated in 10.5 and later. Use the SecItemImport function instead; see -*/ -OSStatus SecKeyImportPair( - SecKeychainRef keychainRef, - const CSSM_KEY *publicCssmKey, - const CSSM_KEY *privateCssmKey, - SecAccessRef initialAccess, - SecKeyRef* publicKey, - SecKeyRef* privateKey) - API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); - -/*! - @function SecKeyCreate - @abstract Create a key reference from the supplied key data. - @param allocator CFAllocator to allocate the key data. Pass NULL to use the default allocator. - @param keyClass A descriptor for the particular class of key that is being created. - @param keyData Data from which to create the key. Specify the format of this data in the encoding parameter. - @param keyDataLength Length of the data pointed to by keyData. - @param encoding A value of type SecKeyEncoding which describes the format of keyData. - @result A key reference. - @discussion Warning: this function is NOT intended for use outside the Security stack in its current state. - IMPORTANT: on Mac OS X 10.5 and earlier, the SecKeyCreate function had a different parameter list. - The current parameter list matches the iPhone OS implementation. Existing clients of this function - on Mac OS X (and there should not be any outside the Security stack, per the warning above) must - migrate to the replacement function, SecKeyCreateWithCSSMKey. -*/ -SecKeyRef SecKeyCreate(CFAllocatorRef allocator, - const SecKeyDescriptor *keyClass, const uint8_t *keyData, - CFIndex keyDataLength, SecKeyEncoding encoding); - -/*! - @function SecKeyCreateWithCSSMKey - @abstract Generate a temporary floating key reference for a CSSM_KEY. - @param key A pointer to a CSSM_KEY structure. - @param keyRef On return, a key reference. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Warning: this function is NOT intended for use outside the Security stack in its current state. -*/ -OSStatus SecKeyCreateWithCSSMKey(const CSSM_KEY *key, SecKeyRef* keyRef) API_DEPRECATED("CSSM_KEY is deprecated", macos(10.11, 10.14)); - -// Alias macOS versions of this deprecated SPI to unique macOS names. Undecorated names are used for iosmac. -#define SecKeyRawSign SecKeyRawSign_macOS -#define SecKeyRawVerify SecKeyRawVerify_macOS - -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @function SecKeyRawSign - @abstract Given a private key and data to sign, generate a digital signature. - @param key Private key with which to sign. - @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. - @param dataToSign The data to be signed, typically the digest of the actual data. - @param dataToSignLen Length of dataToSign in bytes. - @param sig Pointer to buffer in which the signature will be returned. - @param sigLen IN/OUT maximum length of sig buffer on input, actualy length of sig on output. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be performed prior to signing. If this argument is kSecPaddingNone, - the incoming data will be signed "as is". - - When PKCS1 padding is performed, the maximum length of data that can - be signed is the value returned by SecKeyGetBlockSize() - 11. - - NOTE: The behavior this function with kSecPaddingNone is undefined if the - first byte of dataToSign is zero; there is no way to verify leading zeroes - as they are discarded during the calculation. - - If you want to generate a proper PKCS1 style signature with DER encoding of - the digest type - and the dataToSign is a SHA1 digest - use kSecPaddingPKCS1SHA1. -*/ -OSStatus SecKeyRawSign( - SecKeyRef key, - SecPadding padding, - const uint8_t *dataToSign, - size_t dataToSignLen, - uint8_t *sig, - size_t *sigLen) -SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateSignature", macos(10.7, 10.15)); - - -/*! - @function SecKeyRawVerify - @abstract Given a public key, data which has been signed, and a signature, verify the signature. - @param key Public key with which to verify the signature. - @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. - @param signedData The data over which sig is being verified, typically the digest of the actual data. - @param signedDataLen Length of signedData in bytes. - @param sig Pointer to the signature to verify. - @param sigLen Length of sig in bytes. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be checked during verification. If this argument is kSecPaddingNone, - the incoming data will be compared directly to sig. - - If you are verifying a proper PKCS1-style signature, with DER encoding of the digest - type - and the signedData is a SHA1 digest - use kSecPaddingPKCS1SHA1. -*/ -OSStatus SecKeyRawVerify( - SecKeyRef key, - SecPadding padding, - const uint8_t *signedData, - size_t signedDataLen, - const uint8_t *sig, - size_t sigLen) -SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyVerifySignature", macos(10.7, 10.15)); - -CF_IMPLICIT_BRIDGING_DISABLED - -/*! - @function SecKeyEncrypt - @abstract Encrypt a block of plaintext. - @param key Public key with which to encrypt the data. - @param padding See Padding Types above, typically kSecPaddingPKCS1. - @param plainText The data to encrypt. - @param plainTextLen Length of plainText in bytes, this must be less - or equal to the value returned by SecKeyGetBlockSize(). - @param cipherText Pointer to the output buffer. - @param cipherTextLen On input, specifies how much space is available at - cipherText; on return, it is the actual number of cipherText bytes written. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be performed prior to encryption. If this argument is kSecPaddingNone, - the incoming data will be encrypted "as is". - - When PKCS1 padding is performed, the maximum length of data that can - be encrypted is the value returned by SecKeyGetBlockSize() - 11. - - When memory usage is a critical issue, note that the input buffer - (plainText) can be the same as the output buffer (cipherText). -*/ -OSStatus SecKeyEncrypt( - SecKeyRef key, - SecPadding padding, - const uint8_t *plainText, - size_t plainTextLen, - uint8_t *cipherText, - size_t *cipherTextLen) -SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateEncryptedData", macos(10.7, 10.15)); - - -/*! - @function SecKeyDecrypt - @abstract Decrypt a block of ciphertext. - @param key Private key with which to decrypt the data. - @param padding See SecPadding types above; typically kSecPaddingPKCS1. - @param cipherText The data to decrypt. - @param cipherTextLen Length of cipherText in bytes; this must be less - or equal to the value returned by SecKeyGetBlockSize(). - @param plainText Pointer to the output buffer. - @param plainTextLen On input, specifies how much space is available at - plainText; on return, it is the actual number of plainText bytes written. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding - will be removed after decryption. If this argument is kSecPaddingNone, - the decrypted data will be returned "as is". - - When memory usage is a critical issue, note that the input buffer - (plainText) can be the same as the output buffer (cipherText). -*/ -OSStatus SecKeyDecrypt( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ - const uint8_t *cipherText, - size_t cipherTextLen, /* length of cipherText */ - uint8_t *plainText, - size_t *plainTextLen) /* IN/OUT */ -SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateDecryptedData", macos(10.7, 10.15)); - -// SecAsn1AlgId is deprecated, but we still need to use it. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -OSStatus SecKeyVerifyDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen, /* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen); /* length of sig */ - -OSStatus SecKeySignDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen, /* length of digestData */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen); /* IN/OUT */ -#pragma clang diagnostic pop - -#endif // SEC_OS_OSX_INCLUDES - - -/* These are the named curves we support. These values come from RFC 4492 - section 5.1.1, with the exception of SSL_Curve_None which means - "ECDSA not negotiated". */ -typedef enum -{ - kSecECCurveNone = -1, - kSecECCurveSecp256r1 = 23, - kSecECCurveSecp384r1 = 24, - kSecECCurveSecp521r1 = 25 -} SecECNamedCurve; - -/* Return a named curve enum for ecPrivateKey. */ -SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef ecPrivateKey); -CFDataRef SecECKeyCopyPublicBits(SecKeyRef key); - -/* Given an RSA public key in encoded form return a SecKeyRef representing - that key. Supported encodings are kSecKeyEncodingPkcs1. */ -SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, - const uint8_t *keyData, CFIndex keyDataLength, - SecKeyEncoding encoding); - -CFDataRef SecKeyCopyModulus(SecKeyRef rsaPublicKey); -CFDataRef SecKeyCopyExponent(SecKeyRef rsaPublicKey); - -/*! - @function SecKeyCopyPublicBytes - @abstract Gets the bits of a public key - @param key Key to retrieve the bits. - @param publicBytes An out parameter to receive the public key bits - @result Errors if any when retrieving the public key bits.. - */ -OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes); - -/*! - @function SecKeyCreatePublicFromPrivate - @abstract Create a public SecKeyRef from a private SecKeyRef - @param privateKey The private SecKeyRef for which you want the public key - @result A public SecKeyRef, or NULL if the conversion failed - @discussion This is a "best attempt" function, hence the SPI nature. If the public - key bits are not in memory, it attempts to load from the keychain. If the public - key was not tracked on the keychain, it will fail. -*/ -SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); - -/*! - @function SecKeyCreateFromPublicData -*/ -SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef publicBytes); - -#if SEC_OS_OSX_INCLUDES -OSStatus SecKeyRawVerifyOSX( - SecKeyRef key, - SecPadding padding, - const uint8_t *signedData, - size_t signedDataLen, - const uint8_t *sig, - size_t sigLen) -SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyVerifySignature", macos(10.7, 10.15)); - -#endif // SEC_OS_OSX_INCLUDES - -/*! - @constant kSecKeyApplePayEnabled If set to kCFBooleanTrue during SecKeyCreateRandomKey, then the SEP-based key is ApplePay-enabled, - which means that it can be used for ECIES to re-crypt. - */ -extern const CFStringRef kSecKeyApplePayEnabled -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @constant kSecKeyEncryptionParameterSymmetricKeySizeInBits CFNumberRef with size in bits for ephemeral - symmetric key used for encryption/decryption. - */ -extern const CFStringRef kSecKeyEncryptionParameterSymmetricKeySizeInBits -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @constant kSecKeyEncryptionParameterSymmetricAAD CFDataRef with additional authentiction data for AES-GCM encryption. - */ -extern const CFStringRef kSecKeyEncryptionParameterSymmetricAAD -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @constant kSecKeyEncryptionParameterRecryptParameters Usable only for SecKeyCreateDecryptedDataWithParameters. - Contains dictionary with parameters for re-encryption using the same algorithm and encryption parameters - specified inside this dictionary. - */ -extern const CFStringRef kSecKeyEncryptionParameterRecryptParameters -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @constant kSecKeyEncryptionParameterRecryptCertificate Usable only inside kSecKeyEncryptionParameterRecryptParameters. - Specifies certificate whose public key is used to re-crypt previously decrypted data. This parameter should contain - CFDataRef with X509 DER-encoded data of the certificate chain {leaf, intermediate, root}, leaf's public key is - to be used for re-encryption. - */ -extern const CFStringRef kSecKeyEncryptionParameterRecryptCertificate -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @function SecKeyCreateEncryptedDataWithParameters - @abstract Encrypt a block of plaintext. - @param key Public key with which to encrypt the data. - @param algorithm One of SecKeyAlgorithm constants suitable to perform encryption with this key. - @param plaintext The data to encrypt. The length and format of the data must conform to chosen algorithm, - typically be less or equal to the value returned by SecKeyGetBlockSize(). - @param parameters Dictionary with additional parameters for encryption. Supported parameters are: - - kSecKeyKeyExchangeParameterSharedInfo: additional SharedInfo value for ECIES encryptions - - kSecKeyEncryptionParameterSymmetricKeySizeInBits: 128 or 256, size of ephemeral AES key used for symmetric encryption - - kSecKeyEncryptionParameterSymmetricAAD: optional CFDataRef with additiona authentication data for AES-GCM encryption - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result The ciphertext represented as a CFData, or NULL on failure. - @discussion Encrypts plaintext data using specified key. The exact type of the operation including the format - of input and output data is specified by encryption algorithm. - */ -CFDataRef SecKeyCreateEncryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, - CFDictionaryRef parameters, CFErrorRef *error) -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @function SecKeyCreateDecryptedDataWithParameters - @abstract Decrypt a block of ciphertext. - @param key Private key with which to decrypt the data. - @param algorithm One of SecKeyAlgorithm constants suitable to perform decryption with this key. - @param ciphertext The data to decrypt. The length and format of the data must conform to chosen algorithm, - typically be less or equal to the value returned by SecKeyGetBlockSize(). - @param parameters Dictionary with additional parameters for decryption.Supported parameters are: - - kSecKeyKeyExchangeParameterSharedInfo: additional SharedInfo value for ECIES encryptions - - kSecKeyEncryptionParameterSymmetricKeySizeInBits: 128 or 256, size of ephemeral AES key used for symmetric encryption - - kSecKeyEncryptionParameterSymmetricAAD: optional CFDataRef with additiona authentication data for AES-GCM encryption - - kSecKeyEncryptionParameterRecryptParameters: optional CFDictionaryRef with parameters for immediate re-encryption - of decrypted data. If present, the dictionary *must* contain at least kSecKeyEncryptionParameterRecryptCertificate parameter. - - @param error On error, will be populated with an error object describing the failure. - See "Security Error Codes" (SecBase.h). - @result The plaintext represented as a CFData, or NULL on failure. - @discussion Decrypts ciphertext data using specified key. The exact type of the operation including the format - of input and output data is specified by decryption algorithm. - */ -CFDataRef SecKeyCreateDecryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, - CFDictionaryRef parameters, CFErrorRef *error) -SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); - -/*! - @enum SecKeyAttestationKeyType - @abstract Defines types of builtin attestation keys. -*/ -typedef CF_ENUM(uint32_t, SecKeyAttestationKeyType) -{ - kSecKeyAttestationKeyTypeSIK = 0, - kSecKeyAttestationKeyTypeGID = 1, - kSecKeyAttestationKeyTypeUIKCommitted SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 2, - kSecKeyAttestationKeyTypeUIKProposed SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 3, - kSecKeyAttestationKeyTypeSecureElement SPI_AVAILABLE(ios(13.0)) = 4, -} SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); - -/*! - @function SecKeyCopyAttestationKey - @abstract Returns a copy of a builtin attestation key. - - @param keyType Type of the requested builtin key. - @param error An optional pointer to a CFErrorRef. This value is set if an error occurred. - - @result On success a SecKeyRef containing the requested key is returned, on failure it returns NULL. -*/ -SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef *error) -SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); - -/*! - @function SecKeyCreateAttestation - @abstract Attests a key with another key. - - @param key The attesting key. - @param keyToAttest The key which is to be attested. - @param error An optional pointer to a CFErrorRef. This value is set if an error occurred. - - @result On success a CFDataRef containing the attestation data is returned, on failure it returns NULL. - - @discussion Key attestation only works for CTK SEP keys, i.e. keys created with kSecAttrTokenID=kSecAttrTokenIDSecureEnclave. -*/ -CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) -SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); - -/*! - @function SecKeySetParameter - @abstract Sets unspecified key parameter for the backend. - - @param key Key to set the parameter to. - @param name Identifies parameter to be set. - @param value New value for the parameter. - @param error Error which gathers more information when something went wrong. - - @discussion Serves as channel between SecKey client and backend for passing additional sideband data send from SecKey caller - to SecKey implementation backend. Parameter names and types are either generic kSecUse*** attributes or are a contract between - SecKey user (application) and backend and in this case are not interpreted by SecKey layer in any way. - */ -Boolean SecKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) -SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); - -extern const CFStringRef kSecKeyParameterSETokenAttestationNonce -SPI_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); - -/*! - Available lifetime operations for SEP system keys. - */ -typedef CF_ENUM(int, SecKeyControlLifetimeType) { - kSecKeyControlLifetimeTypeBump = 0, - kSecKeyControlLifetimeTypeCommit = 1, -} SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); - -/*! - @function SecKeyControlLifetime - @abstract Performs key lifetime control operations for SEP system keys. - - @param key Key to be controlled, currently must be either proposed or committed system UIK. - @param type Type of the control operation to be performed. - @param error Error which gathers more information when something went wrong. - */ -Boolean SecKeyControlLifetime(SecKeyRef key, SecKeyControlLifetimeType type, CFErrorRef *error) -SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); - -/*! - @function SecKeyCreateDuplicate - @abstract Creates duplicate fo the key. - - @param key Source key to be duplicated - - @discussion Only memory representation of the key is duplicated, so if the key is backed by keychain, only one instance - stays in the keychain. Duplicating key is useful for setting 'temporary' key parameters using SecKeySetParameter. - If the key is immutable (i.e. does not support SecKeySetParameter), calling this method is identical to calling CFRetain(). - */ -SecKeyRef SecKeyCreateDuplicate(SecKeyRef key) -SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); - -/*! - Algorithms for converting between bigendian and core-crypto ccunit data representation. - */ -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureRawCCUnit; -extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionRawCCUnit; - -/*! - Internal algorithm for RSA-MD5. We do not want to export MD5 in new API, but we need it - for implementing legacy interfaces. - */ -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5; -extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5; - -/*! - Algorithms for interoperability with libaks smartcard support. - */ -extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionAKSSmartCard; - -__END_DECLS - -#endif /* !_SECURITY_SECKEYPRIV_H_ */ diff --git a/keychain/SecKeyProxy.h b/keychain/SecKeyProxy.h deleted file mode 100644 index 00018298..00000000 --- a/keychain/SecKeyProxy.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecKeyProxy - Declaration of SecKey proxy object allowing SecKeyRef to be accessed remotely through XPC. - */ - -#ifndef _SECURITY_SECKEYPROXY_H_ -#define _SECURITY_SECKEYPROXY_H_ - -#import -#include -#include - -NS_ASSUME_NONNULL_BEGIN - -@interface SecKeyProxy : NSObject { -@private - id _key; - NSData * _Nullable _certificate; - NSXPCListener *_listener; -} - -// Creates new proxy instance. Proxy holds reference to the target key or identity and allows remote access to that target key as long as the proxy instance is kept alive. -- (instancetype)initWithKey:(SecKeyRef)key; -- (instancetype)initWithIdentity:(SecIdentityRef)identity; - -// Retrieve endpoint to this proxy instance. Endpoint can be transferred over NSXPCConnection and passed to +[createKeyFromEndpoint:error:] method. -@property (readonly, nonatomic) NSXPCListenerEndpoint *endpoint; - -// Invalidates all connections to this proxy. -- (void)invalidate; - -// Creates new SecKey/SecIdentity object which forwards all operations to the target SecKey identified by endpoint. Returned SecKeyRef can be used as long as target SecKeyProxy instance is kept alive. -+ (nullable SecKeyRef)createKeyFromEndpoint:(NSXPCListenerEndpoint *)endpoint error:(NSError **)error; -+ (nullable SecIdentityRef)createIdentityFromEndpoint:(NSXPCListenerEndpoint *)endpoint error:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END - -#endif /* !_SECURITY_SECKEYPROXY_H_ */ diff --git a/keychain/SecSharedCredential.h b/keychain/SecSharedCredential.h deleted file mode 100644 index 21a89444..00000000 --- a/keychain/SecSharedCredential.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecSharedCredential - SecSharedCredential defines CoreFoundation-based functions for - storing and requesting shared password-based credentials. - These credentials are currently able to be shared with Safari and - applications which have a 'com.apple.developer.associated-domains' - entitlement that includes the domain being requested. - */ - -#ifndef _SECURITY_SECSHAREDCREDENTIAL_H_ -#define _SECURITY_SECSHAREDCREDENTIAL_H_ - -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -#ifdef __BLOCKS__ - -/*! - @enum Credential Key Constants - @discussion Predefined key constants used to get values in a dictionary - of credentials returned by SecRequestWebCredential. - @constant kSecSharedPassword Specifies a dictionary key whose value is a - shared password. You use this key to get a value of type CFStringRef - that contains a password. -*/ -extern const CFStringRef kSecSharedPassword API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); - -/*! - @function SecAddSharedWebCredential - @abstract Asynchronously store (or update) a shared password for a website. - @param fqdn The fully qualified domain name of the website requiring the password. - @param account The account name associated with this password. - @param password The password to be stored. Pass NULL to remove a shared password if it exists. - @param completionHandler A block which will be invoked when the function has completed. If the shared password was successfully added (or removed), the CFErrorRef parameter passed to the block will be NULL. If the error parameter is non-NULL, an error occurred and the error reference will hold the result. Note: the error reference will be automatically released after this handler is called, though you may optionally retain it for as long as needed. - @discussion This function adds a shared password item which will be accessible by Safari and applications that have the specified fully-qualified domain name in their 'com.apple.developer.associated-domains' entitlement. If a shared password item already exists for the specified website and account, it will be updated with the provided password. To remove a password, pass NULL for the password parameter. - - Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available. - */ -void SecAddSharedWebCredential(CFStringRef fqdn, CFStringRef account, CFStringRef __nullable password, - void (^completionHandler)(CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); - -/*! - @function SecRequestSharedWebCredential - @abstract Asynchronously obtain one or more shared passwords for a website. - @param fqdn (Optional) Fully qualified domain name of the website for which passwords are being requested. If NULL is passed in this argument, the domain name(s) listed in the calling application's 'com.apple.developer.associated-domains' entitlement are searched implicitly. - @param account (Optional) Account name for which passwords are being requested. The account may be NULL to request all shared credentials which are available for the site, allowing the caller to discover an existing account. - @param completionHandler A block which will be called to deliver the requested credentials. If no matching items were found, the credentials array will be empty, and the CFErrorRef parameter will provide the error result. Note: the credentials and error references will be automatically released after this handler is called, though you may optionally retain either for as long as needed. - @discussion This function requests one or more shared passwords for a given website, depending on whether the optional account parameter is supplied. To obtain results, the website specified in the fqdn parameter must be one which matches an entry in the calling application's 'com.apple.developer.associated-domains' entitlement. - - If matching shared password items are found, the credentials provided to the completionHandler will be a CFArrayRef containing CFDictionaryRef entries. Each dictionary entry will contain the following pairs (see Security/SecItem.h): - key: kSecAttrServer value: CFStringRef (the website) - key: kSecAttrAccount value: CFStringRef (the account) - key: kSecSharedPassword value: CFStringRef (the password) - - If the found item specifies a non-standard port number (i.e. other than 443 for https), the following key may also be present: - key: kSecAttrPort value: CFNumberRef (the port number) - - Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available. - */ -void SecRequestSharedWebCredential(CFStringRef __nullable fqdn, CFStringRef __nullable account, - void (^completionHandler)(CFArrayRef __nullable credentials, CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); - -/*! - @function SecCreateSharedWebCredentialPassword - @abstract Returns a randomly generated password. - @return CFStringRef password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present. -*/ -__nullable -CFStringRef SecCreateSharedWebCredentialPassword(void) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); - - -#endif /* __BLOCKS__ */ - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECSHAREDCREDENTIAL_H_ */ - diff --git a/keychain/SecureObjectSync/Regressions/SOSTestDevice.c b/keychain/SecureObjectSync/Regressions/SOSTestDevice.c index fb72a1c8..85efa2ec 100644 --- a/keychain/SecureObjectSync/Regressions/SOSTestDevice.c +++ b/keychain/SecureObjectSync/Regressions/SOSTestDevice.c @@ -36,8 +36,8 @@ #include #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" #include #include #include @@ -267,22 +267,6 @@ CFDataRef SOSTestDeviceCreateMessage(SOSTestDeviceRef td, CFStringRef peerID) { return msgData; } -#if 0 -CFDictionaryRef SOSTestDeviceCreateMessages(SOSTestDeviceRef td) { - CFTypeRef peer = NULL; - CFMutableDictionaryRef messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayForEachC(td->peers, peer) { - CFStringRef peerID = SOSPeerGetID((SOSPeerRef)peer); - CFDataRef msg = SOSTestDeviceCreateMessage(td, peerID); - if (msg) { - CFDictionaryAddValue(messages, peerID, msg); - CFRelease(msg); - } - } - return messages; -} -#endif - bool SOSTestDeviceHandleMessage(SOSTestDeviceRef td, CFStringRef peerID, CFDataRef msgData) { setup("handle message"); if (!msgData) return false; diff --git a/keychain/SecureObjectSync/Regressions/sc-40-circle.c b/keychain/SecureObjectSync/Regressions/sc-40-circle.c index 365b88bf..6f516bd1 100644 --- a/keychain/SecureObjectSync/Regressions/sc-40-circle.c +++ b/keychain/SecureObjectSync/Regressions/sc-40-circle.c @@ -41,7 +41,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSCircle_regressions.h" diff --git a/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c b/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c index 87158469..7ee15736 100644 --- a/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c +++ b/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c @@ -26,7 +26,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSCircle_regressions.h" diff --git a/keychain/SecureObjectSync/SOSAccount.h b/keychain/SecureObjectSync/SOSAccount.h index a01d0384..9fed6f2f 100644 --- a/keychain/SecureObjectSync/SOSAccount.h +++ b/keychain/SecureObjectSync/SOSAccount.h @@ -248,7 +248,7 @@ CFStringRef SOSInterestListCopyDescription(CFArrayRef interests); SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount* account, CFErrorRef*); CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccount* account, SOSPeerInfoRef applicant, CFErrorRef *error); bool SOSAccountJoinWithCircleJoiningBlob(SOSAccount* account, CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); -CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error); +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, SOSInitialSyncFlags flags, CFErrorRef *error); // // MARK: Initial-Sync @@ -288,7 +288,7 @@ bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef pe void SOSAccountResetOTRNegotiationCoder(SOSAccount* account, CFStringRef peerid); void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* peerid, NSString* accessGroup); -NSMutableArray* SOSAccountGetAllTLKs(void); +NSArray* SOSAccountGetAllTLKs(void); CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account); __END_DECLS diff --git a/keychain/SecureObjectSync/SOSAccount.m b/keychain/SecureObjectSync/SOSAccount.m index 6c514ce6..41035e2f 100644 --- a/keychain/SecureObjectSync/SOSAccount.m +++ b/keychain/SecureObjectSync/SOSAccount.m @@ -44,13 +44,12 @@ #if OCTAGON #import "keychain/ckks/CKKSViewManager.h" #import "keychain/ckks/CKKSLockStateTracker.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTManager.h" #endif #include #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" -#include +#include "keychain/securityd/SecItemServer.h" #import "SecdWatchdog.h" @@ -2327,11 +2326,11 @@ AddViewManagerResults(NSMutableArray *results, NSMutableSet *seenUUID) } -NSMutableArray* +NSArray* SOSAccountGetAllTLKs(void) { CFTypeRef result = NULL; - NSMutableArray* results = [NSMutableArray array]; + NSMutableArray* results = [NSMutableArray array]; NSMutableSet *seenUUID = [NSMutableSet set]; // first use the TLK from the view manager @@ -2400,6 +2399,7 @@ static uint8_t* piggy_encode_data(NSData* data, } +// you can not add more items here w/o also adding a version, older clients wont understand newer numbers static kTLKTypes name2type(NSString *view) { @@ -2414,6 +2414,7 @@ name2type(NSString *view) return kTLKUnknown; } +// you can not add more items here w/o also adding a version, older clients wont understand newer numbers static unsigned rank_type(NSString *view) { @@ -2613,21 +2614,28 @@ CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* return identities; } -CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error) { - CFMutableArrayRef identities = SOSAccountCopyiCloudIdentities(account); - secnotice("piggy", "identities: %@", identities); +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, SOSInitialSyncFlags flags, CFErrorRef *error) { - NSMutableArray *encodedIdenities = [NSMutableArray array]; - CFIndex i, count = CFArrayGetCount(identities); - for (i = 0; i < count; i++) { - SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identities, i); - NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, error)); - if (data) - [encodedIdenities addObject:data]; + NSMutableArray* encodedIdenities = [NSMutableArray array]; + NSArray* tlks = nil; + + if (flags & kSOSInitialSyncFlagiCloudIdentity) { + CFMutableArrayRef identities = SOSAccountCopyiCloudIdentities(account); + secnotice("piggy", "identities: %@", identities); + + CFIndex i, count = CFArrayGetCount(identities); + for (i = 0; i < count; i++) { + SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identities, i); + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, error)); + if (data) + [encodedIdenities addObject:data]; + } + CFRelease(identities); + } + + if (flags & kSOSInitialSyncFlagTLKs) { + tlks = SOSAccountGetAllTLKs(); } - CFRelease(identities); - - NSMutableArray* tlks = SOSAccountGetAllTLKs(); return CFBridgingRetain(SOSPiggyCreateInitialSyncData(encodedIdenities, tlks)); } diff --git a/keychain/SecureObjectSync/SOSAccountGhost.m b/keychain/SecureObjectSync/SOSAccountGhost.m index a278a5a3..f8de69c2 100644 --- a/keychain/SecureObjectSync/SOSAccountGhost.m +++ b/keychain/SecureObjectSync/SOSAccountGhost.m @@ -18,6 +18,8 @@ #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" #include "keychain/SecureObjectSync/SOSAuthKitHelpers.h" #import "Analytics/Clients/SOSAnalytics.h" +#include "utilities/SecTrace.h" + #define DETECT_IOS_ONLY 1 @@ -290,9 +292,10 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA __block bool result = false; CFErrorRef localError = NULL; __block NSUInteger nbusted = 9999; - __block NSMutableDictionary *attributes =[NSMutableDictionary new]; + NSMutableDictionary *attributes =[NSMutableDictionary new]; + int circleSize = SOSCircleCountPeers(account.trust.trustedCircle); - if ([akh isUseful] && [account isInCircle:nil] && SOSCircleCountPeers(account.trust.trustedCircle) > mincount) { + if ([akh isUseful] && [account isInCircle:nil] && circleSize > mincount) { if(options & SOSGhostBustiCloudIdentities) { secnotice("ghostBust", "Callout to cleanup icloud identities"); result = SOSGhostBustiCloudIdentityPrivateKeys(account); @@ -306,7 +309,8 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA nbusted += thinBusted; attributes[@"byAge"] = @(thinBusted); } - attributes[@"total"] = @(nbusted); + attributes[@"total"] = @(SecBucket1Significant(nbusted)); + attributes[@"startCircleSize"] = @(SecBucket1Significant(circleSize)); result = nbusted > 0; if(result) { SOSAccountRestartPrivateCredentialTimer(account); @@ -318,7 +322,7 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA } return result; }]; - secnotice("circleOps", "Ghostbusting %@ (%@)", result ? CFSTR("Performed") : CFSTR("Not Performed"), localError); + secnotice("circleOps", "Ghostbusting %@ (%@)", result ? CFSTR("Performed") : CFSTR("Not Performed"), localError); } } else { secnotice("circleOps", "Ghostbusting skipped"); diff --git a/keychain/SecureObjectSync/SOSAccountPriv.h b/keychain/SecureObjectSync/SOSAccountPriv.h index 7300f540..fd6d2b1b 100644 --- a/keychain/SecureObjectSync/SOSAccountPriv.h +++ b/keychain/SecureObjectSync/SOSAccountPriv.h @@ -32,7 +32,7 @@ #include "keychain/SecureObjectSync/SOSRing.h" #include "keychain/SecureObjectSync/SOSRingUtils.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "keychain/SecureObjectSync/SOSEngine.h" #include "keychain/SecureObjectSync/SOSPeer.h" #include "keychain/SecureObjectSync/SOSFullPeerInfo.h" diff --git a/keychain/SecureObjectSync/SOSAccountTransaction.h b/keychain/SecureObjectSync/SOSAccountTransaction.h index 36ba7cb3..414e6dcb 100644 --- a/keychain/SecureObjectSync/SOSAccountTransaction.h +++ b/keychain/SecureObjectSync/SOSAccountTransaction.h @@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SOSAccount (Transaction) + (void)performOnQuietAccountQueue:(void (^)(void))action; -+ (void)performWhileHoldingAccountQueue:(void (^)(void))action; - (void) performTransaction: (void (^)(SOSAccountTransaction* txn)) action; - (void) performTransaction_Locked: (void (^)(SOSAccountTransaction* txn)) action; diff --git a/keychain/SecureObjectSync/SOSAccountTransaction.m b/keychain/SecureObjectSync/SOSAccountTransaction.m index 7fa73312..1c014b29 100644 --- a/keychain/SecureObjectSync/SOSAccountTransaction.m +++ b/keychain/SecureObjectSync/SOSAccountTransaction.m @@ -427,14 +427,6 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) { __thread bool __hasAccountQueue = false; -+ (void)performWhileHoldingAccountQueue:(void (^)(void))action -{ - bool hadAccountQueue = __hasAccountQueue; - __hasAccountQueue = true; - action(); - __hasAccountQueue = hadAccountQueue; -} - + (void)performOnQuietAccountQueue:(void (^)(void))action { SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef(); diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h index fa7d5b1f..624badd0 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h @@ -33,6 +33,7 @@ action:(SOSModifyPeersInCircleBlock)block; -(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error; -(bool) joinCircle:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef)user_key useCloudPeer:(bool)use_cloud_peer err:(CFErrorRef*) error; +-(bool) fixICloudIdentities:(SOSAccount *) account circle: (SOSCircleRef) circle; @end diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m index e9486c1d..d118ec54 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m @@ -14,10 +14,15 @@ #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" #import "keychain/SecureObjectSync/SOSAccountGhost.h" +#import "keychain/SecureObjectSync/SOSIntervalEvent.h" #import "keychain/SecureObjectSync/SOSViews.h" +#import "Analytics/Clients/SOSAnalytics.h" + @implementation SOSAccountTrustClassic (Circle) +#define ICLOUDIDDATE @"iCloudIDDate" + -(bool) isInCircleOnly:(CFErrorRef *)error { SOSCCStatus result = [self getCircleStatusOnly:error]; @@ -239,6 +244,16 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO return hasUpdated; } +// Check on the iCloud identity availability every 24-36 hours random interval +- (SOSIntervalEvent *) iCloudCheckEventHandle: (SOSAccount *) account { + return [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"iCloudIDCheck" earliest:60*60*24 latest:60*60*36]; +} + +// Cleanup unusable iCloud identities every 5-7 days random interval +- (SOSIntervalEvent *) iCloudCleanerHandle: (SOSAccount *) account { + return [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"iCloudCleanerCheck" earliest:60*60*24*5 latest:60*60*24*7]; +} + -(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSKVSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error { bool success = true; @@ -474,6 +489,21 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO } CFReleaseNull(reject); } + + if(me && account.accountKeyIsTrusted && SOSCircleHasPeer(newCircle, me, NULL)) { + // do this on daily interval +/- 8 hours random to keep all peers doing this at the same time + SOSIntervalEvent *iCloudCheckEvent = [self iCloudCheckEventHandle: account]; + if([iCloudCheckEvent checkDate]) { + bool fixedIdentities = [self fixICloudIdentities:account circle:newCircle]; + if(fixedIdentities) { + writeUpdate = true; + secnotice("circleOps", "Fixed iCloud Identity in circle"); + } else { + secnotice("circleOps", "Failed to fix broken icloud identity"); + } + [iCloudCheckEvent followup]; + } + } CFRetainSafe(oldCircle); account.previousAccountKey = account.accountKey; @@ -583,6 +613,45 @@ fail: } +// true means things changed. +-(bool) fixICloudIdentities:(SOSAccount *) account circle: (SOSCircleRef) circle { + bool retval = false; + SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); + if(!icfpi) { + SOSAccountRestartPrivateCredentialTimer(account); + if((SOSAccountGetPrivateCredential(account, NULL) != NULL) || SOSAccountAssertStashedAccountCredential(account, NULL)) { + SecKeyRef privKey = SOSAccountGetPrivateCredential(account, NULL); + if(privKey) { + SOSIntervalEvent *iCloudCleanupEvent = [self iCloudCleanerHandle: account]; + if([iCloudCleanupEvent checkDate]) { + SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); + [iCloudCleanupEvent followup]; + } + CFErrorRef error = NULL; + bool identityAdded = [self addiCloudIdentity:circle key:privKey err:&error]; + if(identityAdded) { + account.notifyBackupOnExit = true; + retval = true; + [[SOSAnalytics logger] logSuccessForEventNamed:@"iCloudIdentityFix"]; + } else { + [[SOSAnalytics logger] logResultForEvent:@"iCloudIdentityFix" hardFailure:true result:(__bridge NSError * _Nullable)(error)]; + } + CFReleaseNull(error); + } else { + NSDictionary *attr = @{ @"reason" : @"noPrivateKey" }; + [[SOSAnalytics logger] logHardFailureForEventNamed:@"iCloudIdentityFix" withAttributes:attr]; + } + } else { + NSDictionary *attr = @{ @"reason" : @"noPrivateKey" }; + [[SOSAnalytics logger] logHardFailureForEventNamed:@"iCloudIdentityFix" withAttributes:attr]; + } + } else { + // everything is fine. + CFReleaseNull(icfpi); + } + return retval; +} + -(void) generationSignatureUpdateWith:(SOSAccount*)account key:(SecKeyRef) privKey { // rdar://51233857 - don't gensign if there isn't a change in the userKey @@ -604,19 +673,11 @@ fail: change |= SOSCircleGenerationSign(circle, privKey, self.fullPeerInfo, NULL); [self setDepartureCode:kSOSNeverLeftCircle]; } else if(iAmPeer) { - SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); - if(!icfpi) { - SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); - bool identityAdded = [self addiCloudIdentity:circle key:privKey err:NULL]; - if(identityAdded) { - account.notifyBackupOnExit = true; - } - change |= identityAdded; - } else { - CFReleaseNull(icfpi); - } + change |= [self fixICloudIdentities:account circle:circle]; } secnotice("updatingGenSignature", "we changed the circle? %@", change ? CFSTR("YES") : CFSTR("NO")); + SOSIntervalEvent *iCloudCheckEvent = [self iCloudCheckEventHandle: account]; + [iCloudCheckEvent followup]; return change; }]; } diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic.h b/keychain/SecureObjectSync/SOSAccountTrustClassic.h index f9b7a9a7..a1a2e237 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic.h +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic.h @@ -60,5 +60,6 @@ -(void) addRingDictionary; -(void) resetRingDictionary; + @end #endif /* SOSAccountTrustClassic_h */ diff --git a/keychain/SecureObjectSync/SOSCloudCircle.h b/keychain/SecureObjectSync/SOSCloudCircle.h index bb26d2db..46bbae1e 100644 --- a/keychain/SecureObjectSync/SOSCloudCircle.h +++ b/keychain/SecureObjectSync/SOSCloudCircle.h @@ -69,6 +69,12 @@ enum { // Types // +typedef CF_OPTIONS(uint32_t, SOSInitialSyncFlags) { + kSOSInitialSyncFlagTLKs = (1UL << 0), + kSOSInitialSyncFlagiCloudIdentity = (1UL << 1), +}; + + enum { kSOSCCInCircle = 0, kSOSCCNotInCircle = 1, @@ -756,7 +762,7 @@ void SOSCCGhostBustTriggerTimed(SOSAccountGhostBustingOptions options, void (^co void SOSCCGhostBustInfo(void (^complete)(NSData *json, NSError *error)); -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error); NSString * SOSCCCircleHash(NSError **error); diff --git a/keychain/SecureObjectSync/SOSCloudCircle.m b/keychain/SecureObjectSync/SOSCloudCircle.m index 4fe74fe0..d1af2e1a 100644 --- a/keychain/SecureObjectSync/SOSCloudCircle.m +++ b/keychain/SecureObjectSync/SOSCloudCircle.m @@ -47,7 +47,7 @@ #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include @@ -63,7 +63,7 @@ #include #define MINIMIZE_INCLUDES MINIMIZE_INCLUDES #include -#include +#include "keychain/securityd/spi.h" #include @@ -396,6 +396,31 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef peer_info_error_request(enum SecXPCOpe return result; } +static CFDataRef flags_to_data_error_request(enum SecXPCOperation op, uint32_t flags, CFErrorRef *error) +{ + __block CFDataRef result = NULL; + + secdebug("sosops", "enter -- operation: %d", op); + securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { + xpc_dictionary_set_uint64(message, kSecXPCKeyFlags, flags); + return true; + }, ^bool(xpc_object_t response, CFErrorRef *error) { + xpc_object_t temp_result = xpc_dictionary_get_value(response, kSecXPCKeyResult); + if (response && (NULL != temp_result)) { + result = _CFXPCCreateCFObjectFromXPCObject(temp_result); + } + return result != NULL; + }); + + if (!isData(result)) { + SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), result); + return NULL; + } + + return result; +} + + static CFDataRef data_to_error_request(enum SecXPCOperation op, CFErrorRef *error) { __block CFDataRef result = NULL; @@ -1731,13 +1756,13 @@ CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error }, CFSTR("return=%@")); } -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error) { +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error) { secnotice("circleJoin", "enter SOSCCCopyInitialSyncData approver"); sec_trace_enter_api(NULL); sec_trace_return_api(CFDataRef, ^{ - do_if_registered(soscc_CopyInitialSyncData, error); - return data_to_error_request(kSecXPCOpCopyInitialSyncBlob, error); + do_if_registered(soscc_CopyInitialSyncData, flags, error); + return flags_to_data_error_request(kSecXPCOpCopyInitialSyncBlob, flags, error); }, CFSTR("return=%@")); } diff --git a/keychain/SecureObjectSync/SOSCloudCircleInternal.h b/keychain/SecureObjectSync/SOSCloudCircleInternal.h index 1ed5dde6..36e5dfbd 100644 --- a/keychain/SecureObjectSync/SOSCloudCircleInternal.h +++ b/keychain/SecureObjectSync/SOSCloudCircleInternal.h @@ -114,7 +114,7 @@ bool SOSCCDeleteEngineState(CFErrorRef *error); CFDataRef SOSCCCopyRecoveryPublicKey(CFErrorRef *error); CFDictionaryRef SOSCCCopyBackupInformation(CFErrorRef *error); bool SOSCCTestPopulateKVSWithBadKeys(CFErrorRef *error); -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error); void SOSCCForEachEngineStateAsStringFromArray(CFArrayRef states, void (^block)(CFStringRef oneStateString)); diff --git a/keychain/SecureObjectSync/SOSDataSource.h b/keychain/SecureObjectSync/SOSDataSource.h index 39099b58..371edeae 100644 --- a/keychain/SecureObjectSync/SOSDataSource.h +++ b/keychain/SecureObjectSync/SOSDataSource.h @@ -55,7 +55,6 @@ struct SOSDataSourceFactory { CFStringRef (*copy_name)(SOSDataSourceFactoryRef factory); SOSDataSourceRef (*create_datasource)(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, CFErrorRef *error); void (*release)(SOSDataSourceFactoryRef factory); - void (*circle_changed)(SOSDataSourceFactoryRef factory, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs); }; static inline CFStringRef SOSDataSourceFactoryCopyName(SOSDataSourceFactoryRef dsf) { @@ -71,11 +70,6 @@ static inline void SOSDataSourceFactoryRelease(SOSDataSourceFactoryRef dsf) { dsf->release(dsf); } -static inline void SOSDataSourceFactoryCircleChanged(SOSDataSourceFactoryRef dsf, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs) { - dsf->circle_changed(dsf, myPeerID, trustedPeerIDs, untrustedPeerIDs); -} - - // // MARK: - SOSDataSource protocol // diff --git a/keychain/SecureObjectSync/SOSEngine.c b/keychain/SecureObjectSync/SOSEngine.c index 00a09107..f2a4a9db 100644 --- a/keychain/SecureObjectSync/SOSEngine.c +++ b/keychain/SecureObjectSync/SOSEngine.c @@ -57,12 +57,12 @@ #include #include -#include // TODO: We can't leave this here. -#include // TODO: We can't leave this here. +#include "keychain/securityd/SecItemServer.h" // TODO: We can't leave this here. +#include "keychain/securityd/SOSCloudCircleServer.h" // TODO: We can't leave this here. #include // TODO: We can't leave this here. #include // TODO: We can't leave this here. -#include -#include +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/iCloudTrace.h" #include @@ -1276,51 +1276,6 @@ static void SOSEngineSetNotifyPhaseBlock(SOSEngineRef engine) { }); } -#if 0 // TODO: update these checks -static void SOSEngineCircleChanged_sanitycheck(SOSEngineRef engine, CFStringRef myPeerID, CFArrayRef trustedPeers, CFArrayRef untrustedPeers) { - // Logging code - CFMutableArrayRef addedPeers = CFArrayCreateDifference(kCFAllocatorDefault, trustedPeers, engine->peerIDs); - CFMutableArrayRef deletedPeers = CFArrayCreateDifference(kCFAllocatorDefault, engine->peerIDs, trustedPeers); - CFMutableArrayRef addedUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, untrustedPeers, engine->peerIDs); - CFMutableArrayRef deletedUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, engine->peerIDs, untrustedPeers); - - CFStringRef tpDesc = SOSPeerIDArrayCreateString(trustedPeers); - CFStringRef apDesc = SOSPeerIDArrayCreateString(addedPeers); - CFStringRef dpDesc = SOSPeerIDArrayCreateString(deletedPeers); - CFStringRef aupDesc = SOSPeerIDArrayCreateString(addedUntrustedPeers); - CFStringRef dupDesc = SOSPeerIDArrayCreateString(deletedUntrustedPeers); - secnotice("engine", "trusted %@ added %@ removed %@ add ut: %@ rem ut: %@", tpDesc, apDesc, dpDesc, aupDesc, dupDesc); - CFReleaseSafe(dupDesc); - CFReleaseSafe(aupDesc); - CFReleaseSafe(dpDesc); - CFReleaseSafe(apDesc); - CFReleaseSafe(tpDesc); - - // Assertions: - // Ensure SOSAccount isn't giving us the runaround. - // Assert that trustedPeers, untrustedPeers and myPeerId are disjoint sets - if (trustedPeers) { - CFMutableArrayRef allTrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, trustedPeers, untrustedPeers); - assert(CFEqual(trustedPeers, allTrustedPeers)); - CFReleaseSafe(allTrustedPeers); - assert(!CFArrayContainsValue(trustedPeers, CFRangeMake(0, CFArrayGetCount(trustedPeers)), myPeerID)); - } - if (untrustedPeers) { - CFMutableArrayRef allUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, untrustedPeers, trustedPeers); - assert(CFEqual(untrustedPeers, allUntrustedPeers)); - CFReleaseSafe(allUntrustedPeers); - assert(!CFArrayContainsValue(untrustedPeers, CFRangeMake(0, CFArrayGetCount(trustedPeers)), myPeerID)); - } - - CFReleaseNull(deletedUntrustedPeers); - CFReleaseNull(addedUntrustedPeers); - CFReleaseNull(deletedPeers); - CFReleaseNull(addedPeers); - - // End of logging and asertions, actual code here. -} -#endif - static SOSChangeTrackerRef SOSReferenceAndGetChangeTracker(CFDictionaryRef lookup, CFMutableDictionaryRef referenced, CFSetRef viewNameSet) { SOSChangeTrackerRef ct = (SOSChangeTrackerRef)CFDictionaryGetValue(referenced, viewNameSet); if (!ct) { @@ -2070,163 +2025,6 @@ L local C confirmed */ -#if 0 -static bool SOSAppendRemoveToPatch(CFTypeRef remove, CFMutableDictionaryRef patch, CFErrorRef *error) { -} - -static bool SOSAppendAddToPatch(CFTypeRef add, CFMutableDictionaryRef patch, CFErrorRef *error) { -} - -static bool SOSAppendDiffToPatch(CFTypeRef left, CFTypeRef right, CFMutableDictionaryRef patch, CFErrorRef *error) { - bool ok = true; - if (!left && right) { - SOSAppendAddToPatch(right, patch, error); - } else if (left && !right) { - SOSAppendRemoveToPatch(left, patch, error); - } else if (left && right) { - CFTypeID ltype = CFGetTypeID(left); - CFTypeID rtype = CFGetTypeID(right); - if (ltype == rtype) { - if (CFArrayGetTypeID() == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type array"), ltype); - } else if (CFBooleanGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type boolean"), ltype); - } else if (CFDataGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type data"), ltype); - } else if (CFDictionaryGetTypeID == ltype) { - __block CFMutableDictionaryRef leftnotright = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - __block CFMutableDictionaryRef rightnotleft = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, right); - - CFDictionaryForEach(left, ^(const void *key, const void *lvalue) { - const void *rvalue = NULL; - if (CFDictionaryGetValueIfPresent(right, key, &rvalue)) { - CFDictionaryRemoveValue(rightnotleft, key); - - CFMutableDictionaryRef subpatch = CFDictionaryCreateForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(patch, key, subpatch); - SOSAppendDiffToPatch(lvalue, rvalue, subpatch, error); - CFReleaseSafe(subpatch); - } else { - CFDictionaryAddValue(leftnotright, key, lvalue); - } - }); - // Proccess leftnotright and rightnotleft - CFReleaseSafe(leftnotright); - CFReleaseSafe(rightnotleft); - } else if (SOSManifestGetTypeID == ltype) { - SOSManifestRef removed = NULL, added = NULL; - ok &= SOSManifestDiff(left, right, &removed, &added, error); - if (SOSManifestGetCount(removed) || SOSManifestGetCount(added)) { - SOSAppendDiffToPatch(lvalue, rvalue, subpatch, error); - CFStringAppend(, <#CFStringRef appendedString#>) - } - CFReleaseSafe(removed); - CFReleaseSafe(added); - } else if (CFNumberGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type number"), ltype); - } else if (CFSetGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type set"), ltype); - } else if (CFStringGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type string"), ltype); - } else { - ok = SecError(errSecParam, error, CFSTR("unknown type %lu"), ltype); - } - } - } else if (!left && !right) { - // NOOP - } -} -#endif - -static __unused bool SOSEngineCheckPeerIntegrity(SOSEngineRef engine, SOSPeerRef peer, CFErrorRef *error) { -#if 0 - //static CFMutableDictionaryRef p2amtu; - if (!engine->p2amtu) - engine->p2amtu = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef amtu = CFDictionaryGetValue(engine->p2amtu, SOSPeerGetID(peer)); -#endif - - // Inputs - SOSManifestRef L = SOSEngineCopyLocalPeerManifest_locked(engine, peer, error); - SOSManifestRef T = SOSPeerGetPendingObjects(peer); - SOSManifestRef C = SOSPeerGetConfirmedManifest(peer); - SOSManifestRef U = SOSPeerGetUnwantedManifest(peer); - - // Computed - SOSManifestRef CunionU = SOSManifestCreateUnion(C, U, error); - SOSManifestRef S = SOSManifestCreateIntersection(L, CunionU, error); - - SOSManifestRef AunionT = NULL, MunionU = NULL; - SOSManifestDiff(L, C, &AunionT, &MunionU, error); - - SOSManifestRef A = SOSManifestCreateComplement(T, AunionT, error); - SOSManifestRef M = SOSManifestCreateComplement(U, MunionU, error); - - SOSManifestRef SunionAunionT = SOSManifestCreateUnion(S, AunionT, error); - SOSManifestRef SunionMunionU = SOSManifestCreateUnion(S, MunionU, error); - - SOSManifestRef AintersectM = SOSManifestCreateIntersection(A, M, error); - SOSManifestRef AintersectS = SOSManifestCreateIntersection(A, S, error); - SOSManifestRef AintersectT = SOSManifestCreateIntersection(A, T, error); - SOSManifestRef AintersectU = SOSManifestCreateIntersection(A, U, error); - SOSManifestRef MintersectS = SOSManifestCreateIntersection(M, S, error); - SOSManifestRef MintersectT = SOSManifestCreateIntersection(M, T, error); - SOSManifestRef MintersectU = SOSManifestCreateIntersection(M, U, error); - SOSManifestRef SintersectT = SOSManifestCreateIntersection(S, T, error); - SOSManifestRef SintersectU = SOSManifestCreateIntersection(S, U, error); - SOSManifestRef TintersectU = SOSManifestCreateIntersection(T, U, error); - -#if 0 - CFDictionaryRef newAmtu = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("A"), A, CFSTR("M"), M, CFSTR("T"), T, CFSTR("U") U, NULL); - CFDictionarySetValue(engine->p2amtu, SOSPeerGetID(peer), newAmtu); - CFMutableStringRef amtuChanges = CFStringCreateMutable(kCFAllocatorDefault, 0); - SOSAppendDiffToString(amtu, newAmtu, amtuChanges); - secnotice("engine", "%@: %@", SOSPeerGetID(peer), amtuChanges); -#endif - -#define SOSASSERT(e) (__builtin_expect(!(e), 0) ? secnotice("engine", "state-assertion %s", #e), assert(e) : (void)0) - - SOSASSERT(L ? CFEqual(L, SunionAunionT) : SOSManifestGetCount(SunionAunionT) == 0); - SOSASSERT(C ? CFEqual(C, SunionMunionU) : SOSManifestGetCount(SunionMunionU) == 0); - - SOSASSERT(SOSManifestGetCount(AintersectM) == 0); - SOSASSERT(SOSManifestGetCount(AintersectS) == 0); - SOSASSERT(SOSManifestGetCount(AintersectT) == 0); - SOSASSERT(SOSManifestGetCount(AintersectU) == 0); - SOSASSERT(SOSManifestGetCount(MintersectS) == 0); - SOSASSERT(SOSManifestGetCount(MintersectT) == 0); - SOSASSERT(SOSManifestGetCount(MintersectU) == 0); - SOSASSERT(SOSManifestGetCount(SintersectT) == 0); - SOSASSERT(SOSManifestGetCount(SintersectU) == 0); - SOSASSERT(SOSManifestGetCount(TintersectU) == 0); - - CFReleaseSafe(AintersectM); - CFReleaseSafe(AintersectS); - CFReleaseSafe(AintersectT); - CFReleaseSafe(AintersectU); - CFReleaseSafe(MintersectS); - CFReleaseSafe(MintersectT); - CFReleaseSafe(MintersectU); - CFReleaseSafe(SintersectT); - CFReleaseSafe(SintersectU); - CFReleaseSafe(TintersectU); - - CFReleaseSafe(AunionT); - CFReleaseSafe(MunionU); - CFReleaseSafe(CunionU); - - CFReleaseNull(SunionAunionT); - CFReleaseNull(SunionMunionU); - - CFReleaseSafe(A); - CFReleaseSafe(M); - CFReleaseSafe(S); - //CFReleaseSafe(T); // Get - //CFReleaseSafe(U); // Get - //CFReleaseSafe(C); // Get - CFReleaseSafe(L); - return true; -} void SOSEngineSetSyncCompleteListener(SOSEngineRef engine, SOSEnginePeerInSyncBlock notify_block) { SOSEngineDoOnQueue(engine, ^{ @@ -2518,7 +2316,6 @@ CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef t SOSPeerAddLocalManifest(pmsc2->peer, pmsc2->local); SOSPeerAddProposedManifest(pmsc2->peer, pmsc2->proposed); secnoticeq("engine", "send %@:%@ %@", pmsc2->engine->myID, SOSPeerGetID(pmsc2->peer), pmsc2->message); - //SOSEngineCheckPeerIntegrity(engine, peer, NULL); } else { secerror("%@:%@ failed to send %@", pmsc2->engine->myID, SOSPeerGetID(pmsc2->peer), pmsc2->message); } diff --git a/keychain/SecureObjectSync/SOSFullPeerInfo.m b/keychain/SecureObjectSync/SOSFullPeerInfo.m index d14f20e9..7b2bee13 100644 --- a/keychain/SecureObjectSync/SOSFullPeerInfo.m +++ b/keychain/SecureObjectSync/SOSFullPeerInfo.m @@ -226,8 +226,9 @@ CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error) exit: CFReleaseNull(query); CFReleaseNull(pubKey); - - secnotice("fpi","no private key found"); + if (vData == NULL) { + secnotice("fpi","no private key found"); + } return (CFDataRef)vData; } diff --git a/keychain/SecureObjectSync/SOSInternal.m b/keychain/SecureObjectSync/SOSInternal.m index 0506af6f..35e8c151 100644 --- a/keychain/SecureObjectSync/SOSInternal.m +++ b/keychain/SecureObjectSync/SOSInternal.m @@ -37,7 +37,7 @@ #include #include #include -#include // For SecError +#include "keychain/securityd/SecDbItem.h" // For SecError #include "utilities/iOSforOSX.h" #include diff --git a/keychain/SecureObjectSync/SOSIntervalEvent.h b/keychain/SecureObjectSync/SOSIntervalEvent.h new file mode 100644 index 00000000..324befa3 --- /dev/null +++ b/keychain/SecureObjectSync/SOSIntervalEvent.h @@ -0,0 +1,26 @@ +// +// SOSIntervalEvent.h +// Security +// +// Created by murf on 9/12/19. +// + +#ifndef SOSIntervalEvent_h +#define SOSIntervalEvent_h + +@interface SOSIntervalEvent : NSObject + +@property (nonatomic, retain) NSUserDefaults *defaults; +@property (nonatomic, retain) NSString *dateDescription; +@property (nonatomic) NSTimeInterval earliestDate; +@property (nonatomic) NSTimeInterval latestDate; + +- (id) initWithDefaults:(NSUserDefaults*) defaults dateDescription:(NSString *)dateDescription earliest:(NSTimeInterval) earliest latest: (NSTimeInterval) latest; +- (void) schedule; +- (bool) checkDate; +- (NSDate *) getDate; +- (void) followup; + +@end + +#endif /* SOSIntervalEvent_h */ diff --git a/keychain/SecureObjectSync/SOSIntervalEvent.m b/keychain/SecureObjectSync/SOSIntervalEvent.m new file mode 100644 index 00000000..30fda736 --- /dev/null +++ b/keychain/SecureObjectSync/SOSIntervalEvent.m @@ -0,0 +1,70 @@ +// +// SOSIntervalEvent.m +// Security_ios +// +// Created by murf on 9/12/19. +// + +#import +#import "SOSIntervalEvent.h" +#import "keychain/SecureObjectSync/SOSInternal.h" + +/* + + interval setting examples: + NSTimeInterval earliestGB = 60*60*24*3; // wait at least 3 days + NSTimeInterval latestGB = 60*60*24*7; // wait at most 7 days + + pattern: + +SOSIntervalEvent fooEvent = [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"foocheck" earliest:60*60*24 latest:60*60*36]; + + // should we foo? + if([fooEvent checkDate]) { + WeDoFooToo(); + // schedule next foo + [fooEvent followup]; + } + // "schedule" is only used if you think there's a date upcoming you don't want altered + // getDate will return the next schedule event date + */ + +@implementation SOSIntervalEvent + +- (NSDate *) getDate { + return [_defaults valueForKey: _dateDescription]; +} + +- (bool) checkDate { + NSDate *theDate = [self getDate]; + if(theDate && ([theDate timeIntervalSinceNow] <= 0)) return true; + return false; +} + +- (void) followup { + NSDate *theDate = SOSCreateRandomDateBetweenNowPlus(_earliestDate, _latestDate); + [_defaults setValue:theDate forKey: _dateDescription]; +} + +- (void)schedule { + NSDate *theDate = [self getDate]; + if(!theDate) { + [self followup]; + } +} + +-(id)initWithDefaults:(NSUserDefaults*) defaults dateDescription:(NSString *)dateDescription earliest:(NSTimeInterval) earliest latest: (NSTimeInterval) latest { + if(!self) return nil; + _defaults = defaults; + if(! _defaults) { + _defaults = [[NSUserDefaults alloc] init]; + } + _dateDescription = dateDescription; + _earliestDate = earliest; + _latestDate = latest; + [self schedule]; + return self; +} + +@end + diff --git a/keychain/SecureObjectSync/SOSMessage.c b/keychain/SecureObjectSync/SOSMessage.c index cc9cfe13..97ab42db 100644 --- a/keychain/SecureObjectSync/SOSMessage.c +++ b/keychain/SecureObjectSync/SOSMessage.c @@ -48,7 +48,7 @@ // TODO: This is a layer violation, we need a better way to do this // Currently it's only used for logging. -#include +#include "keychain/securityd/SecItemDataSource.h" #if defined(SOSMessageFormatSpecification) && 0 @@ -211,29 +211,6 @@ parameters ANY DEFINED BY algorithm OPTIONAL } #endif // defined(SOSMessageFormatSpecification) && 0 -#if 0 -static inline bool SecMallocOk(const void *ptr) { - if (ptr) return true; - - return false; -} -#endif -#if 0 -static void appendObjects(CFMutableStringRef desc, CFArrayRef objects) { - __block bool needComma = false; - CFArrayForEach(objects, ^(const void *value) { - if (needComma) - CFStringAppend(desc, CFSTR(",")); - else - needComma = true; - - SecItemServerAppendItemDescription(desc, value); - }); -} -#endif - - - // // MARK: SOSMessage implementation. // @@ -300,7 +277,7 @@ static void SOSMessageDestroy(CFTypeRef cf) { } // TODO: Remove this layer violation! -#include +#include "keychain/securityd/SecItemServer.h" static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error); @@ -975,22 +952,6 @@ static const uint8_t *der_decode_optional_objects(SOSMessageRef message, CFError return seq_end ? seq_end : der; } -#if 0 -// Move to ccder and possibly refactor ccder_decode_constructed_tl to call this. -#ifdef CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -#endif -inline CC_NONNULL((1, 3)) -const uint8_t * -ccder_decode_constructed_len(const uint8_t **body_end, - const uint8_t *der, const uint8_t *der_end) { - size_t len; - der = ccder_decode_len(&len, der, der_end); - *body_end = der + len; - return der; -} -#endif - static const uint8_t *der_decode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { cc_unit flags[1] = {}; der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end); diff --git a/keychain/SecureObjectSync/SOSPeer.m b/keychain/SecureObjectSync/SOSPeer.m index 6b35c782..495c561c 100644 --- a/keychain/SecureObjectSync/SOSPeer.m +++ b/keychain/SecureObjectSync/SOSPeer.m @@ -44,7 +44,7 @@ #include "keychain/SecureObjectSync/SOSBackupEvent.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include @@ -53,7 +53,7 @@ #include // Backup Peer Support -#include +#include "keychain/securityd/SecKeybagSupport.h" #include diff --git a/keychain/SecureObjectSync/SOSPiggyback.m b/keychain/SecureObjectSync/SOSPiggyback.m index 5193395e..0234388f 100644 --- a/keychain/SecureObjectSync/SOSPiggyback.m +++ b/keychain/SecureObjectSync/SOSPiggyback.m @@ -29,7 +29,7 @@ #include #include -#include +#include "keychain/securityd/SecItemSchema.h" #include #include @@ -336,7 +336,7 @@ SOSPiggyCopyInitialSyncData(const uint8_t** der, const uint8_t *der_end) /* Don't check length here so we can add more data */ - if(results.count == 0 || tlks.count == 0){ + if(results.count == 0){ secnotice("piggy","NO DATA, falling back to waiting 5 minutes for initial sync to finish"); results = NULL; } @@ -369,11 +369,13 @@ SOSPiggyBackBlobCreateFromDER(SOSGenCountRef *retGencount, *der_p = der_decode_data_or_null(kCFAllocatorDefault, &publicBytes, error, *der_p, sequence_end); *der_p = der_decode_data_or_null(kCFAllocatorDefault, &signature, error, *der_p, sequence_end); - if(version == kPiggyV1){ + if(version != kPiggyV0 && *der_p != der_end) { NSDictionary* initialSyncDict = SOSPiggyCopyInitialSyncData(der_p, der_end); if (initialSyncDict) { NSArray* idents = initialSyncDict[@"idents"]; NSArray* tlks = initialSyncDict[@"tlks"]; + secnotice("piggy", "Piggybacking include identities(%d) and tlks(%d)", + (int)idents.count, (int)tlks.count); SOSPiggyBackAddToKeychain(idents, tlks); *setInitialSyncTimeoutToV0 = false; } diff --git a/keychain/SecureObjectSync/SOSRingUtils.h b/keychain/SecureObjectSync/SOSRingUtils.h index 64201e52..7fe9a6b4 100644 --- a/keychain/SecureObjectSync/SOSRingUtils.h +++ b/keychain/SecureObjectSync/SOSRingUtils.h @@ -135,19 +135,4 @@ SOSRingRef SOSRingCreateFromDER(CFErrorRef* error, const uint8_t** der_p, const CFDictionaryRef SOSRingCreateRetirementTicket(SOSFullPeerInfoRef fpi, CFErrorRef *error); -#if 0 -int SOSRingCountActivePeers(SOSCircleRef circle, SOSRingRef ring); -int SOSRingCountActiveValidPeers(SOSCircleRef circle, SOSRingRef ring, SecKeyRef pubkey); -int SOSRingCountRetiredPeers(SOSCircleRef circle, SOSRingRef ring); -void SOSRingForEachPeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachRetiredPeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachActivePeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachActiveValidPeer(SOSCircleRef circle, SOSRingRef ring, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)); -SOSPeerInfoRef SOSRingCopyPeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, CFErrorRef *error); -bool SOSRingHasActivePeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, CFErrorRef *error); -bool SOSRingHasActiveValidPeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error); -void SOSRingForEachApplicant(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -bool SOSRingResetToOffering_Internal(SOSCircleRef circle, SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error); -#endif - #endif /* defined(_sec_SOSRingUtils_) */ diff --git a/keychain/SecureObjectSync/SOSTransportKeyParameter.m b/keychain/SecureObjectSync/SOSTransportKeyParameter.m index 784d6a55..84b1bf27 100644 --- a/keychain/SecureObjectSync/SOSTransportKeyParameter.m +++ b/keychain/SecureObjectSync/SOSTransportKeyParameter.m @@ -2,7 +2,7 @@ #include "keychain/SecureObjectSync/SOSTransport.h" #include "keychain/SecureObjectSync/SOSTransportKeyParameter.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/SOSAccountPriv.h" #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/SOSTransportMessage.m b/keychain/SecureObjectSync/SOSTransportMessage.m index 6b0f0482..407c5543 100644 --- a/keychain/SecureObjectSync/SOSTransportMessage.m +++ b/keychain/SecureObjectSync/SOSTransportMessage.m @@ -12,7 +12,7 @@ #include "keychain/SecureObjectSync/SOSInternal.h" #include "keychain/SecureObjectSync/SOSAccountPriv.h" #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" -#include // TODO: Remove this layer violation. +#include "keychain/securityd/SecItemServer.h" // TODO: Remove this layer violation. static const CFStringRef kSecSOSMessageRTT = CFSTR("com.apple.security.sos.messagertt"); static const CFStringRef kSecAccessGroupSecureBackupd = CFSTR("com.apple.securebackupd"); diff --git a/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m b/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m index 96b421a1..9cdf7d3a 100644 --- a/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m +++ b/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m @@ -39,7 +39,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/Tool/keychain_log.m b/keychain/SecureObjectSync/Tool/keychain_log.m index ee601a3e..fd004c9b 100644 --- a/keychain/SecureObjectSync/Tool/keychain_log.m +++ b/keychain/SecureObjectSync/Tool/keychain_log.m @@ -54,7 +54,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/Tool/keychain_sync.m b/keychain/SecureObjectSync/Tool/keychain_sync.m index f5172661..4d17e4e5 100644 --- a/keychain/SecureObjectSync/Tool/keychain_sync.m +++ b/keychain/SecureObjectSync/Tool/keychain_sync.m @@ -46,7 +46,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m index 235da5d3..00fe0159 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m @@ -29,30 +29,29 @@ } - (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError *))complete { - NSError *error = nil; - OTControl* rpc = [OTControl controlObject:true error:&error]; - if (rpc == nil) { - complete(@NO, error); + [self.remoteDevice otReset:altDSID complete:^(bool success, NSError * _Nullable error) { + complete([NSNumber numberWithBool:success], error); + }]; +} - return; - } +- (void)octagonPeerID:(NSString *)altDSID complete:(void (^)(NSString *, NSError *))complete { - [rpc resetAndEstablish:NULL context:OTDefaultContext altDSID:altDSID reply:^(NSError * _Nullable e) { - complete([NSNumber numberWithBool:e != NULL], e); + [self.remoteDevice otPeerID:altDSID complete:^(NSString *peerID, NSError * _Nullable error) { + complete(peerID, error); }]; } -/* Oh, ObjC, you are my friend */ -- (void)forwardInvocation:(NSInvocation *)invocation { - struct objc_method_description desc = protocol_getMethodDescription(@protocol(SecRemoteDeviceProtocol), [invocation selector], true, true); - if (desc.name == NULL) { - [super forwardInvocation:invocation]; - } else { - [invocation invokeWithTarget:self.remoteDevice]; - } +- (void)octagonInCircle:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError *_Nullable error))complete +{ + [self.remoteDevice otInCircle:altDSID complete:^(bool inCircle, NSError * _Nullable error) { + complete(@(inCircle), error); + }]; } + + + @end #pragma clang diagnostic pop diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m index d35615a5..c6404265 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m @@ -24,7 +24,7 @@ #import #import -#import +#import "keychain/securityd/SOSCloudCircleServer.h" #import #import #import @@ -428,7 +428,7 @@ #if OCTAGON OTControl *ot = [self OTControl]; - [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID reply:^(NSError * _Nullable error) { + [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID resetReason:CuttlefishResetReasonTestGenerated reply:^(NSError * _Nullable error) { complete(error == NULL, error); }]; #else diff --git a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h index 1cce9364..af5f2089 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h +++ b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h @@ -2,9 +2,15 @@ #import +NS_ASSUME_NONNULL_BEGIN + @protocol OctagonTestHarnessXPCServiceProtocol // Trieste-compliant Octagon reset -- (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *reset, NSError *error))complete; +- (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError * _Nullable))complete; +- (void)octagonPeerID:(NSString *)altDSID complete:(void (^)(NSString *, NSError *_Nullable))complete; +- (void)octagonInCircle:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError * _Nullable))complete; @end + +NS_ASSUME_NONNULL_END diff --git a/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift b/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift index 7308bfd6..04bb5f27 100644 --- a/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift +++ b/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift @@ -65,7 +65,6 @@ class EscrowKeys: NSObject { class func generateEscrowKey(keyType: escrowKeyType, masterSecret: Data, bottleSalt: String) throws -> (Data) { var keyLength: Int var info: Data - var infoLength: Int var derivedKey: Data var finalKey = Data() @@ -75,7 +74,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Symmetric Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case escrowKeyType.kOTEscrowKeyEncryption: @@ -83,7 +81,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Encryption Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case escrowKeyType.kOTEscrowKeySigning: @@ -91,7 +88,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Signing Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break } @@ -107,30 +103,28 @@ class EscrowKeys: NSObject { derivedKey = Data(count: keyLength) var masterSecretMutable = masterSecret - let masterSecretLength = masterSecret.count - let derivedKeySize = derivedKey.count let bottleSaltData = Data(bytes: Array(bottleSalt.utf8), count: bottleSalt.utf8.count) - try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutablePointer) throws ->Void in - try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutablePointer) throws ->Void in - try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafePointer) throws -> Void in - try info.withUnsafeBytes { (infoBytes: UnsafePointer) throws -> Void in + try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutableRawBufferPointer) throws -> Void in + try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutableRawBufferPointer) throws -> Void in + try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafeRawBufferPointer) throws -> Void in + try info.withUnsafeBytes { (infoBytes: UnsafeRawBufferPointer) throws -> Void in status = cchkdf(ccsha384_di(), - masterSecretLength, masterSecretBytes, - bottleSaltData.count, bottleSaltBytes, - infoLength, infoBytes, - keyLength, derivedKeyBytes) + masterSecretBytes.count, masterSecretBytes.baseAddress!, + bottleSaltBytes.count, bottleSaltBytes.baseAddress!, + infoBytes.count, infoBytes.baseAddress!, + derivedKeyBytes.count, derivedKeyBytes.baseAddress!) if status != 0 { throw EscrowKeysError.corecryptoKeyGeneration(corecryptoError: status) } if(keyType == escrowKeyType.kOTEscrowKeySymmetric) { - finalKey = Data(buffer: UnsafeBufferPointer(start: derivedKeyBytes, count: derivedKeySize)) + finalKey = Data(buffer: derivedKeyBytes.bindMemory(to: UInt8.self)) return } else if(keyType == escrowKeyType.kOTEscrowKeyEncryption || keyType == escrowKeyType.kOTEscrowKeySigning) { status = ccec_generate_key_deterministic(cp, - derivedKeySize, derivedKeyBytes, + derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!, ccDRBGGetRngState(), UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS), fullKey) @@ -141,8 +135,8 @@ class EscrowKeys: NSObject { let space = ccec_x963_export_size(1, ccec_ctx_pub(fullKey)) var key = Data(count: space) - key.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - ccec_x963_export(1, bytes, fullKey) + key.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) -> Void in + ccec_x963_export(1, bytes.baseAddress!, fullKey) } finalKey = Data(key) } @@ -192,11 +186,10 @@ class EscrowKeys: NSObject { let di = ccsha384_di() var result = Data(count: TPHObjectiveC.ccsha384_diSize()) - let derivedKeySize = keyData.count var keyDataMutable = keyData - result.withUnsafeMutableBytes {(resultBytes: UnsafeMutablePointer) -> Void in - keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutablePointer) -> Void in - ccdigest(di, derivedKeySize, keyDataBytes, resultBytes) + result.withUnsafeMutableBytes {(resultBytes: UnsafeMutableRawBufferPointer) -> Void in + keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutableRawBufferPointer) -> Void in + ccdigest(di, keyDataBytes.count, keyDataBytes.baseAddress!, resultBytes.baseAddress!) } } let hash = result.base64EncodedString(options: []) @@ -211,7 +204,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrLabel: label, kSecAttrApplicationLabel: String(format: "Escrowed Encryption Key-%@", NSUUID().uuidString), kSecValueData: keyData, @@ -225,7 +218,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Escrowed Signing Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -239,7 +232,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Escrowed Symmetric Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -256,7 +249,7 @@ class EscrowKeys: NSObject { kSecAttrLabel: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitAll, ] @@ -368,14 +361,12 @@ extension EscrowKeysError: CustomNSError { } switch self { case .failedToSaveToKeychain(errorCode: let osError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) case .corecryptoKeyGeneration(corecryptoError: let corecryptoError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) default: break } return userInfo } } - - diff --git a/keychain/TrustedPeersHelper/Client.swift b/keychain/TrustedPeersHelper/Client.swift index fc8327ac..a7c5f127 100644 --- a/keychain/TrustedPeersHelper/Client.swift +++ b/keychain/TrustedPeersHelper/Client.swift @@ -89,7 +89,7 @@ class Client: TrustedPeersHelperProtocol { container.trustStatus(reply: reply) } catch { os_log("Trust status failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) - reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: TPPeerStatus.unknown, peerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error)) + reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: TPPeerStatus.unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error)) } } @@ -105,12 +105,12 @@ class Client: TrustedPeersHelperProtocol { } } - func reset(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) { + func reset(withContainer container: String, context: String, resetReason: CuttlefishResetReason, reply: @escaping (Error?) -> Void) { do { let containerName = ContainerName(container: container, context: context) os_log("Resetting for %@", log: tplogDebug, type: .default, containerName.description) let container = try self.containerMap.findOrCreate(name: containerName) - container.reset { error in + container.reset(resetReason: resetReason) { error in self.logComplete(function: "Resetting", container: container.name, error: error) reply(CKXPCSuitableError(error)) } } catch { @@ -290,6 +290,23 @@ class Client: TrustedPeersHelperProtocol { } } + func preflightVouchWithBottle(withContainer container: String, + context: String, + bottleID: String, + reply: @escaping (String?, Error?) -> Void) { + do { + let containerName = ContainerName(container: container, context: context) + os_log("Preflight Vouch With Bottle %@", log: tplogDebug, type: .default, containerName.description) + let container = try self.containerMap.findOrCreate(name: containerName) + container.preflightVouchWithBottle(bottleID: bottleID) { peerID, error in + self.logComplete(function: "Preflight Vouch With Bottle", container: container.name, error: error) + reply(peerID, CKXPCSuitableError(error)) } + } catch { + os_log("Preflighting Vouch With Bottle failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) + reply(nil, CKXPCSuitableError(error)) + } + } + func vouchWithBottle(withContainer container: String, context: String, bottleID: String, @@ -358,7 +375,7 @@ class Client: TrustedPeersHelperProtocol { let containerName = ContainerName(container: container, context: context) os_log("Attempting to preflight a preapproved join for %@", log: tplogDebug, type: .default, containerName.description) let container = try self.containerMap.findOrCreate(name: containerName) - container.preflightPreapprovedJoin() { success, error in reply(success, CKXPCSuitableError(error)) } + container.preflightPreapprovedJoin { success, error in reply(success, CKXPCSuitableError(error)) } } catch { reply(false, CKXPCSuitableError(error)) } diff --git a/keychain/TrustedPeersHelper/Container.swift b/keychain/TrustedPeersHelper/Container.swift index 271e6c1a..c64e51b8 100644 --- a/keychain/TrustedPeersHelper/Container.swift +++ b/keychain/TrustedPeersHelper/Container.swift @@ -33,6 +33,29 @@ let tplogTrace = OSLog(subsystem: "com.apple.security.trustedpeers", category: " let egoIdentitiesAccessGroup = "com.apple.security.egoIdentities" +extension ResetReason { + static func from(cuttlefishResetReason: CuttlefishResetReason) -> ResetReason { + switch cuttlefishResetReason { + case .unknown: + return ResetReason.unknown + case .userInitiatedReset: + return ResetReason.userInitiatedReset + case .healthCheck: + return ResetReason.healthCheck + case .noBottleDuringEscrowRecovery: + return ResetReason.noBottleDuringEscrowRecovery + case .legacyJoinCircle: + return ResetReason.legacyJoinCircle + case .recoveryKey: + return ResetReason.recoveryKey + case .testGenerated: + return ResetReason.testGenerated + @unknown default: + fatalError() + } + } +} + public enum ContainerError: Error { case unableToCreateKeyPair case noPreparedIdentity @@ -74,6 +97,7 @@ public enum ContainerError: Error { case failedToAssembleBottle case invalidPeerID case failedToStoreSecret(errorCode: Int) + case unknownSecurityFoundationError } extension ContainerError: LocalizedError { @@ -159,6 +183,8 @@ extension ContainerError: LocalizedError { return "peerID is invalid" case .failedToStoreSecret(errorCode: let errorCode): return "failed to store the secret in the keychain \(errorCode)" + case .unknownSecurityFoundationError: + return "SecurityFoundation returned an unknown type" } } } @@ -253,6 +279,8 @@ extension ContainerError: CustomNSError { return 41 case .invalidPeerID: return 42 + case .unknownSecurityFoundationError: + return 43 } } @@ -294,7 +322,7 @@ func saveSecret(_ secret: Data, label: String) throws { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrDescription: label, kSecAttrPath: label, kSecValueData: secret, @@ -315,7 +343,7 @@ func saveSecret(_ secret: Data, label: String) throws { findQuery[kSecAttrAccessGroup] = query[kSecAttrAccessGroup] findQuery[kSecAttrServer] = query[kSecAttrDescription] findQuery[kSecAttrPath] = query[kSecAttrPath] - findQuery[kSecUseDataProtectionKeychain] = query[kSecUseDataProtectionKeychain]; + findQuery[kSecUseDataProtectionKeychain] = query[kSecUseDataProtectionKeychain] var updateQuery: [CFString: Any] = query updateQuery[kSecClass] = nil @@ -339,7 +367,7 @@ func loadSecret(label: String) throws -> (Data?) { kSecAttrDescription: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitOne, ] @@ -385,6 +413,8 @@ func loadEgoKeyPair(identifier: String, resultHandler: @escaping (_SFECKeyPair?, resultHandler(nil, ContainerError.needsAuthentication) case .error: resultHandler(nil, result.error) + @unknown default: + resultHandler(nil, ContainerError.unknownSecurityFoundationError) } } } @@ -419,7 +449,7 @@ func removeEgoKeysSync(peerID: String) throws -> Bool { let keychainManager = _SFKeychainManager.default() var retresultForSigningDeletion: Bool = false - var reterrorForSigningDeletion: Error? = nil + var reterrorForSigningDeletion: Error? //remove signing keys keychainManager.removeItem(withIdentifier: signingKeyIdentifier(peerID: peerID)) { result, error in @@ -441,7 +471,7 @@ func removeEgoKeysSync(peerID: String) throws -> Bool { // now let's do the same thing with the encryption keys resultSema = DispatchSemaphore(value: 0) var retresultForEncryptionDeletion: Bool = false - var reterrorForEncryptionDeletion: Error? = nil + var reterrorForEncryptionDeletion: Error? keychainManager.removeItem(withIdentifier: encryptionKeyIdentifier(peerID: peerID)) { result, error in retresultForEncryptionDeletion = result @@ -818,7 +848,7 @@ class Container: NSObject { } func onQueueDetermineLocalTrustStatus(reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) { - let peerCountsByModelID = self.model.peerCountsByModelID() + let viablePeerCountsByModelID = self.model.viablePeerCountsByModelID() if let egoPeerID = self.containerMO.egoPeerID { var status = self.model.statusOfPeer(withID: egoPeerID) @@ -844,7 +874,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: isExcluded, isLocked: isLocked) reply(egoStatus, returnError) @@ -856,7 +886,7 @@ class Container: NSObject { os_log("trust status: No error but Ego Peer Keys are nil", log: tplogDebug, type: .default) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: .excluded, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: true, isLocked: false) @@ -866,7 +896,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: isExcluded, isLocked: false) reply(egoStatus, nil) @@ -879,7 +909,7 @@ class Container: NSObject { os_log("No existing peers in account", log: tplogDebug, type: .debug) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: false, isLocked: false) reply(egoStatus, nil) @@ -888,7 +918,7 @@ class Container: NSObject { os_log("Existing peers in account, but we don't have a peer ID. We are excluded.", log: tplogDebug, type: .debug) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .excluded, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: true, isLocked: false) reply(egoStatus, nil) @@ -919,7 +949,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, - peerCountsByModelID: [:], + viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false) reply(egoStatus, fetchError) @@ -955,14 +985,17 @@ class Container: NSObject { return } - let isPreapproved = self.model.hasPeerPreapprovingKey(permanentInfo.signingPubKey.spki()) + let isPreapproved = self.model.hasPotentiallyTrustedPeerPreapprovingKey(permanentInfo.signingPubKey.spki()) os_log("fetchTrustState: ego peer is %@", log: tplogDebug, type: .default, isPreapproved ? "preapproved" : "not yet preapproved") + let egoStableInfo = self.model.getStableInfoForPeer(withID: egoPeerID) + let egoPeerStatus = TrustedPeersHelperPeerState(peerID: egoPeerID, isPreapproved: isPreapproved, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: false, - unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful()) + unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful(), + osVersion: egoStableInfo?.osVersion) var tphPeers: [TrustedPeersHelperPeer] = [] @@ -990,7 +1023,7 @@ class Container: NSObject { } else { // With no ego peer ID, there are no trusted peers os_log("No peer ID => no trusted peers", log: tplogDebug, type: .debug) - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: false, unknownMachineIDs: false), [], nil) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: false, unknownMachineIDs: false, osVersion: nil), [], nil) } } } @@ -1029,6 +1062,8 @@ class Container: NSObject { let midList = self.onqueueCurrentMIDList() d["machineIDsAllowed"] = midList.machineIDs(in: .allowed).sorted() d["machineIDsDisallowed"] = midList.machineIDs(in: .disallowed).sorted() + d["modelRecoverySigningPublicKey"] = self.model.recoverySigningPublicKey() + d["modelRecoveryEncryptionPublicKey"] = self.model.recoveryEncryptionPublicKey() reply(d, nil) } @@ -1117,7 +1152,7 @@ class Container: NSObject { } } - func reset(reply: @escaping (Error?) -> Void) { + func reset(resetReason: CuttlefishResetReason, reply: @escaping (Error?) -> Void) { self.semaphore.wait() let reply: (Error?) -> Void = { os_log("reset complete %@", log: tplogTrace, type: .info, traceError($0)) @@ -1126,7 +1161,10 @@ class Container: NSObject { } self.moc.performAndWait { - let request = ResetRequest() + let resetReason = ResetReason.from(cuttlefishResetReason: resetReason) + let request = ResetRequest.with { + $0.resetReason = resetReason + } self.cuttlefish.reset(request) { response, error in os_log("Reset(%@): %@, error: %@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))") guard let response = response, error == nil else { @@ -1345,7 +1383,7 @@ class Container: NSObject { } } - func onqueueTTRUntrusted() -> Void { + func onqueueTTRUntrusted() { let ttr = SecTapToRadar(tapToRadar: "Device not IDMS trusted", description: "Device not IDMS trusted", radar: "52874119") @@ -1487,7 +1525,7 @@ class Container: NSObject { // This is an odd error condition: we might be able to fetch again and be in a good state... os_log("fetch-after-establish failed: %@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "no error") reply(nil, keyHierarchyRecords, fetchError) - return; + return } os_log("fetch-after-establish succeeded", log: tplogDebug, type: .default) @@ -1646,7 +1684,7 @@ class Container: NSObject { return !bmos.isEmpty } - func findBottleForEscrowRecordID(bottleID: String, reply: @escaping (BottleMO?, Error?) -> Void) { + func onqueueFindBottle(bottleID: String, reply: @escaping (BottleMO?, Error?) -> Void) { var bmo: BottleMO? var bottles: Set = [] @@ -1681,7 +1719,7 @@ class Container: NSObject { return } - os_log("findBottleForEscrowRecordID found bottle: %@", log: tplogDebug, type: .default, newBottles) + os_log("onqueueFindBottle found bottle: %@", log: tplogDebug, type: .default, newBottles) bottles = newBottles.filter { $0.bottleID == bottleID @@ -1760,6 +1798,29 @@ class Container: NSObject { } } + func preflightVouchWithBottle(bottleID: String, + reply: @escaping (String?, Error?) -> Void) { + self.semaphore.wait() + let reply: (String?, Error?) -> Void = { + os_log("preflightVouchWithBottle complete: %@", + log: tplogTrace, type: .info, traceError($1)) + self.semaphore.signal() + reply($0, $1) + } + + self.moc.performAndWait { + self.onqueueFindBottle(bottleID: bottleID) { bottleMO, error in + guard let bottleMO = bottleMO else { + os_log("preflightVouchWithBottle found no bottle: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "") + reply(nil, error) + return + } + + reply(bottleMO.peerID, nil) + } + } + } + func vouchWithBottle(bottleID: String, entropy: Data, bottleSalt: String, @@ -1780,7 +1841,7 @@ class Container: NSObject { return } - self.findBottleForEscrowRecordID(bottleID: bottleID) { returnedBMO, error in + self.onqueueFindBottle(bottleID: bottleID) { returnedBMO, error in self.moc.performAndWait { guard error == nil else { os_log("vouchWithBottle unable to find bottle for escrow record id: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "") @@ -2248,13 +2309,13 @@ class Container: NSObject { self.moc.performAndWait { guard let egoPeerID = self.containerMO.egoPeerID else { os_log("fetchEscrowContents failed", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.noPreparedIdentity) + reply(nil, nil, nil, ContainerError.noPreparedIdentity) return } guard let bottles = self.containerMO.bottles as? Set else { os_log("fetchEscrowContents failed", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.noBottleForPeer) + reply(nil, nil, nil, ContainerError.noBottleForPeer) return } @@ -2266,19 +2327,19 @@ class Container: NSObject { do { guard let loaded = try loadSecret(label: egoPeerID) else { os_log("fetchEscrowContents failed to load entropy", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.failedToFetchEscrowContents) + reply(nil, nil, nil, ContainerError.failedToFetchEscrowContents) return } entropy = loaded } catch { os_log("fetchEscrowContents failed to load entropy: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error") - reply (nil, nil, nil, error) + reply(nil, nil, nil, error) return } guard let signingPublicKey = bmo.escrowedSigningSPKI else { os_log("fetchEscrowContents no escrow signing spki", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.bottleDoesNotContainerEscrowKeySPKI) + reply(nil, nil, nil, ContainerError.bottleDoesNotContainerEscrowKeySPKI) return } reply(entropy, bottleID, signingPublicKey, nil) @@ -2321,12 +2382,12 @@ class Container: NSObject { func fetchViableBottlesWithSemaphore(reply: @escaping ([String]?, [String]?, Error?) -> Void) { os_log("beginning a fetchViableBottles", log: tplogDebug, type: .default) - let cachedBottles:TPCachedViableBottles = self.model.currentCachedViableBottlesSet() + let cachedBottles: TPCachedViableBottles = self.model.currentCachedViableBottlesSet() self.moc.performAndWait { if self.onqueueCachedBottlesContainEgoPeerBottle(cachedBottles: cachedBottles) && (cachedBottles.viableBottles.count > 0 || cachedBottles.partialBottles.count > 0) { os_log("returning from fetchViableBottles, using cached bottles", log: tplogDebug, type: .default) - reply (cachedBottles.viableBottles, cachedBottles.partialBottles, nil) + reply(cachedBottles.viableBottles, cachedBottles.partialBottles, nil) return } @@ -2423,7 +2484,7 @@ class Container: NSObject { do { try self.moc.save() os_log("fetchViableBottles saved bottles", log: tplogDebug, type: .default) - let cached = TPCachedViableBottles.init(viableBottles: viableBottleIDs, partialBottles: partialBottleIDs) + let cached = TPCachedViableBottles(viableBottles: viableBottleIDs, partialBottles: partialBottleIDs) self.model.setViableBottles(cached) reply(viableBottleIDs, partialBottleIDs, nil) } catch { @@ -2973,7 +3034,7 @@ class Container: NSObject { return } - guard self.model.hasPeerPreapprovingKey(egoPermanentInfo.signingPubKey.spki()) else { + guard self.model.hasPotentiallyTrustedPeerPreapprovingKey(egoPermanentInfo.signingPubKey.spki()) else { os_log("preflightPreapprovedJoin: no peers preapprove our key", log: tplogDebug, type: .debug) reply(false, ContainerError.noPeersPreapprovePreparedIdentity) return @@ -3048,7 +3109,7 @@ class Container: NSObject { return } - guard self.model.hasPeerPreapprovingKey(egoPeerKeys.signingKey.publicKey().spki()) else { + guard self.model.hasPotentiallyTrustedPeerPreapprovingKey(egoPeerKeys.signingKey.publicKey().spki()) else { os_log("preapprovedJoin: no peers preapprove our key", log: tplogDebug, type: .debug) reply(nil, [], ContainerError.noPeersPreapprovePreparedIdentity) return @@ -3464,6 +3525,7 @@ class Container: NSObject { if let error = error { os_log("fetchChangesAndUpdateTrustIfNeeded: fetching failed: %@", log: tplogDebug, type: .default, error as CVarArg) reply(nil, error) + return } self.updateTrustIfNeeded(stableChanges: stableChanges, changesPending: changesPending, reply: reply) @@ -3486,24 +3548,25 @@ class Container: NSObject { guard let egoPeerID = self.containerMO.egoPeerID else { // No identity, nothing to do os_log("updateTrustIfNeeded: No identity.", log: tplogDebug, type: .default) - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false), nil) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false, osVersion: nil), nil) return } loadEgoKeyPair(identifier: signingKeyIdentifier(peerID: egoPeerID)) { signingKeyPair, error in guard let signingKeyPair = signingKeyPair else { os_log("updateTrustIfNeeded: no signing key pair: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error") - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false), error) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false, osVersion: nil), error) return } guard self.model.hasPeer(withID: egoPeerID) else { // Not in circle, nothing to do - let isPreapproved = self.model.hasPeerPreapprovingKey(signingKeyPair.publicKey().spki()) + let isPreapproved = self.model.hasPotentiallyTrustedPeerPreapprovingKey(signingKeyPair.publicKey().spki()) os_log("updateTrustIfNeeded: ego peer is not in model, is %@", log: tplogDebug, type: .default, isPreapproved ? "preapproved" : "not yet preapproved") reply(TrustedPeersHelperPeerState(peerID: egoPeerID, isPreapproved: isPreapproved, status: .unknown, memberChanges: changesPending, - unknownMachineIDs: false), + unknownMachineIDs: false, + osVersion: nil), nil) return } @@ -3531,7 +3594,8 @@ class Container: NSObject { isPreapproved: false, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: changesPending, - unknownMachineIDs: false), + unknownMachineIDs: false, + osVersion: nil), error) return } @@ -3555,7 +3619,8 @@ class Container: NSObject { isPreapproved: false, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: changesPending, - unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful()), + unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful(), + osVersion: peer?.stableInfo?.osVersion), nil) return } @@ -3603,7 +3668,6 @@ class Container: NSObject { } } - private func persist(changes: Changes) throws { // This is some nonsense: I can't figure out how to tell swift to throw an exception across performAndWait. // So, do it ourself @@ -3636,7 +3700,7 @@ class Container: NSObject { if changes.differences.count > 0 { self.model.clearViableBottles() } - + try changes.differences.forEach { peerDifference in if let operation = peerDifference.operation { switch operation { @@ -3647,7 +3711,7 @@ class Container: NSObject { try self.addOrUpdate(peer: peer) // Update containerMO ego data if it has changed. if peer.peerID == self.containerMO.egoPeerID { - guard let stableInfoAndSig:TPPeerStableInfo = peer.stableInfoAndSig.toStableInfo() else { + guard let stableInfoAndSig: TPPeerStableInfo = peer.stableInfoAndSig.toStableInfo() else { break } self.containerMO.egoPeerStableInfo = stableInfoAndSig.data @@ -3913,7 +3977,7 @@ class Container: NSObject { } self.moc.performAndWait { - self.cuttlefish.pushHealthInquiry(HealthInquiryRequest()) { response, error in + self.cuttlefish.pushHealthInquiry(PushHealthInquiryRequest()) { response, error in os_log("pushHealthInquiry(): %@, error: %@", log: tplogDebug, "\(String(describing: response))", "\(String(describing: error))") guard error == nil else { reply(error) diff --git a/keychain/TrustedPeersHelper/ContainerMap.swift b/keychain/TrustedPeersHelper/ContainerMap.swift index 83cfbbb3..59f539dc 100644 --- a/keychain/TrustedPeersHelper/ContainerMap.swift +++ b/keychain/TrustedPeersHelper/ContainerMap.swift @@ -32,6 +32,50 @@ import Foundation let CuttlefishPushTopicBundleIdentifier = "com.apple.security.cuttlefish" +struct CKInternalErrorMatcher { + let code: Int + let internalCode: Int +} + +// Match a CKError/CKInternalError +func ~= (pattern: CKInternalErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + guard let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError else { + return false + } + return error.domain == CKErrorDomain && error.code == pattern.code && + underlyingError.domain == CKInternalErrorDomain && underlyingError.code == pattern.internalCode +} + +struct CKErrorMatcher { + let code: Int +} + +// Match a CKError +func ~= (pattern: CKErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + return error.domain == CKErrorDomain && error.code == pattern.code +} + +struct NSURLErrorMatcher { + let code: Int +} + +// Match an NSURLError +func ~= (pattern: NSURLErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + return error.domain == NSURLErrorDomain && error.code == pattern.code +} + public class RetryingInvocable: CloudKitCode.Invocable { private let underlyingInvocable: CloudKitCode.Invocable @@ -39,14 +83,18 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.underlyingInvocable = retry } - private func retryableError(error: Error?) -> Bool { + public class func retryableError(error: Error?) -> Bool { switch error { - case let error as NSError where error.domain == NSURLErrorDomain && error.code == NSURLErrorTimedOut: + case NSURLErrorMatcher(code: NSURLErrorTimedOut): + return true + case CKErrorMatcher(code: CKError.networkFailure.rawValue): return true - case let error as NSError where error.domain == CKErrorDomain && error.code == CKError.networkFailure.rawValue: + case CKInternalErrorMatcher(code: CKError.serverRejectedRequest.rawValue, internalCode: CKInternalErrorCode.errorInternalServerInternalError.rawValue): return true case CuttlefishErrorMatcher(code: CuttlefishErrorCode.retryableServerFailure): return true + case CuttlefishErrorMatcher(code: CuttlefishErrorCode.transactionalFailure): + return true default: return false } @@ -54,7 +102,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { public func invoke(function: String, request: RequestType, - completion: @escaping (ResponseType?, Error?) -> Void) where RequestType : Message, ResponseType : Message { + completion: @escaping (ResponseType?, Error?) -> Void) where RequestType: Message, ResponseType: Message { let now = Date() let deadline = Date(timeInterval: 30, since: now) let delay = TimeInterval(5) @@ -62,7 +110,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.invokeRetry(function: function, request: request, deadline: deadline, - delay: delay, + minimumDelay: delay, completion: completion) } @@ -70,14 +118,20 @@ public class RetryingInvocable: CloudKitCode.Invocable { function: String, request: RequestType, deadline: Date, - delay: TimeInterval, + minimumDelay: TimeInterval, completion: @escaping (ResponseType?, Error?) -> Void) { self.underlyingInvocable.invoke(function: function, request: request) { (response: ResponseType?, error: Error?) in - if self.retryableError(error: error) { + if let error = error, RetryingInvocable.retryableError(error: error) { let now = Date() + + // Check cuttlefish and CKError retry afters. + let cuttlefishDelay = CuttlefishRetryAfter(error: error) + let ckDelay = CKRetryAfterSecondsForError(error) + let delay = max(minimumDelay, cuttlefishDelay, ckDelay) let cutoff = Date(timeInterval: delay, since: now) + guard cutoff.compare(deadline) == ComparisonResult.orderedDescending else { Thread.sleep(forTimeInterval: delay) os_log("%{public}@ error: %{public}@ (retrying, now=%{public}@, deadline=%{public}@)", log: tplogDebug, @@ -88,7 +142,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.invokeRetry(function: function, request: request, deadline: deadline, - delay: delay, + minimumDelay: minimumDelay, completion: completion) return } diff --git a/keychain/TrustedPeersHelper/Container_MachineIDs.swift b/keychain/TrustedPeersHelper/Container_MachineIDs.swift index 7c015f98..0e5f5c8c 100644 --- a/keychain/TrustedPeersHelper/Container_MachineIDs.swift +++ b/keychain/TrustedPeersHelper/Container_MachineIDs.swift @@ -1,4 +1,3 @@ - import CoreData import Foundation @@ -8,7 +7,7 @@ extension MachineMO { return false } - let dateLimit = Date(timeIntervalSinceNow: -60*60*TimeInterval(hours)) + let dateLimit = Date(timeIntervalSinceNow: -60 * 60 * TimeInterval(hours)) return modifiedDate.compare(dateLimit) == ComparisonResult.orderedDescending } @@ -89,8 +88,7 @@ extension Container { var differences = false var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) - + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) knownMachines.forEach { machine in guard let mid = machine.machineID else { @@ -162,21 +160,26 @@ extension Container { } } - // Now, are there any machine IDs in the model that aren't in the list? If so, add them as "unknown" - let modelMachineIDs = self.model.allMachineIDs() - modelMachineIDs.forEach { peerMachineID in - if !knownMachineIDs.contains(peerMachineID) && !allowedMachineIDs.contains(peerMachineID) { - os_log("Peer machineID is unknown, beginning grace period: %@", log: tplogDebug, type: .default, peerMachineID) - let machine = MachineMO(context: self.moc) - machine.machineID = peerMachineID - machine.container = containerMO - machine.seenOnFullList = false - machine.modified = Date() - machine.status = Int64(TPMachineIDStatus.unknown.rawValue) - differences = true + // if this account is not a demo account... + if knownMachines.count > 0 { + // Are there any machine IDs in the model that aren't in the list? If so, add them as "unknown" + let modelMachineIDs = self.model.allMachineIDs() + modelMachineIDs.forEach { peerMachineID in + if !knownMachineIDs.contains(peerMachineID) && !allowedMachineIDs.contains(peerMachineID) { + os_log("Peer machineID is unknown, beginning grace period: %@", log: tplogDebug, type: .default, peerMachineID) + let machine = MachineMO(context: self.moc) + machine.machineID = peerMachineID + machine.container = containerMO + machine.seenOnFullList = false + machine.modified = Date() + machine.status = Int64(TPMachineIDStatus.unknown.rawValue) + differences = true - self.containerMO.addToMachines(machine) + self.containerMO.addToMachines(machine) + } } + } else { + os_log("Believe we're in a demo account; not starting an unknown machine ID grace period", log: tplogDebug, type: .default) } // We no longer use allowed machine IDs. @@ -205,7 +208,7 @@ extension Container { self.moc.performAndWait { do { var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) // We treat an add push as authoritative (even though we should really confirm it with a full list fetch). // We can get away with this as we're using this list as a deny-list, and if we accidentally don't deny someone fast enough, that's okay. @@ -254,7 +257,7 @@ extension Container { self.moc.performAndWait { do { var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) // This is an odd approach: we'd like to confirm that this MID was actually removed (and not just a delayed push). // So, let's set the status to "unknown", and its modification date to the distant past. @@ -331,7 +334,7 @@ extension Container { // We don't want to automatically kick out new peers if they rejoin with the same MID. let machines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(machines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(machines.compactMap { $0.machineID }) // Peers trust themselves. So if the ego peer is in Octagon, its machineID will be in this set let trustedMachineIDs = Set(dynamicInfo.includedPeerIDs.compactMap { self.model.peer(withID: $0)?.permanentInfo.machineID }) diff --git a/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift b/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift index 708d1881..af712744 100644 --- a/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift +++ b/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift @@ -19,7 +19,7 @@ extension ViewKey { $0.parentkeyUuid = ckksKey.parentKeyUUID $0.keyclass = kc $0.wrappedkeyBase64 = ckksKey.wrappedkey.base64WrappedKey() - $0.uploadOsversion = SecCKKSHostOSVersion() + $0.uploadOsVersion = SecCKKSHostOSVersion() } } } diff --git a/keychain/TrustedPeersHelper/CuttlefishErrors.swift b/keychain/TrustedPeersHelper/CuttlefishErrors.swift index 138c7c6d..04d9b902 100644 --- a/keychain/TrustedPeersHelper/CuttlefishErrors.swift +++ b/keychain/TrustedPeersHelper/CuttlefishErrors.swift @@ -1,32 +1,22 @@ import Foundation -let CuttlefishErrorDomain = "CuttlefishError" -enum CuttlefishErrorCode: Int { - case establishFailed = 1001 - case invalidChangeToken = 1005 - case resultGraphNotFullyReachable = 1007 - case changeTokenExpired = 1018 - case transactionalFailure = 1019 - case retryableServerFailure = 1021 - case keyHierarchyAlreadyExists = 1033 -} - struct CuttlefishErrorMatcher { let code: CuttlefishErrorCode } // Use a 'pattern match operator' to make pretty case statements matching Cuttlefish errors func ~=(pattern: CuttlefishErrorMatcher, value: Error?) -> Bool { - guard let value = value else { + guard let error = value else { return false } + let nserror = error as NSError + return nserror.isCuttlefishError(pattern.code) +} - let error = value as NSError - - guard let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError else { - return false +func CuttlefishRetryAfter(error: Error?) -> TimeInterval { + guard let error = error else { + return 0 } - - return error.domain == CKInternalErrorDomain && error.code == CKInternalErrorCode.errorInternalPluginError.rawValue && - underlyingError.domain == CuttlefishErrorDomain && underlyingError.code == pattern.code.rawValue + let nserror = error as NSError + return nserror.cuttlefishRetryAfter() } diff --git a/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift b/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift index 2ed38843..1ab70461 100644 --- a/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift +++ b/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift @@ -61,7 +61,6 @@ class RecoveryKeySet: NSObject { class func generateRecoveryKey(keyType: recoveryKeyType, masterSecret: Data, recoverySalt: String) throws -> (Data) { var keyLength: Int var info: Data - var infoLength: Int var derivedKey: Data var finalKey = Data() @@ -71,7 +70,6 @@ class RecoveryKeySet: NSObject { let infoString = Array("Recovery Encryption Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case recoveryKeyType.kOTRecoveryKeySigning: @@ -79,7 +77,6 @@ class RecoveryKeySet: NSObject { let infoString = Array("Recovery Signing Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break } @@ -95,27 +92,25 @@ class RecoveryKeySet: NSObject { derivedKey = Data(count: keyLength) var masterSecretMutable = masterSecret - let masterSecretLength = masterSecret.count - let derivedKeySize = derivedKey.count let bottleSaltData = Data(bytes: Array(recoverySalt.utf8), count: recoverySalt.utf8.count) - try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutablePointer) throws ->Void in - try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutablePointer) throws ->Void in - try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafePointer) throws -> Void in - try info.withUnsafeBytes { (infoBytes: UnsafePointer) throws -> Void in + try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutableRawBufferPointer) throws ->Void in + try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutableRawBufferPointer) throws ->Void in + try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafeRawBufferPointer) throws -> Void in + try info.withUnsafeBytes { (infoBytes: UnsafeRawBufferPointer) throws -> Void in status = cchkdf(ccsha384_di(), - masterSecretLength, masterSecretBytes, - bottleSaltData.count, bottleSaltBytes, - infoLength, infoBytes, - keyLength, derivedKeyBytes) + masterSecretBytes.count, masterSecretBytes.baseAddress!, + bottleSaltBytes.count, bottleSaltBytes.baseAddress!, + infoBytes.count, infoBytes.baseAddress!, + derivedKeyBytes.count, derivedKeyBytes.baseAddress!) if status != 0 { throw RecoveryKeySetError.corecryptoKeyGeneration(corecryptoError: status) } if(keyType == recoveryKeyType.kOTRecoveryKeyEncryption || keyType == recoveryKeyType.kOTRecoveryKeySigning) { status = ccec_generate_key_deterministic(cp, - derivedKeySize, derivedKeyBytes, + derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!, ccDRBGGetRngState(), UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS), fullKey) @@ -126,8 +121,8 @@ class RecoveryKeySet: NSObject { let space = ccec_x963_export_size(1, ccec_ctx_pub(fullKey)) var key = Data(count: space) - key.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - ccec_x963_export(1, bytes, fullKey) + key.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) -> Void in + ccec_x963_export(1, bytes.baseAddress!, fullKey) } finalKey = Data(key) } @@ -178,11 +173,10 @@ class RecoveryKeySet: NSObject { let di = ccsha384_di() var result = Data(count: TPHObjectiveC.ccsha384_diSize()) - let derivedKeySize = keyData.count var keyDataMutable = keyData - result.withUnsafeMutableBytes {(resultBytes: UnsafeMutablePointer) -> Void in - keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutablePointer) -> Void in - ccdigest(di, derivedKeySize, keyDataBytes, resultBytes) + result.withUnsafeMutableBytes {(resultBytes: UnsafeMutableRawBufferPointer) -> Void in + keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutableRawBufferPointer) -> Void in + ccdigest(di, keyDataBytes.count, keyDataBytes.baseAddress!, resultBytes.baseAddress!) } } let hash = result.base64EncodedString(options: []) @@ -197,7 +191,7 @@ class RecoveryKeySet: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrLabel: label, kSecAttrApplicationLabel: String(format: "Recoveryed Encryption Key-%@", NSUUID().uuidString), kSecValueData: keyData, @@ -211,7 +205,7 @@ class RecoveryKeySet: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Recoveryed Signing Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -228,7 +222,7 @@ class RecoveryKeySet: NSObject { kSecAttrLabel: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitAll, ] @@ -335,9 +329,9 @@ extension RecoveryKeySetError: CustomNSError { } switch self { case .failedToSaveToKeychain(errorCode: let osError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) case .corecryptoKeyGeneration(corecryptoError: let corecryptoError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) default: break } diff --git a/keychain/TrustedPeersHelper/SetValueTransformer.swift b/keychain/TrustedPeersHelper/SetValueTransformer.swift index ced7dd28..2529be27 100644 --- a/keychain/TrustedPeersHelper/SetValueTransformer.swift +++ b/keychain/TrustedPeersHelper/SetValueTransformer.swift @@ -6,11 +6,11 @@ class SetValueTransformer: ValueTransformer { override class func transformedValueClass() -> AnyClass { return NSData.self } - + override class func allowsReverseTransformation() -> Bool { return true } - + override func transformedValue(_ value: Any?) -> Any? { do { guard let value = value else { return nil } @@ -27,7 +27,7 @@ class SetValueTransformer: ValueTransformer { guard let data = dataOp else { return nil } let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data) - return unarchiver.decodeObject(of: [NSSet.self], forKey:NSKeyedArchiveRootObjectKey) + return unarchiver.decodeObject(of: [NSSet.self], forKey: NSKeyedArchiveRootObjectKey) } catch { os_log("Failed to deserialize a purported Set: %@", log: tplogDebug, type: .default, error as CVarArg) return nil diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h b/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h index d46c031d..a633cef5 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h +++ b/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h @@ -41,6 +41,7 @@ #import "keychain/ckks/CKKSKeychainBackedKey.h" #import "keychain/ckks/CKKSPeer.h" #import "keychain/ckks/CKKSTLKShare.h" +#import "keychain/ckks/CloudKitCategories.h" #import #include diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist b/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist index 555752c4..6947f3d5 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist +++ b/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist @@ -35,5 +35,7 @@ com.apple.security.octagon com.apple.security.egoIdentities + com.apple.symptom_diagnostics.report + diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h index c313182d..be36cc1f 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h @@ -27,6 +27,8 @@ #import "keychain/ckks/CKKSKeychainBackedKey.h" #import "keychain/ckks/CKKSTLKShare.h" +#import "keychain/ot/OTConstants.h" + NS_ASSUME_NONNULL_BEGIN // Any client hoping to use the TrustedPeersHelperProtocol should have an entitlement @@ -38,13 +40,16 @@ NS_ASSUME_NONNULL_BEGIN @property TPPeerStatus peerStatus; @property BOOL memberChanges; @property BOOL unknownMachineIDsPresent; +@property (nullable) NSString* osVersion; - (instancetype)initWithPeerID:(NSString* _Nullable)peerID isPreapproved:(BOOL)isPreapproved status:(TPPeerStatus)peerStatus memberChanges:(BOOL)memberChanges - unknownMachineIDs:(BOOL)unknownMachineIDs; + unknownMachineIDs:(BOOL)unknownMachineIDs + osVersion:(NSString * _Nullable)osVersion; @end + @interface TrustedPeersHelperPeer : NSObject @property (nullable) NSString* peerID; @property (nullable) NSData* signingSPKI; @@ -61,13 +66,15 @@ NS_ASSUME_NONNULL_BEGIN @property TPPeerStatus egoStatus; @property NSString* _Nullable egoPeerID; @property (assign) uint64_t numberOfPeersInOctagon; -@property NSDictionary* peerCountsByModelID; + +// Note: this field does not include untrusted peers +@property NSDictionary* viablePeerCountsByModelID; @property BOOL isExcluded; @property BOOL isLocked; - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus - peerCountsByModelID:(NSDictionary*)peerCountsByModelID + viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked; @@ -99,6 +106,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)resetWithContainer:(NSString *)container context:(NSString *)context + resetReason:(CuttlefishResetReason)reason reply:(void (^)(NSError * _Nullable error))reply; - (void)localResetWithContainer:(NSString *)container @@ -179,6 +187,14 @@ NS_ASSUME_NONNULL_BEGIN NSData * _Nullable voucherSig, NSError * _Nullable error))reply; +// Preflighting a vouch will return the peer ID associated with the bottle you will be recovering. +// You can then use that peer ID to filter the tlkshares provided to vouchWithBottle. +- (void)preflightVouchWithBottleWithContainer:(NSString *)container + context:(NSString *)context + bottleID:(NSString*)bottleID + reply:(void (^)(NSString* _Nullable peerID, + NSError * _Nullable error))reply; + // Returns a voucher for our own identity, created by the identity inside this bottle - (void)vouchWithBottleWithContainer:(NSString *)container context:(NSString *)context diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m index a912a227..f04ac68e 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m @@ -149,6 +149,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) status:(TPPeerStatus)peerStatus memberChanges:(BOOL)memberChanges unknownMachineIDs:(BOOL)unknownMachineIDs + osVersion:(NSString *)osVersion { if((self = [super init])) { _peerID = peerID; @@ -156,18 +157,20 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _peerStatus = peerStatus; _memberChanges = memberChanges; _unknownMachineIDsPresent = unknownMachineIDs; + _osVersion = osVersion; } return self; } - (NSString*)description { - return [NSString stringWithFormat:@"", + return [NSString stringWithFormat:@"", self.peerID, self.identityIsPreapproved, (int64_t)self.peerStatus, self.memberChanges ? @"YES" : @"NO", - self.unknownMachineIDsPresent ? @"YES" : @"NO"]; + self.unknownMachineIDsPresent ? @"YES" : @"NO", + self.osVersion?:@"unknown"]; } + (BOOL)supportsSecureCoding { @@ -181,6 +184,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _peerStatus = (TPPeerStatus)[coder decodeInt64ForKey:@"peerStatus"]; _memberChanges = (BOOL)[coder decodeInt64ForKey:@"memberChanges"]; _unknownMachineIDsPresent = (BOOL)[coder decodeInt64ForKey:@"unknownMachineIDs"]; + _osVersion = [coder decodeObjectOfClass:[NSString class] forKey:@"osVersion"]; } return self; } @@ -191,6 +195,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) [coder encodeInt64:(int64_t)self.peerStatus forKey:@"peerStatus"]; [coder encodeInt64:(int64_t)self.memberChanges forKey:@"memberChanges"]; [coder encodeInt64:(int64_t)self.unknownMachineIDsPresent forKey:@"unknownMachineIDs"]; + [coder encodeObject:self.osVersion forKey:@"osVersion"]; } @end @@ -199,16 +204,16 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus - peerCountsByModelID:(NSDictionary*)peerCountsByModelID + viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked { if((self = [super init])) { _egoPeerID = egoPeerID; _egoStatus = egoStatus; - _peerCountsByModelID = peerCountsByModelID; + _viablePeerCountsByModelID = viablePeerCountsByModelID; _numberOfPeersInOctagon = 0; - for(NSNumber* n in peerCountsByModelID.allValues) { + for(NSNumber* n in viablePeerCountsByModelID.allValues) { _numberOfPeersInOctagon += [n unsignedIntegerValue]; } _isExcluded = isExcluded; @@ -230,9 +235,9 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) if ((self = [super init])) { _egoPeerID = [coder decodeObjectOfClass:[NSString class] forKey:@"peerID"]; _egoStatus = (TPPeerStatus)[coder decodeInt64ForKey:@"egoStatus"]; - _peerCountsByModelID = [coder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSString class], [NSNumber class]]] forKey:@"peerCountsByModelID"]; + _viablePeerCountsByModelID = [coder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSString class], [NSNumber class]]] forKey:@"viablePeerCountsByModelID"]; _numberOfPeersInOctagon = 0; - for(NSNumber* n in _peerCountsByModelID.allValues) { + for(NSNumber* n in _viablePeerCountsByModelID.allValues) { _numberOfPeersInOctagon += [n unsignedIntegerValue]; } @@ -245,7 +250,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.egoPeerID forKey:@"peerID"]; [coder encodeInt64:self.egoStatus forKey:@"egoStatus"]; - [coder encodeObject:self.peerCountsByModelID forKey:@"peerCountsByModelID"]; + [coder encodeObject:self.viablePeerCountsByModelID forKey:@"viablePeerCountsByModelID"]; [coder encodeBool:self.isExcluded forKey:@"isExcluded"]; [coder encodeBool:self.isLocked forKey:@"isLocked"]; } diff --git a/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m b/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m index b2607898..0e4cdeb0 100644 --- a/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m +++ b/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m @@ -26,6 +26,7 @@ #import #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTConstants.h" +#import "utilities/SecCFWrappers.h" @implementation OTPrivateKey (SecurityFoundation) @@ -36,7 +37,8 @@ pk.keyData = keyPair.keyData; return pk; } -+ (SecKeyRef) createSecKey:(NSData*)keyData + ++ (SecKeyRef) createSecKey:(NSData*)keyData CF_RETURNS_RETAINED { NSDictionary *keyAttributes = @{ (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, @@ -55,7 +57,10 @@ } return nil; } - return [[SFECKeyPair alloc] initWithSecKey:[OTPrivateKey createSecKey:self.keyData]]; + SecKeyRef secKey = [OTPrivateKey createSecKey:self.keyData]; + SFECKeyPair *result = [[SFECKeyPair alloc] initWithSecKey:secKey]; + CFReleaseNull(secKey); + return result; } @end diff --git a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift index 17ab441f..30916147 100644 --- a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift +++ b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift @@ -21,10 +21,10 @@ extension Container { return (reta, reterr) } - func resetSync(test: XCTestCase) -> Error? { + func resetSync(resetReason: CuttlefishResetReason, test: XCTestCase) -> Error? { let expectation = XCTestExpectation(description: "reset replied") var reterr: Error? - self.reset { error in + self.reset(resetReason: resetReason) { error in reterr = error expectation.fulfill() } @@ -126,6 +126,18 @@ extension Container { return (reta, retb, reterr) } + func preflightVouchWithBottleSync(test: XCTestCase, bottleID: String) -> (String?, Error?) { + let expectation = XCTestExpectation(description: "preflightVouchWithBottle replied") + var reta: String?, reterr: Error? + self.preflightVouchWithBottle(bottleID: bottleID) { a, err in + reta = a + reterr = err + expectation.fulfill() + } + test.wait(for: [expectation], timeout: 10.0) + return (reta, reterr) + } + func vouchWithBottleSync(test: XCTestCase, b: String, entropy: Data, bottleSalt: String, tlkShares: [CKKSTLKShare]) -> (Data?, Data?, Error?) { let expectation = XCTestExpectation(description: "vouchWithBottle replied") var reta: Data?, retb: Data?, reterr: Error? @@ -310,7 +322,7 @@ extension Container { func trustStatusSync(test: XCTestCase) -> (TrustedPeersHelperEgoPeerStatus, Error?) { let expectation = XCTestExpectation(description: "trustStatus replied") - var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, peerCountsByModelID: [:], isExcluded: false, isLocked: false) + var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false) var reterror: Error? self.trustStatus { egoStatus, error in retEgoStatus = egoStatus diff --git a/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift b/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift index fce8f219..fbef651a 100644 --- a/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift +++ b/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift @@ -210,6 +210,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { var joinListener: ((JoinWithVoucherRequest) -> NSError?)? var healthListener: ((GetRepairActionRequest) -> NSError?)? var fetchViableBottlesListener: ((FetchViableBottlesRequest) -> NSError?)? + var resetListener: ((ResetRequest) -> NSError?)? var fetchViableBottlesDontReturnBottleWithID: String? @@ -233,12 +234,19 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { } } - static func makeCloudKitCuttlefishError(code: CuttlefishErrorCode) -> NSError { - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: code.rawValue, - userInfo: nil)]) + static func makeCloudKitCuttlefishError(code: CuttlefishErrorCode, retryAfter: TimeInterval = 5) -> NSError { + let cuttlefishError = CKPrettyError(domain: CuttlefishErrorDomain, + code: code.rawValue, + userInfo: [CuttlefishErrorRetryAfterKey: retryAfter]) + let internalError = CKPrettyError(domain: CKInternalErrorDomain, + code: CKInternalErrorCode.errorInternalPluginError.rawValue, + userInfo: [NSUnderlyingErrorKey: cuttlefishError, ]) + let ckError = CKPrettyError(domain: CKErrorDomain, + code: CKError.serverRejectedRequest.rawValue, + userInfo: [NSUnderlyingErrorKey: internalError, + CKErrorServerDescriptionKey: "Fake: FunctionError domain: CuttlefishError, code: \(code),\(code.rawValue)", + ]) + return ckError } func makeSnapshot() { @@ -287,6 +295,13 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { func reset(_ request: ResetRequest, completion: @escaping (ResetResponse?, Error?) -> Void) { print("FakeCuttlefish: reset called") + if let resetListener = self.resetListener { + let possibleError = resetListener(request) + guard possibleError == nil else { + completion(nil, possibleError) + return + } + } self.state = State() self.makeSnapshot() completion(ResetResponse.with { @@ -328,11 +343,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { if let fakeZone = self.fakeCKZones[rzid] as? FakeCKZone { fakeZone.queue.sync { - let tlkRecord = viewKeys.newTlk.fakeRecord(zoneID: rzid) + let tlkRecord = viewKeys.newTlk.fakeRecord(zoneID: rzid) let classARecord = viewKeys.newClassA.fakeRecord(zoneID: rzid) let classCRecord = viewKeys.newClassC.fakeRecord(zoneID: rzid) - let tlkPointerRecord = viewKeys.newTlk.fakeKeyPointer(zoneID: rzid) + let tlkPointerRecord = viewKeys.newTlk.fakeKeyPointer(zoneID: rzid) let classAPointerRecord = viewKeys.newClassA.fakeKeyPointer(zoneID: rzid) let classCPointerRecord = viewKeys.newClassC.fakeKeyPointer(zoneID: rzid) @@ -342,11 +357,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let zoneKeys = self.ckksZoneKeys[rzid] as? ZoneKeys ?? ZoneKeys(forZoneName: rzid.zoneName) self.ckksZoneKeys[rzid] = zoneKeys - zoneKeys.tlk = CKKSKey(ckRecord: tlkRecord) + zoneKeys.tlk = CKKSKey(ckRecord: tlkRecord) zoneKeys.classA = CKKSKey(ckRecord: classARecord) zoneKeys.classC = CKKSKey(ckRecord: classCRecord) - zoneKeys.currentTLKPointer = CKKSCurrentKeyPointer(ckRecord: tlkPointerRecord) + zoneKeys.currentTLKPointer = CKKSCurrentKeyPointer(ckRecord: tlkPointerRecord) zoneKeys.currentClassAPointer = CKKSCurrentKeyPointer(ckRecord: classAPointerRecord) zoneKeys.currentClassCPointer = CKKSCurrentKeyPointer(ckRecord: classCPointerRecord) #endif @@ -407,7 +422,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = establishListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -426,7 +441,6 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { self.makeSnapshot() - let response = EstablishResponse.with { if self.nextEstablishReturnsMoreChanges { $0.changes = Changes.with { @@ -450,7 +464,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = joinListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -518,7 +532,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = updateListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -571,7 +585,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = fetchChangesListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -606,7 +620,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = fetchViableBottlesListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -659,8 +673,8 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { func reportHealth(_: ReportHealthRequest, completion: @escaping (ReportHealthResponse?, Error?) -> Void) { completion(ReportHealthResponse(), nil) } - func pushHealthInquiry(_: HealthInquiryRequest, completion: @escaping (HealthInquiryResponse?, Error?) -> Void) { - completion(HealthInquiryResponse(), nil) + func pushHealthInquiry(_: PushHealthInquiryRequest, completion: @escaping (PushHealthInquiryResponse?, Error?) -> Void) { + completion(PushHealthInquiryResponse(), nil) } func getRepairAction(_ request: GetRepairActionRequest, completion: @escaping (GetRepairActionResponse?, Error?) -> Void) { @@ -670,7 +684,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = healthListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -679,20 +693,17 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { $0.repairAction = .postRepairEscrow } completion(response, nil) - } - else if self.returnRepairAccountResponse { + } else if self.returnRepairAccountResponse { let response = GetRepairActionResponse.with { $0.repairAction = .postRepairAccount } completion(response, nil) - } - else if self.returnResetOctagonResponse { + } else if self.returnResetOctagonResponse { let response = GetRepairActionResponse.with { $0.repairAction = .resetOctagon } completion(response, nil) - } - else if self.returnNoActionResponse { + } else if self.returnNoActionResponse { let response = GetRepairActionResponse.with { $0.repairAction = .noAction } @@ -702,14 +713,17 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { $0.repairAction = .noAction } completion(response, self.returnRepairErrorResponse) - } - else { + } else { completion(GetRepairActionResponse(), nil) } } + + func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) { + completion(GetSupportAppInfoResponse(), nil) + } } -extension FakeCuttlefishServer : CloudKitCode.Invocable { +extension FakeCuttlefishServer: CloudKitCode.Invocable { func invoke(function: String, request: RequestType, completion: @escaping (ResponseType?, Error?) -> Void) { @@ -745,8 +759,8 @@ extension FakeCuttlefishServer : CloudKitCode.Invocable { case let request as ReportHealthRequest: self.reportHealth(request, completion: completion as! (ReportHealthResponse?, Error?) -> Void) return - case let request as HealthInquiryRequest: - self.pushHealthInquiry(request, completion: completion as! (HealthInquiryResponse?, Error?) -> Void) + case let request as PushHealthInquiryRequest: + self.pushHealthInquiry(request, completion: completion as! (PushHealthInquiryResponse?, Error?) -> Void) return case let request as GetRepairActionRequest: self.getRepairAction(request, completion: completion as! (GetRepairActionResponse?, Error?) -> Void) diff --git a/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift b/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift index 5c0ee671..5d8d2c33 100644 --- a/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift +++ b/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift @@ -159,11 +159,15 @@ class MockCuttlefishAPIAsyncClient: CuttlefishAPIAsync { print("MockCuttlefish: reportHealth called") completion(ReportHealthResponse(), nil) } - func pushHealthInquiry(_: HealthInquiryRequest, completion: @escaping (HealthInquiryResponse?, Error?) -> Void) { - completion(HealthInquiryResponse(), nil) + func pushHealthInquiry(_: PushHealthInquiryRequest, completion: @escaping (PushHealthInquiryResponse?, Error?) -> Void) { + completion(PushHealthInquiryResponse(), nil) } func getRepairAction(_: GetRepairActionRequest, completion: @escaping (GetRepairActionResponse?, Error?) -> Void) { completion(GetRepairActionResponse(), nil) } + func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) { + completion(GetSupportAppInfoResponse(), nil) + } + } diff --git a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h index b74e57ec..fc2d9223 100644 --- a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h +++ b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h @@ -7,8 +7,8 @@ #import "utilities/SecCFError.h" -#import "securityd/SecItemServer.h" -#import "securityd/spi.h" +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/spi.h" #import #import "keychain/ckks/CKKS.h" diff --git a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift index 0c6f1ef1..0516c23a 100644 --- a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift +++ b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift @@ -16,6 +16,10 @@ let encryptionKey_384 = Data(base64Encoded: "BE1RuazBWmSEx0XVGhobbrdSE6fRQOrUrYE let symmetricKey_384 = Data(base64Encoded: "MfHje3Y/mWV0q+grjwZ4VxuqB7OreYHLxYkeeCiNjjY=") +let recovery_signingKey_384 = Data(base64Encoded: "BK5nrmP6oitJHtGV2Josk5cUKnG3pqxgEP8uzyPtNXgAMNHZoDKwCKFXpUzQSgbYiR4G2XZY2Q0+qSCKN7YSY2KNKE0hM9p4GvABBmAWKW/O9eFd5ugKQWisn25a/7nieIw8CQ81hBDR7R/vBpfLVtzE8ieRA8JPGqulQ5RdLcClFrD3B8BPJAZpLv4OP1CLDA==") + +let recovery_encryptionKey_384 = Data(base64Encoded: "BKkZpYHTbMi2yrWFo+ErM3HbcYJCngPuWDYoVUD7egKkmiHFvv1Bsk0j/Dcj3xTR12vj5QOpZQV3GzE5estf75BV+EZz1cjUUSi/MysfpKsqEbwYrhIEkmeyMGr7CVWQWRLR2LnoihnQajvWi1LmO0AoDl3+LzVgTJBjjDQ5ANyw0Yv1EgOgBvZsLA9UTN4oAg==") + class TrustedPeersHelperUnitTests: XCTestCase { var tmpPath: String! @@ -158,10 +162,11 @@ class TrustedPeersHelperUnitTests: XCTestCase { func establish(reload: Bool, contextID: String, + allowedMachineIDs: Set = Set(["aaa", "bbb", "ccc"]), store: NSPersistentStoreDescription) throws -> (Container, String) { var container = try Container(name: ContainerName(container: "test", context: contextID), persistentStoreDescription: store, cuttlefish: cuttlefish) - XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["aaa", "bbb", "ccc"]), "should be able to set allowed machine IDs") + XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: allowedMachineIDs, listDifference: allowedMachineIDs.count > 0), "should be able to set allowed machine IDs") let (peerID, permanentInfo, permanentInfoSig, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1") do { @@ -243,7 +248,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { persistentStoreDescription: store, cuttlefish: cuttlefish) - XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs), "Should be able to set machine IDs") + XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, listDifference: machineIDs.count > 0), "Should be able to set machine IDs") print("preparing \(containerID)") let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error) = @@ -561,7 +566,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { print("reset A") do { - let error = containerA.resetSync(test: self) + let error = containerA.resetSync(resetReason: .testGenerated, test: self) XCTAssertNil(error) } do { @@ -854,6 +859,31 @@ class TrustedPeersHelperUnitTests: XCTestCase { } } + func testRecoveryKeyTestVectors() { + let secretString = "I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret" + + let secret = secretString.data(using: .utf8) + + do { + let testv1 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeySigning, masterSecret: secret!, recoverySalt: testDSID) + XCTAssertEqual(testv1, recovery_signingKey_384, "signing keys should match") + + let testv2 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeyEncryption, masterSecret: secret!, recoverySalt: testDSID) + XCTAssertEqual(testv2, recovery_encryptionKey_384, "encryption keys should match") + + let newSecretString = "I'm f secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret" + let newSecret = newSecretString.data(using: .utf8) + + let testv4 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeySigning, masterSecret: newSecret!, recoverySalt: testDSID) + XCTAssertNotEqual(testv4, recovery_signingKey_384, "signing keys should not match") + + let testv5 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeyEncryption, masterSecret: newSecret!, recoverySalt: testDSID) + XCTAssertNotEqual(testv5, recovery_encryptionKey_384, "encryption keys should not match") + } catch { + XCTFail("error testing RecoveryKey test vectors \(error)") + } + } + func testJoiningWithBottle() throws { var bottleA: BottleMO var entropy: Data @@ -916,6 +946,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) @@ -997,6 +1031,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) @@ -1073,6 +1111,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: "wrong escrow record") + XCTAssertNotNil(errorPreflight, "Should be an error preflighting bottle that doesn't exist") + XCTAssertNil(bottlePeerID, "peerID should be nil for no bottle") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: "wrong escrow record", entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1138,6 +1180,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleB.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, bPeerID, "Bottle should be for peer B") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleB.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1205,6 +1251,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "987654321", tlkShares: []) XCTAssertNotNil(error3) @@ -1270,6 +1320,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: Data(count: Int(OTMasterSecretLength)), bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1335,10 +1389,13 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") - // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.fetchViableBottlesError.append(ckError) + self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) + + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNotNil(errorPreflight, "Should be an error preflighting a vouch with bottle with a fetch error") + XCTAssertNil(bottlePeerID, "peerID should be nil") + + self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) @@ -1465,10 +1522,9 @@ class TrustedPeersHelperUnitTests: XCTestCase { let (_, peerID2) = try establish(reload: false, contextID: "second", store: tmpStoreDescription(name: "container-peer2.db")) // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.nextFetchErrors.append(ckError) - _ = c.updateSync(test: self) + self.cuttlefish.nextFetchErrors.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) + let (_, updateError) = c.updateSync(test: self) + XCTAssertNil(updateError, "Update should have succeeded") // and c's model should only include peerID2 c.moc.performAndWait { @@ -1772,16 +1828,17 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) XCTAssertNotNil(voucherData) XCTAssertNotNil(voucherSig) - // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.nextFetchErrors.append(ckError) + self.cuttlefish.nextFetchErrors.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) // Before B joins, there should be no TLKShares for B assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee")) @@ -1798,7 +1855,6 @@ class TrustedPeersHelperUnitTests: XCTestCase { let containerA = try Container(name: ContainerName(container: "a", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish) let containerB = try Container(name: ContainerName(container: "b", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish) - let machineIDs = Set(["aaa", "bbb"]) XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs)) XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs)) @@ -1912,7 +1968,6 @@ class TrustedPeersHelperUnitTests: XCTestCase { XCTAssertNil(containerA.distrustSync(test: self, peerIDs: Set([bPeerID!])), "Should be no error distrusting peers") assertDistrusts(context: containerA, peerIDs: [bPeerID!]) - let recoveryKey = SecRKCreateRecoveryKeyString(nil) XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") @@ -2089,7 +2144,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { knownMachineMOs.forEach { if $0.machineID == "xxx" { - $0.modified = Date(timeIntervalSinceNow: -60*60*72) + $0.modified = Date(timeIntervalSinceNow: -60 * 60 * 72) } } @@ -2251,17 +2306,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { func testMachineIDListSetDisallowedOldUnknownMachineIDs() throws { let description = tmpStoreDescription(name: "container.db") - let (container, _) = try establish(reload: false, store: description) - - container.moc.performAndWait { - let knownMachineMOs = container.containerMO.machines as? Set ?? Set() - - knownMachineMOs.forEach { - container.containerMO.removeFromMachines($0) - } - - try! container.moc.save() - } + let (container, _) = try establish(reload: false, contextID: OTDefaultContext, allowedMachineIDs: Set(), store: description) // and set the machine ID list to something that doesn't include 'aaa' XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["bbb", "ccc"], listDifference: true), "should be able to set allowed machine IDs") @@ -2280,7 +2325,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { XCTAssertFalse(aaaMO.allowed, "allowed should no longer be a used field") // Pretend that aaa was added 49 hours ago - aaaMO.modified = Date(timeIntervalSinceNow: -60*60*49) + aaaMO.modified = Date(timeIntervalSinceNow: -60 * 60 * 49) try! container.moc.save() } @@ -2324,7 +2369,41 @@ class TrustedPeersHelperUnitTests: XCTestCase { try self.assert(container: container, allowedMachineIDs: Set(["aaa", "bbb", "ccc"]), disallowedMachineIDs: [], unknownMachineIDs: Set([unknownMachineID]), persistentStore: description, cuttlefish: self.cuttlefish) } - func testContainerAndModelConsistency() throws{ + func testMachineIDListHandlingInDemoAccounts() throws { + // Demo accounts have no machine IDs in their lists + let description = tmpStoreDescription(name: "container.db") + let (container, peerID1) = try establish(reload: false, contextID: OTDefaultContext, allowedMachineIDs: Set(), store: description) + + // And so we just don't write down any MIDs + try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // Even when joining... + let unknownMachineID = "not-on-list" + let (c2, peerID2) = try self.joinByVoucher(sponsor: container, + containerID: "second", + machineID: unknownMachineID, + machineIDs: Set(), + store: description) + try self.assert(container: c2, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // And the first container accepts the join... + let (_, cUpdateError) = container.updateSync(test: self) + XCTAssertNil(cUpdateError, "Should be able to update first container") + assertTrusts(context: container, peerIDs: [peerID1, peerID2]) + + // And still has nothing in its list... + try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // Even after a full list set + XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: [], listDifference: false), "should be able to set allowed machine IDs") + try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set") + + + } + + func testContainerAndModelConsistency() throws { let preTestContainerName = ContainerName(container: "testToCreatePrepareData", context: "context") let description = tmpStoreDescription(name: "container.db") @@ -2358,19 +2437,19 @@ class TrustedPeersHelperUnitTests: XCTestCase { containerMO.egoPeerStableInfoSig = stableInfoSig containerMO.egoPeerStableInfo = stableInfo let containerEgoStableInfo = TPPeerStableInfo(data: stableInfo!, sig: stableInfoSig!) - do{ + do { let peerKeys: OctagonSelfPeerKeys = try loadEgoKeysSync(peerID: containerMO.egoPeerID!) - let info3: TPPeerStableInfo = TPPeerStableInfo(clock: containerEgoStableInfo!.clock + 2, - policyVersion:containerEgoStableInfo!.policyVersion, - policyHash:containerEgoStableInfo!.policyHash, - policySecrets:containerEgoStableInfo!.policySecrets, - deviceName:containerEgoStableInfo!.deviceName, - serialNumber:containerEgoStableInfo!.serialNumber, - osVersion:containerEgoStableInfo!.osVersion, - signing:peerKeys.signingKey, - recoverySigningPubKey:containerEgoStableInfo!.recoverySigningPublicKey, - recoveryEncryptionPubKey:containerEgoStableInfo!.recoveryEncryptionPublicKey, - error:nil) + let info3 = TPPeerStableInfo(clock: containerEgoStableInfo!.clock + 2, + policyVersion: containerEgoStableInfo!.policyVersion, + policyHash: containerEgoStableInfo!.policyHash, + policySecrets: containerEgoStableInfo!.policySecrets, + deviceName: containerEgoStableInfo!.deviceName, + serialNumber: containerEgoStableInfo!.serialNumber, + osVersion: containerEgoStableInfo!.osVersion, + signing: peerKeys.signingKey, + recoverySigningPubKey: containerEgoStableInfo!.recoverySigningPublicKey, + recoveryEncryptionPubKey: containerEgoStableInfo!.recoveryEncryptionPublicKey, + error: nil) //setting the containerMO's ego stable info to an old clock containerMO.egoPeerStableInfo = containerEgoStableInfo!.data @@ -2406,4 +2485,34 @@ class TrustedPeersHelperUnitTests: XCTestCase { //after boot the clock should be updated to the one that was saved in the model XCTAssertEqual(stableInfoAfterBoot!.clock, 3, "clock should be updated to 3") } + + func testRetryableError() throws { + XCTAssertTrue(RetryingInvocable.retryableError(error: NSError(domain: NSURLErrorDomain, code: NSURLErrorTimedOut, userInfo: nil))) + XCTAssertFalse(RetryingInvocable.retryableError(error: NSError(domain: NSURLErrorDomain, code: NSURLErrorUnknown, userInfo: nil))) + XCTAssertTrue(RetryingInvocable.retryableError(error: NSError(domain: CKErrorDomain, code: CKError.networkFailure.rawValue, userInfo: nil))) + XCTAssertFalse(RetryingInvocable.retryableError(error: NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: nil))) + + let sub0 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalServerInternalError.rawValue, userInfo: nil) + let e0 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: sub0]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e0)) + + let sub1 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalGenericError.rawValue, userInfo: nil) + let e1 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: sub1]) + XCTAssertFalse(RetryingInvocable.retryableError(error: e1)) + + let cf2 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) + let int2 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf2]) + let e2 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int2]) + XCTAssertFalse(RetryingInvocable.retryableError(error: e2)) + + let cf3 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.retryableServerFailure.rawValue, userInfo: nil) + let int3 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf3]) + let e3 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int3]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e3)) + + let cf4 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) + let int4 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf4]) + let e4 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int4]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e4)) + } } diff --git a/keychain/ckks/CKKS.m b/keychain/ckks/CKKS.m index 9c1e5ea1..934ff6a2 100644 --- a/keychain/ckks/CKKS.m +++ b/keychain/ckks/CKKS.m @@ -28,7 +28,7 @@ #endif #include -#include +#include "keychain/securityd/SecItemServer.h" #include #import diff --git a/keychain/ckks/CKKSAccountStateTracker.m b/keychain/ckks/CKKSAccountStateTracker.m index 34c411e5..05900dc0 100644 --- a/keychain/ckks/CKKSAccountStateTracker.m +++ b/keychain/ckks/CKKSAccountStateTracker.m @@ -211,7 +211,11 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status) // signals when this notify is Complete, including all downcalls. dispatch_semaphore_t finishedSema = dispatch_semaphore_create(0); + WEAKIFY(self); + [self.container accountInfoWithCompletionHandler:^(CKAccountInfo* ckAccountInfo, NSError * _Nullable error) { + STRONGIFY(self); + if(error) { secerror("ckksaccount: error getting account info: %@", error); dispatch_semaphore_signal(finishedSema); diff --git a/keychain/ckks/CKKSAnalytics.h b/keychain/ckks/CKKSAnalytics.h index ae6b6b9f..dd876eaf 100644 --- a/keychain/ckks/CKKSAnalytics.h +++ b/keychain/ckks/CKKSAnalytics.h @@ -46,12 +46,14 @@ extern NSString* const OctagonAnalyticsSOSStatus; extern NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin; extern NSString* const OctagonAnalyticsLastKeystateReady; extern NSString* const OctagonAnalyticsLastCoreFollowup; -extern NSString* const OctagonAnalyticsCoreFollowupStatus; extern NSString* const OctagonAnalyticsCoreFollowupFailureCount; extern NSString* const OctagonAnalyticsCoreFollowupLastFailureTime; extern NSString* const OctagonAnalyticsPrerecordPending; extern NSString* const OctagonAnalyticsCDPStateRun; +extern NSString* const CKKSAnalyticsLastCKKSPush; +extern NSString* const CKKSAnalyticsLastOctagonPush; + extern NSString* const OctagonAnalyticsKVSProvisioned; extern NSString* const OctagonAnalyticsKVSEnabled; extern NSString* const OctagonAnalyticsKeychainSyncProvisioned; @@ -118,6 +120,7 @@ extern CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoinAfter extern CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher; /* inner: join with bottle */ +extern CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithBottle; extern CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle; /* inner: join with recovery key */ diff --git a/keychain/ckks/CKKSAnalytics.m b/keychain/ckks/CKKSAnalytics.m index 8b37272d..ce66283d 100644 --- a/keychain/ckks/CKKSAnalytics.m +++ b/keychain/ckks/CKKSAnalytics.m @@ -55,12 +55,15 @@ NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus"; NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ"; NSString* const OctagonAnalyticsLastKeystateReady = @"OALastKSR"; NSString* const OctagonAnalyticsLastCoreFollowup = @"OALastCFU"; -NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus"; +//NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus"; NSString* const OctagonAnalyticsCoreFollowupFailureCount = @"OACFUTFailureCount"; NSString* const OctagonAnalyticsCoreFollowupLastFailureTime = @"OACFULastFailureTime"; NSString* const OctagonAnalyticsPrerecordPending = @"OAPrerecordPending"; NSString* const OctagonAnalyticsCDPStateRun = @"OACDPStateRun"; +NSString* const CKKSAnalyticsLastCKKSPush = @"lastCKKSPush"; +NSString* const CKKSAnalyticsLastOctagonPush = @"lastOctagonPush"; + NSString* const OctagonAnalyticsKVSProvisioned = @"OADCKVSProvisioned"; NSString* const OctagonAnalyticsKVSEnabled = @"OADCKVSEnabled"; NSString* const OctagonAnalyticsKeychainSyncProvisioned = @"OADCKCSProvisioned"; @@ -117,6 +120,7 @@ CKKSAnalyticsFailableEvent* const OctagonEventUpgradePrepare = (CKKSAnalyticsFai CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinWithVoucher"; +CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightVouchWithBottle"; CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithBottle"; CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithRecoveryKey"; diff --git a/keychain/ckks/CKKSDeviceStateEntry.h b/keychain/ckks/CKKSDeviceStateEntry.h index 16230793..f542e185 100644 --- a/keychain/ckks/CKKSDeviceStateEntry.h +++ b/keychain/ckks/CKKSDeviceStateEntry.h @@ -26,7 +26,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #include #import diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h index 082ec101..763195b2 100644 --- a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h @@ -47,6 +47,15 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; /* Clients that register to use fetches */ @interface CKKSCloudKitFetchRequest : NSObject @property bool participateInFetch; + +// If true, you will receive YES in the resync parameter to your callback. +// You may also receive YES to your callback if a resync has been triggered for you. +// It does nothing else. Use as you see fit. +// Note: you will receive exactly one callback with moreComing=0 and resync=1 for each +// resync fetch. You may then receive further callbacks with resync=0 during the same fetch, +// if other clients keep needing fetches. +@property BOOL resync; + @property (nullable) CKServerChangeToken* changeToken; @end @@ -60,8 +69,9 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; - (void)changesFetched:(NSArray*)changedRecords deletedRecordIDs:(NSArray*)deleted - oldChangeToken:(CKServerChangeToken* _Nullable)oldChangeToken - newChangeToken:(CKServerChangeToken*)changeToken; + newChangeToken:(CKServerChangeToken*)changeToken + moreComing:(BOOL)moreComing + resync:(BOOL)resync; @end // I don't understand why recordType isn't part of record ID, but deletions come in as both things @@ -80,7 +90,6 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; // Fetching everything currently in CloudKit and comparing to local copy @property bool resync; -@property NSDictionary>* clientMap; @property (nullable) NSMutableArray* fetchedZoneIDs; @property NSSet* fetchReasons; diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m index 1304cb87..9a03e976 100644 --- a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m @@ -39,7 +39,7 @@ #import "keychain/analytics/SecMetrics.h" #import "NSError+UsefulConstructors.h" #import "CKKSPowerCollection.h" -#include +#include "keychain/securityd/SecItemServer.h" @implementation CKKSCloudKitFetchRequest @end @@ -60,14 +60,19 @@ @property CKDatabaseOperation* fetchRecordZoneChangesOperation; @property NSMutableDictionary* allClientOptions; +@property NSMutableDictionary>* clientMap; + @property CKOperationGroup* ckoperationGroup; @property (assign) NSUInteger fetchedItems; @property bool forceResync; @property bool moreComing; -// Holds the original change token that the client believes they have synced to -@property NSMutableDictionary* originalChangeTokens; +@property size_t totalModifications; +@property size_t totalDeletions; + +// A zoneID is in this set if we're attempting to resync them +@property NSMutableSet* resyncingZones; @property CKKSResultOperation* fetchCompletedOperation; @end @@ -93,11 +98,10 @@ _container = container; _fetchRecordZoneChangesOperationClass = fetchRecordZoneChangesOperationClass; - NSMutableDictionary* clientMap = [NSMutableDictionary dictionary]; + _clientMap = [NSMutableDictionary dictionary]; for(id client in clients) { - clientMap[client.zoneID] = client; + _clientMap[client.zoneID] = client; } - _clientMap = [clientMap copy]; _ckoperationGroup = ckoperationGroup; _forceResync = forceResync; @@ -107,7 +111,11 @@ _modifications = [[NSMutableDictionary alloc] init]; _deletions = [[NSMutableDictionary alloc] init]; _changeTokens = [[NSMutableDictionary alloc] init]; - _originalChangeTokens = [[NSMutableDictionary alloc] init]; + + _resyncingZones = [NSMutableSet set]; + + _totalModifications = 0; + _totalDeletions = 0; _fetchCompletedOperation = [CKKSResultOperation named:@"record-zone-changes-completed" withBlock:^{}]; @@ -140,13 +148,11 @@ } else { options.previousServerChangeToken = clientPreference.changeToken; } - - self.originalChangeTokens[clientZoneID] = options.previousServerChangeToken; } - //if(options.previousServerChangeToken == nil) { - // nilChangeTag = true; - //} + if(clientPreference.resync || self.forceResync) { + [self.resyncingZones addObject:clientZoneID]; + } self.allClientOptions[client.zoneID] = options; } @@ -242,6 +248,8 @@ ckksnotice("ckksfetch", recordZoneID, "Record zone fetch complete: changeToken=%@ clientChangeTokenData=%@ moreComing=%@ error=%@", serverChangeToken, clientChangeTokenData, moreComing ? @"YES" : @"NO", recordZoneError); + + [self sendChangesToClient:recordZoneID moreComing:moreComing]; }; // Called with overall operation success. As I understand it, this block will be called for every operation. @@ -253,6 +261,15 @@ return; } + // Count record changes per zone + NSMutableDictionary* recordChangesPerZone = [NSMutableDictionary dictionary]; + self.totalModifications += self.modifications.count; + self.totalDeletions += self.deletions.count; + + // All of these should have been delivered by recordZoneFetchCompletionBlock; throw them away + [self.modifications removeAllObjects]; + [self.deletions removeAllObjects]; + // If we were told that there were moreChanges coming for any zone, we'd like to fetch again. // This is true if we recieve no error or a network timeout. Any other error should cause a failure. if(self.moreComing && (operationError == nil || [CKKSReachabilityTracker isNetworkFailureError:operationError])) { @@ -264,9 +281,6 @@ if(operationError) { self.error = operationError; - } else { - secnotice("ckksfetch", "Advising clients of fetched changes"); - [self sendAllChangesToClients]; } secnotice("ckksfetch", "Record zone changes fetch complete: error=%@", operationError); @@ -274,10 +288,6 @@ [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventFetchAllChanges count:self.fetchedItems]; - // Count record changes per zone - NSMutableDictionary* recordChangesPerZone = [NSMutableDictionary dictionary]; - NSNumber* totalModifications = [NSNumber numberWithUnsignedLong:self.modifications.count]; - NSNumber* totalDeletions = [NSNumber numberWithUnsignedLong:self.deletions.count]; for(CKRecordID* recordID in self.modifications) { NSNumber* last = recordChangesPerZone[recordID.zoneID]; @@ -303,8 +313,8 @@ metric[@"fetch_error_domain"] = operationError.domain; metric[@"fetch_error_code"] = [NSNumber numberWithLong:operationError.code]; - metric[@"total_modifications"] = totalModifications; - metric[@"total_deletions"] = totalDeletions; + metric[@"total_modifications"] = @(self.totalModifications); + metric[@"total_deletions"] = @(self.totalDeletions); for(CKRecordZoneID* zoneID in recordChangesPerZone) { metric[zoneID.zoneName] = recordChangesPerZone[zoneID]; } @@ -316,8 +326,8 @@ metric2[@"fetch_error"] = operationError; - metric2[@"total_modifications"] = totalModifications; - metric2[@"total_deletions"] = totalDeletions; + metric2[@"total_modifications"] = @(self.totalModifications); + metric2[@"total_deletions"] = @(self.totalDeletions); for(CKRecordZoneID* zoneID in recordChangesPerZone) { metric2[zoneID.zoneName] = recordChangesPerZone[zoneID]; } @@ -341,12 +351,11 @@ } } - // Don't need these any more; save some memory - [self.modifications removeAllObjects]; - [self.deletions removeAllObjects]; - // Trigger the fake 'we're done' operation. [self runBeforeGroupFinished: self.fetchCompletedOperation]; + + // Drop strong pointer to clients + [self.clientMap removeAllObjects]; }; [self dependOnBeforeGroupFinished:self.fetchCompletedOperation]; @@ -354,14 +363,7 @@ [self.container.privateCloudDatabase addOperation:self.fetchRecordZoneChangesOperation]; } -- (void)sendAllChangesToClients -{ - for(CKRecordZoneID* clientZoneID in self.clientMap) { - [self sendChangesToClient:clientZoneID]; - } -} - -- (void)sendChangesToClient:(CKRecordZoneID*)recordZoneID +- (void)sendChangesToClient:(CKRecordZoneID*)recordZoneID moreComing:(BOOL)moreComing { id client = self.clientMap[recordZoneID]; if(!client) { @@ -391,14 +393,22 @@ } }]; - ckksnotice("ckksfetch", recordZoneID, "Delivering fetched changes: changed=%lu deleted=%lu", - (unsigned long)zoneModifications.count, (unsigned long)zoneDeletions.count); + BOOL resync = [self.resyncingZones containsObject:recordZoneID]; + + ckksnotice("ckksfetch", recordZoneID, "Delivering fetched changes: changed=%lu deleted=%lu moreComing=%lu resync=%u", + (unsigned long)zoneModifications.count, (unsigned long)zoneDeletions.count, (unsigned long)moreComing, resync); // Tell the client about these changes! [client changesFetched:zoneModifications deletedRecordIDs:zoneDeletions - oldChangeToken:self.originalChangeTokens[recordZoneID] - newChangeToken:self.changeTokens[recordZoneID]]; + newChangeToken:self.changeTokens[recordZoneID] + moreComing:moreComing + resync:resync]; + + if(resync && !moreComing) { + ckksnotice("ckksfetch", recordZoneID, "No more changes for zone; turning off resync bit"); + [self.resyncingZones removeObject:recordZoneID]; + } } - (void)cancel { diff --git a/keychain/ckks/CKKSIncomingQueueEntry.h b/keychain/ckks/CKKSIncomingQueueEntry.h index 991e9a59..8d425b21 100644 --- a/keychain/ckks/CKKSIncomingQueueEntry.h +++ b/keychain/ckks/CKKSIncomingQueueEntry.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSMirrorEntry.h" diff --git a/keychain/ckks/CKKSIncomingQueueEntry.m b/keychain/ckks/CKKSIncomingQueueEntry.m index 0d38c781..3bb5e78d 100644 --- a/keychain/ckks/CKKSIncomingQueueEntry.m +++ b/keychain/ckks/CKKSIncomingQueueEntry.m @@ -30,8 +30,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import #import "CKKSIncomingQueueEntry.h" diff --git a/keychain/ckks/CKKSIncomingQueueOperation.m b/keychain/ckks/CKKSIncomingQueueOperation.m index 2aed9402..f53425a1 100644 --- a/keychain/ckks/CKKSIncomingQueueOperation.m +++ b/keychain/ckks/CKKSIncomingQueueOperation.m @@ -33,8 +33,8 @@ #import "keychain/ckks/CKKSCurrentItemPointer.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include diff --git a/keychain/ckks/CKKSItem.h b/keychain/ckks/CKKSItem.h index 6cd0088d..75e0f601 100644 --- a/keychain/ckks/CKKSItem.h +++ b/keychain/ckks/CKKSItem.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSRecordHolder.h" diff --git a/keychain/ckks/CKKSItem.m b/keychain/ckks/CKKSItem.m index 144b04fc..445d4898 100644 --- a/keychain/ckks/CKKSItem.m +++ b/keychain/ckks/CKKSItem.m @@ -30,8 +30,8 @@ #import "CKKSSIV.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import #import diff --git a/keychain/ckks/CKKSItemEncrypter.h b/keychain/ckks/CKKSItemEncrypter.h index aa477698..0780da11 100644 --- a/keychain/ckks/CKKSItemEncrypter.h +++ b/keychain/ckks/CKKSItemEncrypter.h @@ -23,7 +23,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" @class CKKSItem; @class CKKSMirrorEntry; diff --git a/keychain/ckks/CKKSItemEncrypter.m b/keychain/ckks/CKKSItemEncrypter.m index 6327aa9f..90810cef 100644 --- a/keychain/ckks/CKKSItemEncrypter.m +++ b/keychain/ckks/CKKSItemEncrypter.m @@ -26,7 +26,7 @@ #import #import -#include +#include "keychain/securityd/SecItemSchema.h" #import "CKKSItemEncrypter.h" #import "CKKSKeychainView.h" diff --git a/keychain/ckks/CKKSKey.m b/keychain/ckks/CKKSKey.m index 8cfa8b41..10e88f36 100644 --- a/keychain/ckks/CKKSKey.m +++ b/keychain/ckks/CKKSKey.m @@ -28,7 +28,7 @@ #import "CKKSCurrentKeyPointer.h" #import "CKKSKey.h" #import "keychain/categories/NSError+UsefulConstructors.h" -#include +#include "keychain/securityd/SecItemSchema.h" #include #include #include "OSX/sec/Security/SecItemShim.h" diff --git a/keychain/ckks/CKKSKeychainView.h b/keychain/ckks/CKKSKeychainView.h index 37e28163..ac6e0339 100644 --- a/keychain/ckks/CKKSKeychainView.h +++ b/keychain/ckks/CKKSKeychainView.h @@ -31,7 +31,7 @@ #import "keychain/ckks/CKKSReachabilityTracker.h" #import "keychain/ckks/CloudKitDependencies.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKS.h" @@ -43,6 +43,7 @@ #import "keychain/ckks/CKKSNotifier.h" #import "keychain/ckks/CKKSOutgoingQueueOperation.h" #import "keychain/ckks/CKKSPeer.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/ckks/CKKSProcessReceivedKeysOperation.h" #import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h" #import "keychain/ckks/CKKSScanLocalItemsOperation.h" @@ -69,29 +70,6 @@ NS_ASSUME_NONNULL_BEGIN @class CKKSZoneChangeFetcher; @class CKKSCurrentKeySet; -@interface CKKSPeerProviderState : NSObject -@property NSString* peerProviderID; - -// The peer provider believes trust in this state is essential. Any subsystem using -// a peer provider state should fail and pause if this is YES and there are trust errors. -@property BOOL essential; - -@property (nonatomic, readonly, nullable) CKKSSelves* currentSelfPeers; -@property (nonatomic, readonly, nullable) NSError* currentSelfPeersError; -@property (nonatomic, readonly, nullable) NSSet>* currentTrustedPeers; -@property (nonatomic, readonly, nullable) NSSet* currentTrustedPeerIDs; -@property (nonatomic, readonly, nullable) NSError* currentTrustedPeersError; - -- (instancetype)initWithPeerProviderID:(NSString*)providerID - essential:(BOOL)essential - selfPeers:(CKKSSelves* _Nullable)selfPeers - selfPeersError:(NSError* _Nullable)selfPeersError - trustedPeers:(NSSet>* _Nullable)currentTrustedPeers - trustedPeersError:(NSError* _Nullable)trustedPeersError; - -+ (CKKSPeerProviderState*)noPeersState:(id)provider; -@end - @interface CKKSKeychainView : CKKSZone @@ -118,6 +96,10 @@ NS_ASSUME_NONNULL_BEGIN // If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit. // Use this to track if we've completed a full refetch, so fix-up operations can be done. @property bool keyStateMachineRefetched; + +// Set this to request a key state refetch (tests only) +@property bool keyStateFullRefetchRequested; + @property (nullable) CKKSEgoManifest* egoManifest; @property (nullable) CKKSManifest* latestManifest; @property (nullable) CKKSResultOperation* keyStateReadyDependency; diff --git a/keychain/ckks/CKKSKeychainView.m b/keychain/ckks/CKKSKeychainView.m index 35f32e7a..1bbb06cd 100644 --- a/keychain/ckks/CKKSKeychainView.m +++ b/keychain/ckks/CKKSKeychainView.m @@ -66,6 +66,7 @@ #import "keychain/ckks/CKKSTLKShareRecord.h" #import "keychain/ckks/CKKSHealTLKSharesOperation.h" #import "keychain/ckks/CKKSLocalSynchronizeOperation.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/categories/NSError+UsefulConstructors.h" #import "keychain/ot/OTConstants.h" @@ -76,10 +77,10 @@ #include #include #include -#include -#include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" #include #include #include "keychain/SecureObjectSync/SOSAccountTransaction.h" @@ -88,61 +89,9 @@ #include #if OCTAGON -@implementation CKKSPeerProviderState -- (instancetype)initWithPeerProviderID:(NSString*)providerID - essential:(BOOL)essential - selfPeers:(CKKSSelves* _Nullable)selfPeers - selfPeersError:(NSError* _Nullable)selfPeersError - trustedPeers:(NSSet>* _Nullable)currentTrustedPeers - trustedPeersError:(NSError* _Nullable)trustedPeersError -{ - if((self = [super init])) { - _peerProviderID = providerID; - _essential = essential; - _currentSelfPeers = selfPeers; - _currentSelfPeersError = selfPeersError; - _currentTrustedPeers = currentTrustedPeers; - _currentTrustedPeersError = trustedPeersError; - - if(_currentTrustedPeers) { - NSMutableSet* trustedPeerIDs = [NSMutableSet set]; - for(id peer in _currentTrustedPeers) { - [trustedPeerIDs addObject:peer.peerID]; - } - _currentTrustedPeerIDs = trustedPeerIDs; - } - } - return self; -} - -- (NSString*)description -{ - return [NSString stringWithFormat:@"", - self.peerProviderID, - self.currentSelfPeers, - self.currentSelfPeersError ?: @"", - self.currentTrustedPeers, - self.currentTrustedPeersError ?: @""]; -} - -+ (CKKSPeerProviderState*)noPeersState:(id)provider -{ - return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID - essential:provider.essential - selfPeers:nil - selfPeersError:[NSError errorWithDomain:CKKSErrorDomain - code:CKKSNoPeersAvailable - description:@"No current self peer available"] - trustedPeers:nil - trustedPeersError:[NSError errorWithDomain:CKKSErrorDomain - code:CKKSNoPeersAvailable - description:@"No current trusted peers available"]]; -} -@end @interface CKKSKeychainView() @property bool keyStateFetchRequested; -@property bool keyStateFullRefetchRequested; @property bool keyStateProcessRequested; @property bool trustedPeersSetChanged; @@ -171,6 +120,9 @@ // An extra queue for semaphore-waiting-based NSOperations @property NSOperationQueue* waitingQueue; +// Scratch space for resyncs +@property (nullable) NSMutableSet* resyncRecordsSeen; + // Make these readwrite @property NSArray>* currentPeerProviders; @property NSArray* currentTrustStates; @@ -222,6 +174,8 @@ _zoneChangeFetcher = fetcher; [fetcher registerClient:self]; + _resyncRecordsSeen = nil; + _notifierClass = cloudKitClassDependencies.notifierClass; _notifyViewChangedScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat: @"%@-notify-scheduler", self.zoneName] initialDelay:250*NSEC_PER_MSEC @@ -254,7 +208,7 @@ [center postNotificationName:@"com.apple.security.view-become-ready" object:nil - userInfo:@{ @"view" : self.zoneName } + userInfo:@{ @"view" : self.zoneName ?: @"unknown" } options:0]; }]; @@ -500,6 +454,7 @@ } // If it's been more than 24 hours since the last fetch, fetch and process everything. + // Or, if we think we were interrupted in the middle of fetching, fetch some more. // Otherwise, just kick off the local queue processing. NSDate* now = [NSDate date]; @@ -507,7 +462,9 @@ [offset setHour:-24]; NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0]; - if(ckse.lastFetchTime == nil || [ckse.lastFetchTime compare: deadline] == NSOrderedAscending) { + if(ckse.lastFetchTime == nil || + [ckse.lastFetchTime compare: deadline] == NSOrderedAscending || + ckse.moreRecordsInCloudKit) { initialProcess = [self fetchAndProcessCKChanges:CKKSFetchBecauseSecuritydRestart after:self.lastFixupOperation]; // Also, kick off a scan local items: it'll find any out-of-sync issues in the local keychain @@ -1026,28 +983,20 @@ CKKSZoneKeyState* nextState = nil; NSError* nextError = nil; - // Many of our decisions below will be based on what keys exist. Help them out. - CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; - NSError* localerror = nil; - NSArray* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror]; - NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; - - // We also are checking for OutgoingQueueEntries in the reencrypt state; this is a sign that our key hierarchy is out of date. - NSInteger outdatedOQEs = [CKKSOutgoingQueueEntry countByState:SecCKKSStateReencrypt zone:self.zoneID error:&localerror]; + // Any state that wants should fill this in; it'll be used at the end of this function as well + CKKSCurrentKeySet* keyset = nil; - SecADSetValueForScalarKey((__bridge CFStringRef) SecCKKSAggdViewKeyCount, [localKeys count]); +#if !defined(NDEBUG) + { + NSError* localerror = nil; + NSError* allKeysError = nil; + NSArray* allKeys = [CKKSKey allKeys:self.zoneID error:&allKeysError]; - if(localerror) { - ckkserror("ckkskey", self, "couldn't fetch keys and OQEs from local database, entering error state: %@", localerror); - self.keyHierarchyState = SecCKKSZoneKeyStateError; - self.keyHierarchyError = localerror; - [self _onqueueHandleKeyStateNonTransientDependency:nil]; - return; + if(localerror) { + ckkserror("ckkskey", self, "couldn't fetch all keys from local database, entering error state: %@", allKeysError); + } + ckksdebug("ckkskey", self, "All keys: %@", allKeys); } - -#if !defined(NDEBUG) - NSArray* allKeys = [CKKSKey allKeys:self.zoneID error:&localerror]; - ckksdebug("ckkskey", self, "All keys: %@", allKeys); #endif NSError* hierarchyError = nil; @@ -1122,6 +1071,17 @@ } } else if([state isEqualToString: SecCKKSZoneKeyStateReady]) { + NSError* localerror = nil; + NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; + + if(remoteKeys == nil || localerror) { + ckkserror("ckkskey", self, "couldn't fetch keys from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(self.keyStateProcessRequested || [remoteKeys count] > 0) { // We've either received some remote keys from the last fetch, or someone has requested a reprocess. ckksnotice("ckkskey", self, "Kicking off a key reprocess based on request:%d and remote key count %lu", self.keyStateProcessRequested, (unsigned long)[remoteKeys count]); @@ -1149,6 +1109,7 @@ if(!self.keyStateMachineOperation && !nextState) { // We think we're ready. Double check. + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; CKKSZoneKeyState* checkedstate = [self _onqueueEnsureKeyHierarchyHealth:keyset error:&hierarchyError]; if(![checkedstate isEqualToString:SecCKKSZoneKeyStateReady] || hierarchyError) { // Things is bad. Kick off a heal to fix things up. @@ -1181,6 +1142,7 @@ nextState = SecCKKSZoneKeyStateWaitForFixupOperation; } else { // Check if we have an existing key hierarchy in keyset + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; if(keyset.error && !([keyset.error.domain isEqual: @"securityd"] && keyset.error.code == errSecItemNotFound)) { ckkserror("ckkskey", self, "Error examining existing key hierarchy: %@", error); } @@ -1209,7 +1171,9 @@ } else if([state isEqualToString: SecCKKSZoneKeyStateNeedFullRefetch]) { ckksnotice("ckkskey", self, "Starting a key hierarchy full refetch"); - [self _onqueueKeyHierarchyRefetch]; + [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithObjects:CKKSFetchBecauseKeyHierarchy, CKKSFetchBecauseResync, nil]]; + self.keyStateMachineRefetched = true; + self.keyStateFullRefetchRequested = false; } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForFixupOperation]) { // We should enter 'initialized' when the fixup operation completes @@ -1227,6 +1191,21 @@ } else if([state isEqualToString: SecCKKSZoneKeyStateFetchComplete]) { // We've just completed a fetch of everything. Are there any remote keys? + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + + NSError* localerror = nil; + + NSArray* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror]; + NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; + + if(localKeys == nil || remoteKeys == nil || localerror) { + ckkserror("ckkskey", self, "couldn't fetch keys from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(remoteKeys.count > 0u) { // Process the keys we received. self.keyStateMachineOperation = [[CKKSProcessReceivedKeysStateMachineOperation alloc] initWithCKKSKeychainView: self]; @@ -1274,6 +1253,7 @@ if(self.keyStateProcessRequested) { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; if(keyset.currentTLKPointer.currentKeyUUID) { ckksnotice("ckkskey", self, "Received a nudge that our TLK records might be here (and there's some current TLK pointer)"); nextState = SecCKKSZoneKeyStateProcess; @@ -1306,6 +1286,8 @@ self.trustedPeersSetChanged = false; } else { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + // Should we nuke this zone? if(self.trustStatus == CKKSAccountStatusAvailable) { if([self _onqueueOtherDevicesReportHavingTLKs:keyset]) { @@ -1369,6 +1351,8 @@ } else { ckkserror("ckks", self, "asked to advance state machine to unknown state: %@", state); self.keyHierarchyState = state; + + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; [self _onqueueHandleKeyStateNonTransientDependency:keyset]; return; } @@ -1387,6 +1371,17 @@ } // If there are any OQEs waiting to be encrypted, launch an op to fix them + NSError* localerror = nil; + NSInteger outdatedOQEs = [CKKSOutgoingQueueEntry countByState:SecCKKSStateReencrypt zone:self.zoneID error:&localerror]; + + if(localerror) { + ckkserror("ckkskey", self, "couldn't fetch OQEs from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(outdatedOQEs > 0) { ckksnotice("ckksreencrypt", self, "Reencrypting outgoing items as the key hierarchy is ready"); CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:self.keyHierarchyOperationGroup]; @@ -1433,6 +1428,11 @@ } } + // If the keystate is non-transient, ensure we've loaded the keyset, and provide it to any waiters + // If it is transient, just call the handler anyway: it needs to set up the dependency + if(!CKKSKeyStateTransient(self.keyHierarchyState) && keyset == nil) { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + } [self _onqueueHandleKeyStateNonTransientDependency:keyset]; } @@ -1992,31 +1992,11 @@ } - (void)_onqueueKeyHierarchyFetch { - dispatch_assert_queue(self.queue); - - WEAKIFY(self); - self.keyStateMachineOperation = [NSBlockOperation blockOperationWithBlock: ^{ - STRONGIFY(self); - if(!self) { - ckkserror("ckks", self, "received callback for released object"); - return; - } - [self.launch addEvent:@"fetch-complete"]; - - [self dispatchSyncWithAccountKeys: ^bool{ - [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; - return true; - }]; - }]; - self.keyStateMachineOperation.name = @"waiting-for-fetch"; - - NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetch: CKKSFetchBecauseKeyHierarchy]; - [self.keyStateMachineOperation addDependency: fetchOp]; - - self.keyStateFetchRequested = false; + [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithArray:@[CKKSFetchBecauseKeyHierarchy]]]; } -- (void)_onqueueKeyHierarchyRefetch { +- (void)_onqueueKeyHierarchyFetchForReasons:(NSSet*)reasons +{ dispatch_assert_queue(self.queue); WEAKIFY(self); @@ -2026,19 +2006,18 @@ ckkserror("ckks", self, "received callback for released object"); return; } + [self.launch addEvent:@"fetch-complete"]; [self dispatchSyncWithAccountKeys: ^bool{ [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; return true; }]; }]; - self.keyStateMachineOperation.name = @"waiting-for-refetch"; + self.keyStateMachineOperation.name = @"waiting-for-fetch"; - NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:[NSSet setWithObjects:CKKSFetchBecauseKeyHierarchy, CKKSFetchBecauseResync, nil]]; + NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:reasons]; [self.keyStateMachineOperation addDependency: fetchOp]; - self.keyStateMachineRefetched = true; - self.keyStateFullRefetchRequested = false; self.keyStateFetchRequested = false; } @@ -3649,48 +3628,31 @@ override:(bool)overridePeerProviders block:(bool (^)(void))block { - [SOSAccount performOnQuietAccountQueue: ^{ - NSArray>* actualPeerProviders = overridePeerProviders ? peerProviders : self.currentPeerProviders; - NSMutableArray* trustStates = [NSMutableArray array]; + NSArray>* actualPeerProviders = overridePeerProviders ? peerProviders : self.currentPeerProviders; + NSMutableArray* trustStates = [NSMutableArray array]; - for(id provider in actualPeerProviders) { - ckksnotice("ckks", self, "Fetching account keys for provider %@", provider); - - NSError* selfPeersError = nil; - CKKSSelves* currentSelfPeers = [provider fetchSelfPeers:&selfPeersError]; - - NSError* trustedPeersError = nil; - NSSet>* currentTrustedPeers = [provider fetchTrustedPeers:&trustedPeersError]; + for(id provider in actualPeerProviders) { + ckksnotice("ckks", self, "Fetching account keys for provider %@", provider); + [trustStates addObject:provider.currentState]; + } - [trustStates addObject:[[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID - essential:provider.essential - selfPeers:currentSelfPeers - selfPeersError:selfPeersError - trustedPeers:currentTrustedPeers - trustedPeersError:trustedPeersError]]; + [self dispatchSync:^bool{ + if(overridePeerProviders) { + self.currentPeerProviders = peerProviders; } + self.currentTrustStates = trustStates; - [self dispatchSync:^bool{ - if(overridePeerProviders) { - self.currentPeerProviders = peerProviders; - } - self.currentTrustStates = trustStates; - - __block bool result = false; - [SOSAccount performWhileHoldingAccountQueue:^{ // so any calls through SOS account will know they can perform their work without dispatching to the account queue, which we already hold - result = block(); - }]; + bool result = block(); - // Forget the peers; they might have class A key material - NSMutableArray* noTrustStates = [NSMutableArray array]; - for(id provider in peerProviders) { - (void)provider; - [noTrustStates addObject:[CKKSPeerProviderState noPeersState:provider]]; - } - self.currentTrustStates = noTrustStates; + // Forget the peers; they might have class A key material + NSMutableArray* noTrustStates = [NSMutableArray array]; + for(id provider in peerProviders) { + (void)provider; + [noTrustStates addObject:[CKKSPeerProviderState noPeersState:provider]]; + } + self.currentTrustStates = noTrustStates; - return result; - }]; + return result; }]; } @@ -3868,6 +3830,7 @@ // We want to return a nil change tag (to force a resync) ckksnotice("ckksfetch", self, "Beginning refetch"); request.changeToken = nil; + request.resync = true; } else { CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName]; if(!ckse) { @@ -3888,16 +3851,13 @@ - (void)changesFetched:(NSArray*)changedRecords deletedRecordIDs:(NSArray*)deletedRecords - oldChangeToken:(CKServerChangeToken*)oldChangeToken newChangeToken:(CKServerChangeToken*)newChangeToken + moreComing:(BOOL)moreComing + resync:(BOOL)resync { [self.launch addEvent:@"changes-fetched"]; [self dispatchSyncWithAccountKeys:^bool{ - // This is a resync if we already have a change token, but this fetch didn't have one - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - bool resync = ckse.changeToken && (oldChangeToken == nil); - for (CKRecord* record in changedRecords) { [self _onqueueCKRecordChanged:record resync:resync]; } @@ -3908,51 +3868,67 @@ NSError* error = nil; if(resync) { - // Scan through all CKMirrorEntries and determine if any exist that CloudKit didn't tell us about - ckksnotice("ckksresync", self, "Comparing local UUIDs against the CloudKit list"); - NSMutableArray* uuids = [[CKKSMirrorEntry allUUIDs:self.zoneID error:&error] mutableCopy]; - - for(NSString* uuid in uuids) { - CKRecord* record = nil; - CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:uuid zoneID:self.zoneID]; - for(CKRecord* r in changedRecords) { - if([r.recordID isEqual:recordID]) { - record = r; - break; - } - } + // If we're performing a resync, we need to keep track of everything that's actively in + // CloudKit during the fetch, (so that we can find anything that's on-disk and not in CloudKit). + // Please note that if, during a resync, the fetch errors, we won't be notified. If a record is in + // the first refetch but not the second, it'll be added to our set, and the second resync will not + // delete the record (which is a consistency violation, but only with actively changing records). + // A third resync should correctly delete that record. + + if(self.resyncRecordsSeen == nil) { + self.resyncRecordsSeen = [NSMutableSet set]; + } + for(CKRecord* r in changedRecords) { + [self.resyncRecordsSeen addObject:r.recordID.recordName]; + } - if(record) { - ckksnotice("ckksresync", self, "UUID %@ is still in CloudKit; carry on.", uuid); - } else { - CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:self.zoneID error:&error]; - if(error != nil) { - ckkserror("ckksresync", self, "Couldn't read an item from the database, but it used to be there: %@ %@", uuid, error); - continue; - } - if(!ckme) { - ckkserror("ckksresync", self, "Couldn't read ckme(%@) from database; continuing", uuid); - continue; - } + // Is there More Coming? If not, self.resyncRecordsSeen contains everything in CloudKit. Inspect for anything extra! + if(moreComing) { + ckksnotice("ckksresync", self, "In a resync, but there's More Coming. Waiting to scan for extra items."); - ckkserror("ckksresync", self, "BUG: Local item %@ not found in CloudKit, deleting", uuid); - [self _onqueueCKRecordDeleted:ckme.item.storedCKRecord.recordID recordType:ckme.item.storedCKRecord.recordType resync:resync]; + } else { + // Scan through all CKMirrorEntries and determine if any exist that CloudKit didn't tell us about + ckksnotice("ckksresync", self, "Comparing local UUIDs against the CloudKit list"); + NSMutableArray* uuids = [[CKKSMirrorEntry allUUIDs:self.zoneID error:&error] mutableCopy]; + + for(NSString* uuid in uuids) { + if([self.resyncRecordsSeen containsObject:uuid]) { + ckksnotice("ckksresync", self, "UUID %@ is still in CloudKit; carry on.", uuid); + } else { + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:self.zoneID error:&error]; + if(error != nil) { + ckkserror("ckksresync", self, "Couldn't read an item from the database, but it used to be there: %@ %@", uuid, error); + continue; + } + if(!ckme) { + ckkserror("ckksresync", self, "Couldn't read ckme(%@) from database; continuing", uuid); + continue; + } + + ckkserror("ckksresync", self, "BUG: Local item %@ not found in CloudKit, deleting", uuid); + [self _onqueueCKRecordDeleted:ckme.item.storedCKRecord.recordID recordType:ckme.item.storedCKRecord.recordType resync:resync]; + } } + + // Now that we've inspected resyncRecordsSeen, reset it for the next time through + self.resyncRecordsSeen = nil; } } - error = nil; - CKKSZoneStateEntry* state = [CKKSZoneStateEntry state:self.zoneName]; state.lastFetchTime = [NSDate date]; // The last fetch happened right now! state.changeToken = newChangeToken; + state.moreRecordsInCloudKit = moreComing; [state saveToDatabase:&error]; if(error) { ckkserror("ckksfetch", self, "Couldn't save new server change token: %@", error); } - // Might as well kick off a IQO! - [self processIncomingQueue:false]; + if(!moreComing) { + // Might as well kick off a IQO! + [self processIncomingQueue:false]; + ckksnotice("ckksfetch", self, "Beginning incoming processing for %@", self.zoneID); + } ckksnotice("ckksfetch", self, "Finished processing changes for %@", self.zoneID); diff --git a/keychain/ckks/CKKSManifest.m b/keychain/ckks/CKKSManifest.m index 38ab0eb5..0d7f5562 100644 --- a/keychain/ckks/CKKSManifest.m +++ b/keychain/ckks/CKKSManifest.m @@ -29,8 +29,8 @@ #import "CKKSItem.h" #import "CKKSCurrentItemPointer.h" #import "utilities/der_plist.h" -#import -#import +#import "keychain/securityd/SOSCloudCircleServer.h" +#import "keychain/securityd/SecItemServer.h" #import #import #import diff --git a/keychain/ckks/CKKSMirrorEntry.h b/keychain/ckks/CKKSMirrorEntry.h index dcaf1fbe..17839f25 100644 --- a/keychain/ckks/CKKSMirrorEntry.h +++ b/keychain/ckks/CKKSMirrorEntry.h @@ -23,7 +23,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSSQLDatabaseObject.h" diff --git a/keychain/ckks/CKKSMirrorEntry.m b/keychain/ckks/CKKSMirrorEntry.m index e77c3043..59900f08 100644 --- a/keychain/ckks/CKKSMirrorEntry.m +++ b/keychain/ckks/CKKSMirrorEntry.m @@ -30,8 +30,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import diff --git a/keychain/ckks/CKKSNearFutureScheduler.h b/keychain/ckks/CKKSNearFutureScheduler.h index 44c3e9c3..e84f7f59 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.h +++ b/keychain/ckks/CKKSNearFutureScheduler.h @@ -62,6 +62,14 @@ NS_ASSUME_NONNULL_BEGIN dependencyDescriptionCode:(NSInteger)code block:(void (^_Nonnull)(void))futureBlock; +- (instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + expontialBackoff:(double)backoff + maximumDelay:(dispatch_time_t)maximumDelay + keepProcessAlive:(bool)keepProcessAlive + dependencyDescriptionCode:(NSInteger)code + block:(void (^_Nonnull)(void))futureBlock; + - (void)trigger; - (void)cancel; diff --git a/keychain/ckks/CKKSNearFutureScheduler.m b/keychain/ckks/CKKSNearFutureScheduler.m index 2b3fb6b0..815b2197 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.m +++ b/keychain/ckks/CKKSNearFutureScheduler.m @@ -33,7 +33,11 @@ @interface CKKSNearFutureScheduler () @property NSString* name; @property dispatch_time_t initialDelay; -@property dispatch_time_t continuingDelay; + +@property dispatch_time_t currentDelay; +@property dispatch_time_t maximumDelay; + +@property double backoff; @property NSInteger operationDependencyDescriptionCode; @property CKKSResultOperation* operationDependency; @@ -72,13 +76,36 @@ keepProcessAlive:(bool)keepProcessAlive dependencyDescriptionCode:(NSInteger)code block:(void (^)(void))futureBlock +{ + // If the continuing delay is below the initial delay, use an exponential backoff of 1 + // We'll clamp the timer delay to continuing delay at use time. + return [self initWithName:name + initialDelay:initialDelay + expontialBackoff:MAX(initialDelay > 0 ? (continuingDelay / initialDelay) : 1, 1) + maximumDelay:continuingDelay + keepProcessAlive:keepProcessAlive + dependencyDescriptionCode:code + block:futureBlock]; +} + +- (instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + expontialBackoff:(double)backoff + maximumDelay:(dispatch_time_t)maximumDelay + keepProcessAlive:(bool)keepProcessAlive +dependencyDescriptionCode:(NSInteger)code + block:(void (^_Nonnull)(void))futureBlock { if((self = [super init])) { _name = name; _queue = dispatch_queue_create([[NSString stringWithFormat:@"near-future-scheduler-%@",name] UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); _initialDelay = initialDelay; - _continuingDelay = continuingDelay; + + _currentDelay = initialDelay; + _maximumDelay = maximumDelay; + _backoff = backoff; + _futureBlock = futureBlock; _liveRequest = false; @@ -98,7 +125,9 @@ { dispatch_sync(self.queue, ^{ self.initialDelay = initialDelay; - self.continuingDelay = continuingDelay; + self.currentDelay = self.initialDelay; + self.backoff = initialDelay > 0 ? ((double)continuingDelay) / initialDelay : 1; + self.maximumDelay = continuingDelay; }); } @@ -159,13 +188,26 @@ self.liveRequestReceived = [[CKKSCondition alloc] init]; self.transaction = nil; + // No current delay means that exponential backoff means nothing. Head straight for slowtown. + if(self.currentDelay == 0) { + self.currentDelay = self.maximumDelay; + } else { + // Modify the delay by the exponential backoff, unless that exceeds the maximum delay + self.currentDelay = MIN(self.currentDelay * self.backoff, self.maximumDelay); + } + dispatch_source_set_timer(self.timer, + dispatch_walltime(NULL, self.currentDelay), + self.currentDelay, + 50 * NSEC_PER_MSEC); + [self.operationQueue addOperation: dependency]; - self.predictedNextFireTime = [NSDate dateWithTimeIntervalSinceNow: (NSTimeInterval) ((double) self.continuingDelay) / (double) NSEC_PER_SEC]; + self.predictedNextFireTime = [NSDate dateWithTimeIntervalSinceNow: (NSTimeInterval) ((double) self.currentDelay) / (double) NSEC_PER_SEC]; } else { // The timer has fired with no requests to call the block. Cancel it. dispatch_source_cancel(self.timer); self.predictedNextFireTime = nil; + self.currentDelay = self.initialDelay; } } @@ -226,7 +268,7 @@ [self _onqueueTimerTick]; }); - dispatch_time_t actualDelay = self.initialDelay; + dispatch_time_t actualDelay = self.currentDelay; if(requestedDelay != DISPATCH_TIME_NOW) { actualDelay = MAX(actualDelay, requestedDelay); } @@ -234,9 +276,11 @@ actualDelay = MIN(actualDelay, maximumDelay); } + // Note: we pass initialDelay in as the timerInterval here. [-_onqueueTimerTick] is responsible for + // modifying the delay to be correct for the next time period. dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, actualDelay), - self.continuingDelay, + self.currentDelay, 50 * NSEC_PER_MSEC); dispatch_resume(self.timer); diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.h b/keychain/ckks/CKKSOutgoingQueueEntry.h index 05e6a00c..dd7b00d4 100644 --- a/keychain/ckks/CKKSOutgoingQueueEntry.h +++ b/keychain/ckks/CKKSOutgoingQueueEntry.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSMirrorEntry.h" diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.m b/keychain/ckks/CKKSOutgoingQueueEntry.m index 7ebfd83d..4097edd9 100644 --- a/keychain/ckks/CKKSOutgoingQueueEntry.m +++ b/keychain/ckks/CKKSOutgoingQueueEntry.m @@ -30,8 +30,8 @@ #include #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON diff --git a/keychain/ckks/CKKSOutgoingQueueOperation.m b/keychain/ckks/CKKSOutgoingQueueOperation.m index 3cd1e853..c1d3810d 100644 --- a/keychain/ckks/CKKSOutgoingQueueOperation.m +++ b/keychain/ckks/CKKSOutgoingQueueOperation.m @@ -37,8 +37,8 @@ #import "CKKSAnalytics.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include #import "CKKSPowerCollection.h" diff --git a/keychain/ckks/CKKSPeer.h b/keychain/ckks/CKKSPeer.h index 1270faa5..2d05fc3f 100644 --- a/keychain/ckks/CKKSPeer.h +++ b/keychain/ckks/CKKSPeer.h @@ -57,29 +57,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCurrent:(id)selfPeer allSelves:(NSSet>* _Nullable)allSelves; @end -// ==== Peer handler protocols ==== - -@protocol CKKSPeerUpdateListener; - -@protocol CKKSPeerProvider -@property (readonly) NSString* providerID; -@property BOOL essential; - -- (CKKSSelves* _Nullable)fetchSelfPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; -- (NSSet>* _Nullable)fetchTrustedPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; -// Trusted peers should include self peers - -- (void)registerForPeerChangeUpdates:(id)listener; -- (void)sendSelfPeerChangedUpdate; -- (void)sendTrustedPeerSetChangedUpdate; -@end - -// A CKKSPeerUpdateListener wants to be notified when a CKKSPeerProvider has new information -@protocol CKKSPeerUpdateListener -- (void)selfPeerChanged:(id _Nullable)provider; -- (void)trustedPeerSetChanged:(id _Nullable)provider; -@end - extern NSString* const CKKSSOSPeerPrefix; @interface CKKSActualPeer : NSObject diff --git a/keychain/ckks/CKKSPeerProvider.h b/keychain/ckks/CKKSPeerProvider.h new file mode 100644 index 00000000..6811e63c --- /dev/null +++ b/keychain/ckks/CKKSPeerProvider.h @@ -0,0 +1,69 @@ +#if OCTAGON + +#import +#import "keychain/ckks/CKKSPeer.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol CKKSPeerUpdateListener; +@class CKKSPeerProviderState; + +#pragma mark - CKKSPeerProvider protocol +@protocol CKKSPeerProvider +@property (readonly) NSString* providerID; +@property BOOL essential; + +- (CKKSSelves* _Nullable)fetchSelfPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; +- (NSSet>* _Nullable)fetchTrustedPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; +// Trusted peers should include self peers + +- (void)registerForPeerChangeUpdates:(id)listener; +- (void)sendSelfPeerChangedUpdate; +- (void)sendTrustedPeerSetChangedUpdate; + +- (CKKSPeerProviderState*)currentState; +@end + +#pragma mark - CKKSPeerUpdateListener protocol +// A CKKSPeerUpdateListener wants to be notified when a CKKSPeerProvider has new information +@protocol CKKSPeerUpdateListener +- (void)selfPeerChanged:(id _Nullable)provider; +- (void)trustedPeerSetChanged:(id _Nullable)provider; +@end + + +#pragma mark - CKKSPeerProviderState + +@interface CKKSPeerProviderState : NSObject +@property NSString* peerProviderID; + +// The peer provider believes trust in this state is essential. Any subsystem using +// a peer provider state should fail and pause if this is YES and there are trust errors. +@property BOOL essential; + +@property (nonatomic, readonly, nullable) CKKSSelves* currentSelfPeers; +@property (nonatomic, readonly, nullable) NSError* currentSelfPeersError; +@property (nonatomic, readonly, nullable) NSSet>* currentTrustedPeers; +@property (nonatomic, readonly, nullable) NSSet* currentTrustedPeerIDs; +@property (nonatomic, readonly, nullable) NSError* currentTrustedPeersError; + +- (instancetype)initWithPeerProviderID:(NSString*)providerID + essential:(BOOL)essential + selfPeers:(CKKSSelves* _Nullable)selfPeers + selfPeersError:(NSError* _Nullable)selfPeersError + trustedPeers:(NSSet>* _Nullable)currentTrustedPeers + trustedPeersError:(NSError* _Nullable)trustedPeersError; + ++ (CKKSPeerProviderState*)noPeersState:(id)provider; + +// Intended for use in PeerProviders. Thread-safety is up to the PeerProvider. ++ (CKKSPeerProviderState*)createFromProvider:(id)provider; +@end + + + + +NS_ASSUME_NONNULL_END + + +#endif diff --git a/keychain/ckks/CKKSPeerProvider.m b/keychain/ckks/CKKSPeerProvider.m new file mode 100644 index 00000000..f773204d --- /dev/null +++ b/keychain/ckks/CKKSPeerProvider.m @@ -0,0 +1,76 @@ +#if OCTAGON +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSPeerProvider.h" +#import "keychain/categories/NSError+UsefulConstructors.h" + +@implementation CKKSPeerProviderState +- (instancetype)initWithPeerProviderID:(NSString*)providerID + essential:(BOOL)essential + selfPeers:(CKKSSelves* _Nullable)selfPeers + selfPeersError:(NSError* _Nullable)selfPeersError + trustedPeers:(NSSet>* _Nullable)currentTrustedPeers + trustedPeersError:(NSError* _Nullable)trustedPeersError +{ + if((self = [super init])) { + _peerProviderID = providerID; + _essential = essential; + _currentSelfPeers = selfPeers; + _currentSelfPeersError = selfPeersError; + _currentTrustedPeers = currentTrustedPeers; + _currentTrustedPeersError = trustedPeersError; + + if(_currentTrustedPeers) { + NSMutableSet* trustedPeerIDs = [NSMutableSet set]; + for(id peer in _currentTrustedPeers) { + [trustedPeerIDs addObject:peer.peerID]; + } + _currentTrustedPeerIDs = trustedPeerIDs; + } + } + return self; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"", + self.peerProviderID, + self.currentSelfPeers, + self.currentSelfPeersError ?: @"", + self.currentTrustedPeers, + self.currentTrustedPeersError ?: @""]; +} + ++ (CKKSPeerProviderState*)noPeersState:(id)provider +{ + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID + essential:provider.essential + selfPeers:nil + selfPeersError:[NSError errorWithDomain:CKKSErrorDomain + code:CKKSNoPeersAvailable + description:@"No current self peer available"] + trustedPeers:nil + trustedPeersError:[NSError errorWithDomain:CKKSErrorDomain + code:CKKSNoPeersAvailable + description:@"No current trusted peers available"]]; +} + + ++ (CKKSPeerProviderState*)createFromProvider:(id)provider +{ + NSError* selfPeersError = nil; + CKKSSelves* currentSelfPeers = [provider fetchSelfPeers:&selfPeersError]; + + NSError* trustedPeersError = nil; + NSSet>* currentTrustedPeers = [provider fetchTrustedPeers:&trustedPeersError]; + + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID + essential:provider.essential + selfPeers:currentSelfPeers + selfPeersError:selfPeersError + trustedPeers:currentTrustedPeers + trustedPeersError:trustedPeersError]; +} +@end + +#endif + diff --git a/keychain/ckks/CKKSRecordHolder.h b/keychain/ckks/CKKSRecordHolder.h index 5c52de66..72d0eee3 100644 --- a/keychain/ckks/CKKSRecordHolder.h +++ b/keychain/ckks/CKKSRecordHolder.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKSSQLDatabaseObject.h" diff --git a/keychain/ckks/CKKSRecordHolder.m b/keychain/ckks/CKKSRecordHolder.m index 6d424fa6..bb9db913 100644 --- a/keychain/ckks/CKKSRecordHolder.m +++ b/keychain/ckks/CKKSRecordHolder.m @@ -31,8 +31,8 @@ #import "CKKSSIV.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import diff --git a/keychain/ckks/CKKSSQLDatabaseObject.h b/keychain/ckks/CKKSSQLDatabaseObject.h index 976404b5..85f6ad5c 100644 --- a/keychain/ckks/CKKSSQLDatabaseObject.h +++ b/keychain/ckks/CKKSSQLDatabaseObject.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #define CKKSNilToNSNull(obj) \ diff --git a/keychain/ckks/CKKSSQLDatabaseObject.m b/keychain/ckks/CKKSSQLDatabaseObject.m index 6313ac65..356424cc 100644 --- a/keychain/ckks/CKKSSQLDatabaseObject.m +++ b/keychain/ckks/CKKSSQLDatabaseObject.m @@ -23,7 +23,7 @@ #import #import "CKKSSQLDatabaseObject.h" -#include +#include "keychain/securityd/SecItemServer.h" #import "keychain/ckks/CKKS.h" #import "CKKSKeychainView.h" diff --git a/keychain/ckks/CKKSScanLocalItemsOperation.m b/keychain/ckks/CKKSScanLocalItemsOperation.m index 6c4fe803..7d285ad6 100644 --- a/keychain/ckks/CKKSScanLocalItemsOperation.m +++ b/keychain/ckks/CKKSScanLocalItemsOperation.m @@ -38,9 +38,9 @@ #import "CKKSPowerCollection.h" -#include -#include -#include +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include #import diff --git a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m index aeb57d81..00080ba2 100644 --- a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m +++ b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m @@ -33,11 +33,11 @@ #import "keychain/categories/NSError+UsefulConstructors.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemDb.h" #include -#include +#include "keychain/securityd/SecDbQuery.h" #import @interface CKKSUpdateCurrentItemPointerOperation () diff --git a/keychain/ckks/CKKSViewManager.h b/keychain/ckks/CKKSViewManager.h index 82c8ac34..cd6ac8cd 100644 --- a/keychain/ckks/CKKSViewManager.h +++ b/keychain/ckks/CKKSViewManager.h @@ -26,7 +26,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/OctagonAPSReceiver.h" #import "keychain/ckks/CKKSAccountStateTracker.h" @@ -141,6 +141,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)notifyNewTLKsInKeychain; - (void)syncBackupAndNotifyAboutSync; +// allow user blocking operation to block on trust status trying to sort it-self out the +// first time after launch, only waits the the initial call +- (BOOL)waitForTrustReady; + // For testing - (void)setOverrideCKKSViewsFromPolicy:(BOOL)value; - (BOOL)useCKKSViewsFromPolicy; diff --git a/keychain/ckks/CKKSViewManager.m b/keychain/ckks/CKKSViewManager.m index 1db3c5df..8a226dfc 100644 --- a/keychain/ckks/CKKSViewManager.m +++ b/keychain/ckks/CKKSViewManager.m @@ -37,6 +37,7 @@ #import "keychain/analytics/SecEventMetric.h" #import "keychain/analytics/SecMetrics.h" +#import "keychain/ot/OTManager.h" #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTConstants.h" #import "keychain/ot/ObjCImprovements.h" @@ -45,9 +46,9 @@ #import "SecEntitlements.h" -#include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemSchema.h" #include #import @@ -157,6 +158,18 @@ NSSet* _viewList; return container; } +- (BOOL)waitForTrustReady { + static dispatch_once_t onceToken; + __block BOOL success = YES; + dispatch_once(&onceToken, ^{ + OTManager* manager = [OTManager manager]; + if (![manager waitForReady:OTCKContainerName context:OTDefaultContext wait:3*NSEC_PER_SEC]) { + success = NO; + } + }); + return success; +} + - (void)setupAnalytics { WEAKIFY(self); @@ -883,6 +896,7 @@ dispatch_once_t globalZoneStateQueueOnce; [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC]; NSString *deviceID = self.accountTracker.ckdeviceID; NSError *deviceIDError = self.accountTracker.ckdeviceIDError; + NSDate *lastCKKSPush = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastCKKSPush]; #define stringify(obj) CKKSNilToNSNull([obj description]) NSDictionary* global = @{ @@ -892,6 +906,7 @@ dispatch_once_t globalZoneStateQueueOnce; @"ckdeviceIDError": CKKSNilToNSNull(deviceIDError), @"lockstatetracker": stringify(self.lockStateTracker), @"cloudkitRetryAfter": stringify(self.zoneModifier.cloudkitRetryAfter), + @"lastCKKSPush": CKKSNilToNSNull(lastCKKSPush), }; [a addObject: global]; } @@ -918,6 +933,10 @@ dispatch_once_t globalZoneStateQueueOnce; } if(self.accountTracker.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) { + if (![self waitForTrustReady]) { + secerror("ckks status: Haven't yet figured out trust status"); + } + CKKSResultOperation* blockOp = [CKKSResultOperation named:@"wait-for-status" withBlock:^{}]; [blockOp timeout:8*NSEC_PER_SEC]; for(CKKSKeychainView* view in actualViews) { @@ -1028,6 +1047,11 @@ dispatch_once_t globalZoneStateQueueOnce; -(void)xpc24HrNotification { // XPC has poked us and said we should do some cleanup! + secnotice("ckks", "Received a 24hr notification from XPC"); + + if (![self waitForTrustReady]) { + secnotice("ckks", "Trust not ready, still going ahead"); + } [[CKKSAnalytics logger] dailyCoreAnalyticsMetrics:@"com.apple.security.CKKSHealthSummary"]; @@ -1038,7 +1062,6 @@ dispatch_once_t globalZoneStateQueueOnce; actualViews = self.views.allValues; } - secnotice("ckks", "Received a 24hr notification from XPC"); CKOperationGroup* group = [CKOperationGroup CKKSGroupWithName:@"periodic-device-state-update"]; for(CKKSKeychainView* view in actualViews) { ckksnotice("ckks", view, "Starting device state XPC update"); diff --git a/keychain/ckks/CKKSZoneChangeFetcher.h b/keychain/ckks/CKKSZoneChangeFetcher.h index 80cdc654..d1e60c14 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.h +++ b/keychain/ckks/CKKSZoneChangeFetcher.h @@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithContainer:(CKContainer*)container - fetchClass:(Class)fetchRecordsOperationClass + fetchClass:(Class)fetchRecordZoneChangesOperationClass reachabilityTracker:(CKKSReachabilityTracker *)reachabilityTracker; - (void)registerClient:(id)client; diff --git a/keychain/ckks/CKKSZoneChangeFetcher.m b/keychain/ckks/CKKSZoneChangeFetcher.m index 8b9fe2f5..0ec4cff4 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.m +++ b/keychain/ckks/CKKSZoneChangeFetcher.m @@ -52,7 +52,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- #pragma mark - CKKSZoneChangeFetchDependencyOperation @interface CKKSZoneChangeFetchDependencyOperation : CKKSResultOperation -@property CKKSZoneChangeFetcher* owner; +@property (weak) CKKSZoneChangeFetcher* owner; @property NSMutableArray* chainDependents; - (void)chainDependency:(CKKSZoneChangeFetchDependencyOperation*)newDependency; @end @@ -130,16 +130,17 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- _newRequests = false; - // If we're testing, for the initial delay, use 0.2 second. Otherwise, 2s. - dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 200 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); + // If we're testing, for the initial delay, use 0.25 second. Otherwise, 2s. + dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 250 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); - // If we're testing, for the continuing delay, use 2 second. Otherwise, 30s. - dispatch_time_t continuingDelay = (SecCKKSReduceRateLimiting() ? 2 * NSEC_PER_SEC : 30 * NSEC_PER_SEC); + // If we're testing, for the maximum delay, use 6 second. Otherwise, 2m. + dispatch_time_t maximumDelay = (SecCKKSReduceRateLimiting() ? 6 * NSEC_PER_SEC : 120 * NSEC_PER_SEC); WEAKIFY(self); _fetchScheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"zone-change-fetch-scheduler" initialDelay:initialDelay - continuingDelay:continuingDelay + expontialBackoff:2 + maximumDelay:maximumDelay keepProcessAlive:false dependencyDescriptionCode:CKKSResultDescriptionPendingZoneChangeFetchScheduling block:^{ @@ -308,25 +309,14 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- dispatch_sync(self.queue, ^{ self.lastCKFetchError = fetchAllChanges.error; - if(!fetchAllChanges.error) { - if (attemptAnotherFetch) { - [dependency chainDependency:self.successfulFetchDependency]; - [self.operationQueue addOperation: dependency]; - - [self.currentFetchReasons unionSet:lastFetchReasons]; - [self.apnsPushes unionSet:lastAPNSPushes]; + if(fetchAllChanges.error == nil) { + // success! notify the listeners. + [self.operationQueue addOperation: dependency]; + self.currentFetch = nil; - self.newRequests = true; + // Did new people show up and want another fetch? + if(self.newRequests) { [self.fetchScheduler trigger]; - } else { - // success! notify the listeners. - [self.operationQueue addOperation: dependency]; - self.currentFetch = nil; - - // Did new people show up and want another fetch? - if(self.newRequests) { - [self.fetchScheduler trigger]; - } } } else { // The operation errored. Chain the dependency on the current one... diff --git a/keychain/ckks/CKKSZoneModifier.m b/keychain/ckks/CKKSZoneModifier.m index 66d5d134..d8afc74b 100644 --- a/keychain/ckks/CKKSZoneModifier.m +++ b/keychain/ckks/CKKSZoneModifier.m @@ -99,9 +99,11 @@ if(!self.pendingOperations) { CKKSResultOperation* zoneModificationOperationDependency = [CKKSResultOperation named:@"zone-modification" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) { + secnotice("ckkszonemodifier", "finished creating zones"); }]; CKKSResultOperation* zoneSubscriptionOperationDependency = [CKKSResultOperation named:@"zone-subscription" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) { + secnotice("ckkszonemodifier", "finished subscribing to zones"); }]; self.pendingOperations = [[CKKSZoneModifyOperations alloc] initWithZoneModificationOperation:zoneModificationOperationDependency @@ -244,6 +246,8 @@ - (CKDatabaseOperation* _Nullable)createModifySubscriptionsOperation:(CKKSZoneModifyOperations*)ops { + secnotice("ckkszonemodifier", "Attempting to subscribe to zones %@", ops.subscriptionsToSubscribe); + if(ops.subscriptionsToSubscribe.count == 0) { [self.operationQueue addOperation: ops.zoneSubscriptionOperation]; return nil; @@ -258,10 +262,6 @@ zoneSubscriptionOperation.database = self.database; zoneSubscriptionOperation.name = @"zone-subscription-operation"; - // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. - NSBlockOperation* zoneSubscriptionCompleteOperation = [[NSBlockOperation alloc] init]; - zoneSubscriptionCompleteOperation.name = @"zone-subscription-complete"; - WEAKIFY(self); zoneSubscriptionOperation.modifySubscriptionsCompletionBlock = ^(NSArray * _Nullable savedSubscriptions, NSArray * _Nullable deletedSubscriptionIDs, diff --git a/keychain/ckks/CKKSZoneStateEntry.h b/keychain/ckks/CKKSZoneStateEntry.h index fb44ce17..27213bca 100644 --- a/keychain/ckks/CKKSZoneStateEntry.h +++ b/keychain/ckks/CKKSZoneStateEntry.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSSQLDatabaseObject.h" @@ -55,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN @property bool ckzonesubscribed; @property (nullable, getter=getChangeToken, setter=setChangeToken:) CKServerChangeToken* changeToken; @property (nullable) NSData* encodedChangeToken; +@property BOOL moreRecordsInCloudKit; @property (nullable) NSDate* lastFetchTime; @property CKKSFixup lastFixup; @@ -71,6 +72,7 @@ NS_ASSUME_NONNULL_BEGIN zoneCreated:(bool)ckzonecreated zoneSubscribed:(bool)ckzonesubscribed changeToken:(NSData* _Nullable)changetoken + moreRecordsInCloudKit:(BOOL)moreRecords lastFetch:(NSDate* _Nullable)lastFetch lastFixup:(CKKSFixup)lastFixup encodedRateLimiter:(NSData* _Nullable)encodedRateLimiter; diff --git a/keychain/ckks/CKKSZoneStateEntry.m b/keychain/ckks/CKKSZoneStateEntry.m index bb03f474..f835d9ab 100644 --- a/keychain/ckks/CKKSZoneStateEntry.m +++ b/keychain/ckks/CKKSZoneStateEntry.m @@ -29,8 +29,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON @@ -46,6 +46,7 @@ zoneCreated:(bool)ckzonecreated zoneSubscribed:(bool)ckzonesubscribed changeToken:(NSData*)changetoken + moreRecordsInCloudKit:(BOOL)moreRecords lastFetch:(NSDate*)lastFetch lastFixup:(CKKSFixup)lastFixup encodedRateLimiter:(NSData*)encodedRateLimiter @@ -55,6 +56,7 @@ _ckzonecreated = ckzonecreated; _ckzonesubscribed = ckzonesubscribed; _encodedChangeToken = changetoken; + _moreRecordsInCloudKit = moreRecords; _lastFetchTime = lastFetch; _lastFixup = lastFixup; @@ -74,6 +76,7 @@ self.ckzonecreated == obj.ckzonecreated && self.ckzonesubscribed == obj.ckzonesubscribed && ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) && + self.moreRecordsInCloudKit == obj.moreRecordsInCloudKit && ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) && ((self.rateLimiter == nil && obj.rateLimiter == nil) || [self.rateLimiter isEqual: obj.rateLimiter]) && self.lastFixup == obj.lastFixup && @@ -93,6 +96,7 @@ zoneCreated:false zoneSubscribed:false changeToken:nil + moreRecordsInCloudKit:NO lastFetch:nil lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:nil]; @@ -147,7 +151,7 @@ } + (NSArray*) sqlColumns { - return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup"]; + return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup", @"morecoming"]; } - (NSDictionary*) whereClauseToFindSelf { @@ -164,6 +168,7 @@ @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil), @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]), @"lastFixup": [NSNumber numberWithLong:self.lastFixup], + @"morecoming": [NSNumber numberWithBool:self.moreRecordsInCloudKit], }; } @@ -172,6 +177,7 @@ zoneCreated:row[@"ckzonecreated"].asBOOL zoneSubscribed:row[@"ckzonesubscribed"].asBOOL changeToken:row[@"changetoken"].asBase64DecodedData + moreRecordsInCloudKit:row[@"morecoming"].asBOOL lastFetch:row[@"lastfetch"].asISO8601Date lastFixup:(CKKSFixup)row[@"lastFixup"].asNSInteger encodedRateLimiter:row[@"ratelimiter"].asBase64DecodedData diff --git a/keychain/ckks/CloudKitCategories.h b/keychain/ckks/CloudKitCategories.h index 45fad55a..2bf92f57 100644 --- a/keychain/ckks/CloudKitCategories.h +++ b/keychain/ckks/CloudKitCategories.h @@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN // 2) Every single suberror is either CKErrorServerRecordChanged or CKErrorUnknownItem - (bool)ckksIsCKErrorRecordChangedError; - (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishError; +- (NSTimeInterval)cuttlefishRetryAfter; @end // Ensure we don't print addresses @interface CKAccountInfo (CKKS) diff --git a/keychain/ckks/CloudKitCategories.m b/keychain/ckks/CloudKitCategories.m index ed46d93d..22f57597 100644 --- a/keychain/ckks/CloudKitCategories.m +++ b/keychain/ckks/CloudKitCategories.m @@ -54,30 +54,43 @@ return false; } -- (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishError +- (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishErrorCode { NSError *error = self; - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - // This funny code is becase CodeOperation was not wrapping underlying errors with CKError, and then they fixed that in - // if you find this code, it probably time to always check for CKErrorDomain/CKErrorServerRejectedRequest - if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest && underlyingError) { - error = underlyingError; - } - - if([error.domain isEqualToString:CKInternalErrorDomain] && error.code == CKErrorInternalPluginError) { + if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest) { NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - if(underlyingError && - [underlyingError.domain isEqualToString:CuttlefishErrorDomain] && - underlyingError.code == cuttlefishError) { - return YES; + + if([underlyingError.domain isEqualToString:CKInternalErrorDomain] && underlyingError.code == CKErrorInternalPluginError) { + NSError* cuttlefishError = underlyingError.userInfo[NSUnderlyingErrorKey]; + + if([cuttlefishError.domain isEqualToString:CuttlefishErrorDomain] && cuttlefishError.code == cuttlefishErrorCode) { + return YES; + } } } return NO; } +- (NSTimeInterval)cuttlefishRetryAfter { + NSError *error = self; + + if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest) { + NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; + if([underlyingError.domain isEqualToString:CKInternalErrorDomain] && underlyingError.code == CKErrorInternalPluginError) { + NSError* cuttlefishError = underlyingError.userInfo[NSUnderlyingErrorKey]; + if([cuttlefishError.domain isEqualToString:CuttlefishErrorDomain]) { + NSNumber* val = cuttlefishError.userInfo[CuttlefishErrorRetryAfterKey]; + if (val) { + return (NSTimeInterval)val.doubleValue; + } + } + } + } + return 0; +} @end diff --git a/keychain/ckks/NSOperationCategories.m b/keychain/ckks/NSOperationCategories.m index d69f47a6..b9ea9410 100644 --- a/keychain/ckks/NSOperationCategories.m +++ b/keychain/ckks/NSOperationCategories.m @@ -24,6 +24,7 @@ #import #import "keychain/ckks/NSOperationCategories.h" #import "keychain/ot/ObjCImprovements.h" +#import "utilities/debugging.h" @implementation NSOperation (CKKSUsefulPrintingOperation) - (NSString*)selfname { @@ -41,6 +42,9 @@ // don't depend on yourself continue; } +#if DEBUG + secnotice("ckks-operation", "adding dependency of %@ on %@", self, existingop); +#endif [self addDependency: existingop]; } [collection addObject:self]; diff --git a/keychain/ckks/OctagonAPSReceiver.h b/keychain/ckks/OctagonAPSReceiver.h index cf33ac99..5271338d 100644 --- a/keychain/ckks/OctagonAPSReceiver.h +++ b/keychain/ckks/OctagonAPSReceiver.h @@ -74,5 +74,9 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface OctagonAPSReceiver (Testing) ++ (void)resetGlobalEnviornmentMap; +@end + NS_ASSUME_NONNULL_END #endif // OCTAGON diff --git a/keychain/ckks/OctagonAPSReceiver.m b/keychain/ckks/OctagonAPSReceiver.m index fbd0c175..10499da9 100644 --- a/keychain/ckks/OctagonAPSReceiver.m +++ b/keychain/ckks/OctagonAPSReceiver.m @@ -27,6 +27,7 @@ #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSCondition.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSAnalytics.h" #import "keychain/analytics/SecMetrics.h" #import "keychain/analytics/SecEventMetric.h" #import "keychain/ot/ObjCImprovements.h" @@ -79,18 +80,15 @@ + (instancetype)receiverForEnvironment:(NSString *)environmentName namedDelegatePort:(NSString*)namedDelegatePort - apsConnectionClass:(Class)apsConnectionClass { - static NSMutableDictionary* environmentMap = nil; - + apsConnectionClass:(Class)apsConnectionClass +{ if(environmentName == nil) { secnotice("octagonpush", "No push environment; not bringing up APS."); return nil; } @synchronized([self class]) { - if(environmentMap == nil) { - environmentMap = [[NSMutableDictionary alloc] init]; - } + NSMutableDictionary* environmentMap = [self synchronizedGlobalEnvironmentMap]; OctagonAPSReceiver* recv = [environmentMap valueForKey: environmentName]; @@ -103,6 +101,29 @@ } } ++ (void)resetGlobalEnviornmentMap +{ + @synchronized (self) { + [self resettableSynchronizedGlobalEnvironmentMap:YES]; + } +} + ++ (NSMutableDictionary*)synchronizedGlobalEnvironmentMap +{ + return [self resettableSynchronizedGlobalEnvironmentMap:NO]; +} + ++ (NSMutableDictionary*)resettableSynchronizedGlobalEnvironmentMap:(BOOL)reset +{ + static NSMutableDictionary* environmentMap = nil; + + if(environmentMap == nil || reset) { + environmentMap = [[NSMutableDictionary alloc] init]; + } + + return environmentMap; +} + + (dispatch_queue_t)apsDeliveryQueue { static dispatch_queue_t aps_dispatch_queue; static dispatch_once_t onceToken; @@ -113,7 +134,7 @@ } + (int64_t)stalePushTimeout { - return 5*60*NSEC_PER_MSEC; + return 5*60*NSEC_PER_SEC; } - (BOOL) haveStalePushes @@ -319,6 +340,7 @@ NSString* container = cfInfo[@"c"]; secnotice("octagonpush", "Received a cuttlefish push to container %@", container); + [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastOctagonPush]; if(container) { id receiver = [self.octagonContainerMap objectForKey:container]; @@ -350,6 +372,8 @@ rznotification.ckksPushTracingUUID = message.tracingUUID ? [[[NSUUID alloc] initWithUUIDBytes:message.tracingUUID.bytes] UUIDString] : nil; rznotification.ckksPushReceivedDate = [NSDate date]; + [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastCKKSPush]; + // Find receiever in map id recv = [self.zoneMap objectForKey:rznotification.recordZoneID.zoneName]; if(recv) { diff --git a/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m b/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m index 7420cd8f..1dc7249f 100644 --- a/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m +++ b/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m @@ -33,7 +33,7 @@ #import "keychain/ckks/CKKSIncomingQueueEntry.h" #import "keychain/ckks/CKKSItemEncrypter.h" -#include +#include "keychain/securityd/SecItemServer.h" #include #include "OSX/sec/Security/SecItemShim.h" diff --git a/keychain/ckks/tests/CKKSAPSHandlingTests.m b/keychain/ckks/tests/CKKSAPSHandlingTests.m index 34b0a322..748de40c 100644 --- a/keychain/ckks/tests/CKKSAPSHandlingTests.m +++ b/keychain/ckks/tests/CKKSAPSHandlingTests.m @@ -287,7 +287,7 @@ - (int64_t)stalePushTimeoutShort { - return 10 * NSEC_PER_SEC; + return 4 * NSEC_PER_SEC; } - (void)testDropStalePushes { @@ -298,9 +298,10 @@ APSIncomingMessage* apsMessage = [CKKSAPSHandlingTests messageWithTracingEnabledForZoneID:pushTestZone]; - OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForEnvironment:self.apsEnvironment - namedDelegatePort:SecCKKSAPSNamedPort - apsConnectionClass:[FakeAPSConnection class]]; + // Don't use the global map here, because we need to ensure we create a new object (to use the stalePushTimeout we injected above) + OctagonAPSReceiver* apsReceiver = [[OctagonAPSReceiver alloc] initWithEnvironmentName:self.apsEnvironment + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:[FakeAPSConnection class]]; XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver"); [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage]; @@ -308,12 +309,14 @@ XCTAssertEqual(apsReceiver.haveStalePushes, YES, "should have stale pushes"); XCTestExpectation *expection = [self expectationWithDescription:@"no push"]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, [self stalePushTimeoutShort] + 2), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, [self stalePushTimeoutShort] + (2*NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ XCTAssertEqual(apsReceiver.haveStalePushes, NO, "should have cleared out stale pushes"); [expection fulfill]; }); [self waitForExpectations: @[expection] timeout:([self stalePushTimeoutShort] * 4)/NSEC_PER_SEC]; + + [nearFutureSchduler stopMocking]; } diff --git a/keychain/ckks/tests/CKKSCloudKitTests.m b/keychain/ckks/tests/CKKSCloudKitTests.m index e7586ea8..6add0637 100644 --- a/keychain/ckks/tests/CKKSCloudKitTests.m +++ b/keychain/ckks/tests/CKKSCloudKitTests.m @@ -27,9 +27,9 @@ #import #import -#import +#import "keychain/securityd/SecItemServer.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #import "keychain/ckks/CKKS.h" diff --git a/keychain/ckks/tests/CKKSFetchTests.m b/keychain/ckks/tests/CKKSFetchTests.m index 2a7a1adf..433a2b20 100644 --- a/keychain/ckks/tests/CKKSFetchTests.m +++ b/keychain/ckks/tests/CKKSFetchTests.m @@ -11,8 +11,10 @@ #import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" #import "keychain/ckks/tests/MockCloudKit.h" +#import "keychain/ot/ObjCImprovements.h" @interface CloudKitKeychainFetchTests : CloudKitKeychainSyncingTestsBase @end @@ -188,6 +190,187 @@ [self findGenericPassword: @"account3" expecting:errSecSuccess]; } +- (void)testMoreComingWithFullFailure { + WEAKIFY(self); + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + // The fetch fails with partial results + ckzone.limitFetchTo = ck1; + ckzone.limitFetchError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:@{CKErrorRetryAfterKey : [NSNumber numberWithInt:4]}]; + + self.silentFetchesAllowed = false; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + return YES; + } runBeforeFinished:^{ + STRONGIFY(self); + // We want to fail with a full network failure error, but we explicitly don't want to set network reachability: + // CKKS won't send the fetch in that case. So... + [self.keychainZone failNextFetchWith:[NSError errorWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:NULL]]; + [self expectCKFetch]; + }]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + // Wait for both fetches.... + OCMVerifyAllWithDelay(self.mockDatabase, 20); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + // Potential race here: we need to start this expectation before CKKS issues the fetch. With a 4s delay, this should be safe. + + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + [self.reachabilityTracker setNetworkReachability:true]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + [self findGenericPassword: @"account2" expecting:errSecSuccess]; + [self findGenericPassword: @"account3" expecting:errSecSuccess]; +} + +- (void)testFetchOnRestartWithMoreComing { + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + + // Allow CKKS to fetch fully, then fake on-disk that it received MoreComing. + // (It's very hard to tear down the retry logic in-process) + self.silentFetchesAllowed = false; + [self expectCKFetch]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + + // Now, edit the on-disk CKSE + [self.keychainView halt]; + + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error]; + + XCTAssertNil(error, "no error pulling ckse from database"); + XCTAssertNotNil(ckse, "received a ckse"); + + ckse.moreRecordsInCloudKit = YES; + [ckse saveToDatabase: &error]; + XCTAssertNil(error, "no error saving to database"); + return true; + }]; + + // CKKS should, upon restart, kick off a fetch starting from the previous checkpoint + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.keychainView = [self.injectedManager restartZone:self.keychainZoneID.zoneName]; + [self.keychainView beginCloudKitOperation]; + [self beginSOSTrustedViewOperation:self.keychainView]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + [self findGenericPassword: @"account2" expecting:errSecSuccess]; + [self findGenericPassword: @"account3" expecting:errSecSuccess]; +} + +- (void)testMoreComingAsFirstFetch { + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + ckzone.limitFetchTo = ck1; + + self.silentFetchesAllowed = false; + [self expectCKFetch]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self findGenericPassword:@"account0" expecting:errSecSuccess]; + [self findGenericPassword:@"account1" expecting:errSecSuccess]; + [self findGenericPassword:@"account2" expecting:errSecSuccess]; + [self findGenericPassword:@"account3" expecting:errSecSuccess]; +} + + @end #endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSMockOctagonAdapter.m b/keychain/ckks/tests/CKKSMockOctagonAdapter.m index 89c511b2..88d38640 100644 --- a/keychain/ckks/tests/CKKSMockOctagonAdapter.m +++ b/keychain/ckks/tests/CKKSMockOctagonAdapter.m @@ -128,6 +128,11 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + + @end #endif diff --git a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h index 85c47833..7fcff165 100644 --- a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h +++ b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h @@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN @property CKKSSOSSelfPeer* selfPeer; @property NSMutableSet>* trustedPeers; +@property (nullable) void (^updateOctagonKeySetListener)(id); + - (instancetype)initWithSelfPeer:(CKKSSOSSelfPeer*)selfPeer trustedPeers:(NSSet>*)trustedPeers essential:(BOOL)essential; diff --git a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m index 03491e76..ec18e233 100644 --- a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m +++ b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m @@ -102,6 +102,9 @@ } - (void)updateOctagonKeySetWithAccount:(nonnull id)currentSelfPeer error:(NSError *__autoreleasing _Nullable * _Nullable)error { + if(self.updateOctagonKeySetListener) { + self.updateOctagonKeySetListener(currentSelfPeer); + } return; } @@ -121,6 +124,10 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + - (NSSet>*)allPeers { // include the self peer, but as a CKKSSOSPeer object instead of a self peer diff --git a/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m index b5ae45f4..791dd625 100644 --- a/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m +++ b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m @@ -188,6 +188,122 @@ [self waitForExpectations: @[waitmore] timeout: 0.2]; } +- (void)testBlockMultiShotDelaysWithZeroInitialDelay { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test" + initialDelay:0*NSEC_PER_MSEC + continuingDelay:600*NSEC_PER_MSEC + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + // Watches can be very slow. We expect this to come back immediately, but give them a lot of slack.... + [self waitForExpectations: @[first] timeout:0.4]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // longdelay should NOT be fulfilled again within 0.3 seconds of the first run + [self waitForExpectations: @[longdelay] timeout:0.3]; + + // But second should be fulfilled in the first 1.0 seconds + [self waitForExpectations: @[second] timeout:0.6]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testBlockExponentialDelays { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (twice in 1s)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + longdelay.assertForOverFulfill = NO; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = NO; + + XCTestExpectation *longdelay2 = [self expectationWithDescription:@"FutureScheduler fired (three in 2s)"]; + longdelay2.inverted = YES; + longdelay2.expectedFulfillmentCount = 3; + longdelay2.assertForOverFulfill = NO; + + XCTestExpectation *third = [self expectationWithDescription:@"FutureScheduler fired (three)"]; + third.expectedFulfillmentCount = 3; + third.assertForOverFulfill = NO; + + XCTestExpectation *final = [self expectationWithDescription:@"FutureScheduler fired (fourth)"]; + final.expectedFulfillmentCount = 4; + final.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test" + initialDelay:500*NSEC_PER_MSEC + expontialBackoff:2 + maximumDelay:30*NSEC_PER_SEC + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + [longdelay2 fulfill]; + [third fulfill]; + [final fulfill]; + }]; + + [scheduler trigger]; + + // first should be fulfilled in the first 0.6 seconds + [self waitForExpectations: @[first] timeout:0.6]; + + [scheduler trigger]; + + // longdelay should NOT be fulfilled twice in the first 1.3-1.4 seconds + [self waitForExpectations: @[longdelay] timeout:0.8]; + + // But second should be fulfilled in the first 1.6 seconds + [self waitForExpectations: @[second] timeout:0.3]; + + [scheduler trigger]; + + // and longdelay2 should NOT be fulfilled three times in the first 2.3-2.4 seconds + [self waitForExpectations: @[longdelay2] timeout:0.9]; + + // But third should be fulfilled in the first 3.6 seconds + [self waitForExpectations: @[third] timeout:1.2]; + + // Wait out the 4s reset delay... + XCTestExpectation *reset = [self expectationWithDescription:@"reset"]; + reset.inverted = YES; + [self waitForExpectations: @[reset] timeout:4.2]; + + // and it should use a 0.5s delay after trigger + [scheduler trigger]; + + [self waitForExpectations: @[final] timeout:0.6]; +} + - (void)testBlockCancel { XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"]; cancelexpectation.inverted = YES; diff --git a/keychain/ckks/tests/CKKSSQLTests.m b/keychain/ckks/tests/CKKSSQLTests.m index 76db6ebd..8bd89e46 100644 --- a/keychain/ckks/tests/CKKSSQLTests.m +++ b/keychain/ckks/tests/CKKSSQLTests.m @@ -35,7 +35,7 @@ #import "keychain/ckks/CKKSDeviceStateEntry.h" #import "keychain/ckks/CKKSRateLimiter.h" -#include +#include "keychain/securityd/SecItemServer.h" @interface CloudKitKeychainSQLTests : CloudKitMockXCTest @end @@ -226,6 +226,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:YES lastFetch:[NSDate date] lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:nil]; @@ -235,6 +236,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:YES lastFetch:zse.lastFetchTime lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:zse.encodedRateLimiter]; @@ -243,6 +245,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"allnonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:NO lastFetch:zse.lastFetchTime lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:zse.encodedRateLimiter]; diff --git a/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m index d96cb296..c75ef74c 100644 --- a/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m +++ b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m @@ -117,7 +117,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -504,7 +505,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -613,7 +615,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -687,7 +690,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -766,7 +770,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -852,7 +857,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -915,7 +921,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; diff --git a/keychain/ckks/tests/CKKSTests+MultiZone.m b/keychain/ckks/tests/CKKSTests+MultiZone.m index e121b309..f3179612 100644 --- a/keychain/ckks/tests/CKKSTests+MultiZone.m +++ b/keychain/ckks/tests/CKKSTests+MultiZone.m @@ -687,6 +687,86 @@ OCMVerifyAllWithDelay(self.mockDatabase, 20); } +- (void)testMultiZoneResync { + // Set up + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + [self expectCKKSTLKSelfShareUploads]; + + // Put sample data in zones, and save off a change token for later fetch shenanigans + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"manatee0"]]; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"manatee1"]]; + CKServerChangeToken* manateeChangeToken1 = self.manateeZone.currentChangeToken; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"manatee2"]]; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"manatee3"]]; + + [self.healthZone addToZone:[self createFakeRecord:self.healthZoneID recordName:@"7B598D31-0000-0000-FFFF-5A507ACB2D00" withAccount:@"health0"]]; + [self.healthZone addToZone:[self createFakeRecord:self.healthZoneID recordName:@"7B598D31-0000-0000-FFFF-5A507ACB2D01" withAccount:@"health1"]]; + + [self startCKKSSubsystem]; + [self waitForKeyHierarchyReadinesses]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.manateeView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self.healthView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword:@"manatee0" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee1" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee2" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee3" expecting:errSecSuccess]; + [self findGenericPassword:@"health0" expecting:errSecSuccess]; + [self findGenericPassword:@"health1" expecting:errSecSuccess]; + + // Now, we resync. But, the manatee zone comes down in two fetches + self.silentFetchesAllowed = false; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is a refetch + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.manateeZoneID].previousServerChangeToken; + if(changeToken == nil) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.manateeZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:manateeChangeToken1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.manateeZone.limitFetchTo = manateeChangeToken1; + + // Attempt to trigger simultaneous key state resyncs. This is a horrible hack... + [self.manateeView dispatchSyncWithAccountKeys:^bool { + self.manateeView.keyStateFullRefetchRequested = YES; + [self.manateeView _onqueueAdvanceKeyStateMachineToState:nil withError:nil]; + return true; + }]; + [self.healthView dispatchSyncWithAccountKeys:^bool { + self.healthView.keyStateFullRefetchRequested = YES; + [self.healthView _onqueueAdvanceKeyStateMachineToState:nil withError:nil]; + return true; + }]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.manateeView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self.healthView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + // And all items should still exist + [self findGenericPassword:@"manatee0" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee1" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee2" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee3" expecting:errSecSuccess]; + [self findGenericPassword:@"health0" expecting:errSecSuccess]; + [self findGenericPassword:@"health1" expecting:errSecSuccess]; +} + @end #endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSTests.m b/keychain/ckks/tests/CKKSTests.m index 58bb0e16..8a057b6c 100644 --- a/keychain/ckks/tests/CKKSTests.m +++ b/keychain/ckks/tests/CKKSTests.m @@ -30,8 +30,8 @@ #import #include -#include -#include +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemServer.h" #include #include "keychain/SecureObjectSync/SOSInternal.h" @@ -500,6 +500,8 @@ NSString* account = @"account-delete-me"; [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // We expect a single record to be uploaded. [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID]; @@ -1154,11 +1156,13 @@ // Now, another device comes along and creates the hierarchy; we download it; and it and sends us the TLK [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self putFakeDeviceStatusInCloudKit:self.keychainZoneID]; [self.keychainView notifyZoneChange:nil]; [[self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished]; self.aksLockState = false; [self.lockStateTracker recheck]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], @"Key state should end up in waitfortlk"); // After unlock, the TLK arrives [self expectCKKSTLKSelfShareUpload:self.keychainZoneID]; @@ -2096,6 +2100,23 @@ [self checkGenericPassword:@"newpassword" account:localDataChangedAccount]; SecCKKSEnable(); + // To make this more challenging, CK returns the refetch in multiple batches. This shouldn't affect the resync... + CKServerChangeToken* ck1 = self.keychainZone.currentChangeToken; + self.silentFetchesAllowed = false; + [self expectCKFetch]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.keychainZone.limitFetchTo = ck1; + self.keychainZone.limitFetchError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:@{CKErrorRetryAfterKey : [NSNumber numberWithInt:4]}]; + // The sixth record gets magically added to CloudKit, but CKKS has never heard of it // (emulates a lost record on the client, but that CloudKit already believes it's sent the record for) // Expected outcome: added to local keychain @@ -2118,6 +2139,8 @@ XCTAssertNil(resyncOperation.error, "No error during the resync operation"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + // Now do some checking. Remember, we don't know which record we corrupted, so use the parsed account variables to check. [self findGenericPassword: deleteAccount expecting: errSecSuccess]; diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h index e1d7ef68..933305d3 100644 --- a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h @@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable) NSError* keychainFetchError; // A single trusted SOSPeer, but without any CKKS keys -@property CKKSSOSPeer* remoteSOSOnlyPeer; +@property (nullable) CKKSSOSPeer* remoteSOSOnlyPeer; // Set this to false after calling -setUp if you want to initialize the views yourself @property bool automaticallyBeginCKKSViewCloudKitOperation; diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m index 34477abf..3ea304a4 100644 --- a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m @@ -28,8 +28,8 @@ #import "keychain/ckks/tests/CloudKitMockXCTest.h" #import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" -#import -#import +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/SecItemDb.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSKeychainView.h" @@ -145,16 +145,21 @@ } - (void)tearDown { - [self.mockCKKSKeychainBackedKey stopMocking]; - self.mockCKKSKeychainBackedKey = nil; - // Make sure the key state machine won't be poked after teardown for(CKKSKeychainView* view in self.ckksViews) { [view.pokeKeyStateMachineScheduler cancel]; } + [self.ckksViews removeAllObjects]; [super tearDown]; self.keys = nil; + + [self.mockCKKSKeychainBackedKey stopMocking]; + self.mockCKKSKeychainBackedKey = nil; + + [((id)self.accountMetaDataStore) stopMocking]; + + self.remoteSOSOnlyPeer = nil; } - (void)startCKKSSubsystem @@ -357,6 +362,9 @@ - (void)putFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID { ZoneKeys* zonekeys = [self createFakeKeyHierarchy: zoneID oldTLK:nil]; XCTAssertNotNil(zonekeys, "failed to create fake key hierarchy for zoneID=%@", zoneID); + XCTAssertNil(zonekeys.error, "should have no error creating a zonekeys"); + + secnotice("fake-cloudkit", "new fake hierarchy: %@", zonekeys); FakeCKZone* zone = self.zones[zoneID]; XCTAssertNotNil(zone, "failed to find zone %@", zoneID); diff --git a/keychain/ckks/tests/CloudKitMockXCTest.m b/keychain/ckks/tests/CloudKitMockXCTest.m index f2caddc4..1eded344 100644 --- a/keychain/ckks/tests/CloudKitMockXCTest.m +++ b/keychain/ckks/tests/CloudKitMockXCTest.m @@ -32,18 +32,18 @@ #import #import -#include "securityd/Regressions/SecdTestKeychainUtilities.h" +#include "keychain/securityd/Regressions/SecdTestKeychainUtilities.h" #include -#include +#include "keychain/securityd/SecItemServer.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include #include @@ -124,6 +124,9 @@ self.apsEnvironment = @"fake APS push string"; + // Static variables are a scourge. Let's reset this one... + [OctagonAPSReceiver resetGlobalEnviornmentMap]; + self.mockDatabaseExceptionCatcher = OCMStrictClassMock([CKDatabase class]); self.mockDatabase = OCMStrictClassMock([CKDatabase class]); self.mockContainerExpectations = OCMStrictClassMock([CKContainer class]); @@ -321,6 +324,7 @@ OCMStub([self.mockCKKSViewManager defaultViewList]).andCall(self, @selector(managedViewList)); OCMStub([self.mockCKKSViewManager syncBackupAndNotifyAboutSync]); + OCMStub([self.mockCKKSViewManager waitForTrustReady]).andReturn(YES); self.injectedManager = self.mockCKKSViewManager; diff --git a/keychain/ckks/tests/MockCloudKit.m b/keychain/ckks/tests/MockCloudKit.m index cb56d641..a4172271 100644 --- a/keychain/ckks/tests/MockCloudKit.m +++ b/keychain/ckks/tests/MockCloudKit.m @@ -232,6 +232,7 @@ if(!fakezone) { // This is an error: the zone doesn't exist + ckksnotice("fakeck", subscription.zoneID, "failing subscription for missing zone"); self.subscriptionError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorPartialFailure userInfo:@{ @@ -243,6 +244,7 @@ }]; } else if(fakezone.subscriptionError) { + ckksnotice("fakeck", subscription.zoneID, "failing subscription with injected error %@", fakezone.subscriptionError); // Not the best way to do this, but it's an error // Needs fixing if you want to support multiple zone failures self.subscriptionError = fakezone.subscriptionError; @@ -250,6 +252,7 @@ // 'clear' the error fakezone.subscriptionError = nil; } else { + ckksnotice("fakeck", subscription.zoneID, "Successfully subscribed to zone"); if(!self.subscriptionsSaved) { self.subscriptionsSaved = [[NSMutableArray alloc] init]; } @@ -258,6 +261,7 @@ } for(NSString* subscriptionID in self.subscriptionIDsToDelete) { + secnotice("fakeck", "Successfully deleted subscription: %@", subscriptionID); if(!self.subscriptionIDsDeleted) { self.subscriptionIDsDeleted = [[NSMutableArray alloc] init]; } @@ -352,7 +356,7 @@ return; } - // Not precisely correct in the case of multiple zone fetches. However, we don't currently do that, so it'll work for now. + // Not precisely correct in the case of multiple zone fetches. NSError* mockError = [zone popFetchChangesError]; if(mockError) { self.fetchRecordZoneChangesCompletionBlock(mockError); @@ -678,6 +682,10 @@ dispatch_assert_queue(self.queue); CKRecord* record = [item CKRecordWithZoneID: zoneID]; + + secnotice("fake-cloudkit", "adding item to zone(%@): %@", zoneID.zoneName, item); + secnotice("fake-cloudkit", "new record: %@", record); + [self _onqueueAddToZone: record]; // Save off the etag diff --git a/keychain/ckksctl/ckksctl.m b/keychain/ckksctl/ckksctl.m index 7b200d99..bad4d21b 100644 --- a/keychain/ckksctl/ckksctl.m +++ b/keychain/ckksctl/ckksctl.m @@ -305,6 +305,7 @@ static void print_entry(id k, id v, int ind) NSString* ckdeviceIDError = pop(global, @"ckdeviceIDError", NSString); NSString* lockStateTracker = pop(global,@"lockstatetracker", NSString); NSString* retry = pop(global,@"cloudkitRetryAfter", NSString); + NSDate *lastCKKSPush = pop(global, @"lastCKKSPush", NSDate); printf("================================================================================\n\n"); printf("Global state:\n\n"); @@ -313,6 +314,7 @@ static void print_entry(id k, id v, int ind) printf("CK DeviceID: %s\n", [[ckdeviceID description] UTF8String]); printf("CK DeviceID Error: %s\n", [[ckdeviceIDError description] UTF8String]); printf("Lock state: %s\n", [[lockStateTracker description] UTF8String]); + printf("Last CKKS push: %s\n", [[lastCKKSPush description] UTF8String]); printf("\n"); } diff --git a/keychain/escrowrequest/tests/SecEscrowRequestTests.m b/keychain/escrowrequest/tests/SecEscrowRequestTests.m index 68dc2daf..d504c786 100644 --- a/keychain/escrowrequest/tests/SecEscrowRequestTests.m +++ b/keychain/escrowrequest/tests/SecEscrowRequestTests.m @@ -18,8 +18,8 @@ #include "keychain/ckks/CKKS.h" #include "keychain/ckks/CKKSLockStateTracker.h" -#include "securityd/SecItemServer.h" -#include "securityd/spi.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/spi.h" #include "utilities/SecFileLocations.h" #include "tests/secdmockaks/mockaks.h" diff --git a/keychain/headers/SecAccessControl.h b/keychain/headers/SecAccessControl.h new file mode 100644 index 00000000..5b66b242 --- /dev/null +++ b/keychain/headers/SecAccessControl.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecAccessControl + SecAccessControl defines access rights for items. + */ + +#ifndef _SECURITY_SECACCESSCONTROL_H_ +#define _SECURITY_SECACCESSCONTROL_H_ + +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @function SecAccessControlGetTypeID + @abstract Returns the type identifier of SecAccessControl instances. + @result The CFTypeID of SecAccessControl instances. + */ +CFTypeID SecAccessControlGetTypeID(void) +__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +/*! + @typedef SecAccessControlCreateFlags + + @constant kSecAccessControlUserPresence + User presence policy using biometry or Passcode. Biometry does not have to be available or enrolled. Item is still + accessible by Touch ID even if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled. + + @constant kSecAccessControlBiometryAny + Constraint: Touch ID (any finger) or Face ID. Touch ID or Face ID must be available. With Touch ID + at least one finger must be enrolled. With Face ID user has to be enrolled. Item is still accessible by Touch ID even + if fingers are added or removed. Item is still accessible by Face ID if user is re-enrolled. + + @constant kSecAccessControlTouchIDAny + Deprecated, please use kSecAccessControlBiometryAny instead. + + @constant kSecAccessControlBiometryCurrentSet + Constraint: Touch ID from the set of currently enrolled fingers. Touch ID must be available and at least one finger must + be enrolled. When fingers are added or removed, the item is invalidated. When Face ID is re-enrolled this item is invalidated. + + @constant kSecAccessControlTouchIDCurrentSet + Deprecated, please use kSecAccessControlBiometryCurrentSet instead. + + @constant kSecAccessControlDevicePasscode + Constraint: Device passcode + + @constant kSecAccessControlWatch + Constraint: Watch + + @constant kSecAccessControlOr + Constraint logic operation: when using more than one constraint, at least one of them must be satisfied. + + @constant kSecAccessControlAnd + Constraint logic operation: when using more than one constraint, all must be satisfied. + + @constant kSecAccessControlPrivateKeyUsage + Create access control for private key operations (i.e. sign operation) + + @constant kSecAccessControlApplicationPassword + Security: Application provided password for data encryption key generation. This is not a constraint but additional item + encryption mechanism. +*/ +typedef CF_OPTIONS(CFOptionFlags, SecAccessControlCreateFlags) { + kSecAccessControlUserPresence = 1u << 0, + kSecAccessControlBiometryAny API_AVAILABLE(macos(10.13.4), ios(11.3)) = 1u << 1, + kSecAccessControlTouchIDAny API_DEPRECATED_WITH_REPLACEMENT("kSecAccessControlBiometryAny", macos(10.12.1, 10.13.4), ios(9.0, 11.3)) = 1u << 1, + kSecAccessControlBiometryCurrentSet API_AVAILABLE(macos(10.13.4), ios(11.3)) = 1u << 3, + kSecAccessControlTouchIDCurrentSet API_DEPRECATED_WITH_REPLACEMENT("kSecAccessControlBiometryCurrentSet", macos(10.12.1, 10.13.4), ios(9.0, 11.3)) = 1u << 3, + kSecAccessControlDevicePasscode API_AVAILABLE(macos(10.11), ios(9.0)) = 1u << 4, + kSecAccessControlWatch API_AVAILABLE(macos(10.15), ios(NA), iosmac(13.0)) = 1u << 5, + kSecAccessControlOr API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 14, + kSecAccessControlAnd API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 15, + kSecAccessControlPrivateKeyUsage API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 30, + kSecAccessControlApplicationPassword API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 31, +} __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +/*! + @function SecAccessControlCreateWithFlags + @abstract Creates new access control object based on protection type and additional flags. + @discussion Created access control object should be used as a value for kSecAttrAccessControl attribute in SecItemAdd, + SecItemUpdate or SecKeyGeneratePair functions. Accessing keychain items or performing operations on keys which are + protected by access control objects can block the execution because of UI which can appear to satisfy the access control + conditions, therefore it is recommended to either move those potentially blocking operations out of the main + application thread or use combination of kSecUseAuthenticationContext and kSecUseAuthenticationUI attributes to control + where the UI interaction can appear. + @param allocator Allocator to be used by this instance. + @param protection Protection class to be used for the item. One of kSecAttrAccessible constants. + @param flags If no flags are set then all operations are allowed. + @param error Additional error information filled in case of failure. + @result Newly created access control object. + */ +__nullable +SecAccessControlRef SecAccessControlCreateWithFlags(CFAllocatorRef __nullable allocator, CFTypeRef protection, + SecAccessControlCreateFlags flags, CFErrorRef *error) +API_AVAILABLE(macos(10.10), ios(8.0)); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif // _SECURITY_SECACCESSCONTROL_H_ diff --git a/keychain/headers/SecIdentity.h b/keychain/headers/SecIdentity.h new file mode 100644 index 00000000..ea002f3e --- /dev/null +++ b/keychain/headers/SecIdentity.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2002-2011,2012-2013,2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecIdentity + The functions provided in SecIdentity.h implement a convenient way to + match private keys with certificates. +*/ + +#ifndef _SECURITY_SECIDENTITY_H_ +#define _SECURITY_SECIDENTITY_H_ + +#include +#include + +#include +#include + +#if SEC_OS_OSX +#include +#endif + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @function SecIdentityGetTypeID + @abstract Returns the type identifier of SecIdentity instances. + @result The CFTypeID of SecIdentity instances. +*/ +CFTypeID SecIdentityGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +#if SEC_OS_OSX +/*! + @function SecIdentityCreateWithCertificate + @abstract Creates a new identity reference for the given certificate, assuming the associated private key is in one of the specified keychains. + @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list. + @param certificateRef A certificate reference. + @param identityRef On return, an identity reference. You are responsible for releasing this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecIdentityCreateWithCertificate( + CFTypeRef __nullable keychainOrArray, + SecCertificateRef certificateRef, + SecIdentityRef * __nonnull CF_RETURNS_RETAINED identityRef) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); +#endif + +/*! + @function SecIdentityCopyCertificate + @abstract Returns a reference to a certificate for the given identity + reference. + @param identityRef An identity reference. + @param certificateRef On return, a pointer to the found certificate + reference. You are responsible for releasing this reference by calling + the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecIdentityCopyCertificate( + SecIdentityRef identityRef, + SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificateRef) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecIdentityCopyPrivateKey + @abstract Returns the private key associated with an identity. + @param identityRef An identity reference. + @param privateKeyRef On return, a pointer to the private key for the given + identity. On iOS, the private key must be of class type kSecAppleKeyItemClass. + You are responsible for releasing this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecIdentityCopyPrivateKey( + SecIdentityRef identityRef, + SecKeyRef * __nonnull CF_RETURNS_RETAINED privateKeyRef) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +#if SEC_OS_OSX +/*! + @function SecIdentityCopyPreference + @abstract Returns the preferred identity for the specified name and key usage, optionally limiting the result to an identity issued by a certificate whose subject is one of the distinguished names in validIssuers. If a preferred identity does not exist, NULL is returned. + @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies the service requiring an identity. + @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to ignore this parameter. + @param validIssuers (optional) An array of CFDataRef instances whose contents are the subject names of allowable issuers, as returned by a call to SSLCopyDistinguishedNames (SecureTransport.h). Pass NULL if any issuer is allowed. + @param identity On return, a reference to the preferred identity, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Please use the SecIdentityCopyPreferred API instead. +*/ +OSStatus SecIdentityCopyPreference(CFStringRef name, CSSM_KEYUSE keyUsage, CFArrayRef __nullable validIssuers, SecIdentityRef * __nonnull CF_RETURNS_RETAINED identity) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecIdentityCopyPreferred + @abstract Returns the preferred identity for the specified name and key usage, optionally limiting the result to an identity issued by a certificate whose subject is one of the distinguished names in validIssuers. If a preferred identity does not exist, NULL is returned. + @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies the service requiring an identity. + @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) + @param validIssuers (optional) An array of CFDataRef instances whose contents are the subject names of allowable issuers, as returned by a call to SSLCopyDistinguishedNames (SecureTransport.h). Pass NULL if any issuer is allowed. + @result An identity or NULL, if the preferred identity has not been set. Your code should then typically perform a search for possible identities using the SecItem APIs. + @discussion If a preferred identity has not been set for the supplied name, the returned identity reference will be NULL. Your code should then perform a search for possible identities, using the SecItemCopyMatching API. +*/ +__nullable +SecIdentityRef SecIdentityCopyPreferred(CFStringRef name, CFArrayRef __nullable keyUsage, CFArrayRef __nullable validIssuers) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecIdentitySetPreference + @abstract Sets the preferred identity for the specified name and key usage. + @param identity A reference to the identity which will be preferred. + @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies a service requiring this identity. + @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to specify any key usage. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Please use the SecIdentitySetPreferred API instead. +*/ +OSStatus SecIdentitySetPreference(SecIdentityRef identity, CFStringRef name, CSSM_KEYUSE keyUsage) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecIdentitySetPreferred + @abstract Sets the preferred identity for the specified name and key usage. + @param identity A reference to the identity which will be preferred. If NULL is passed, any existing preference for the specified name is cleared instead. + @param name A string containing a URI, RFC822 email address, DNS hostname, or other name which uniquely identifies a service requiring this identity. + @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to specify any key usage. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecIdentitySetPreferred(SecIdentityRef __nullable identity, CFStringRef name, CFArrayRef __nullable keyUsage) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecIdentityCopySystemIdentity + @abstract Obtain the system-wide SecIdentityRef associated with + a specified domain. + @param domain Identifies the SecIdentityRef to be obtained, typically + in the form "com.apple.subdomain...". + @param idRef On return, the system SecIdentityRef assicated with + the specified domain. Caller must CFRelease this when + finished with it. + @param actualDomain (optional) The actual domain name of the + the returned identity is returned here. This + may be different from the requested domain. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If no system SecIdentityRef exists for the specified + domain, a domain-specific alternate may be returned + instead, typically (but not exclusively) the + kSecIdentityDomainDefault SecIdentityRef. + */ +OSStatus SecIdentityCopySystemIdentity( + CFStringRef domain, + SecIdentityRef * __nonnull CF_RETURNS_RETAINED idRef, + CFStringRef * __nullable CF_RETURNS_RETAINED actualDomain) /* optional */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); + +/*! + @function SecIdentitySetSystemIdentity + @abstract Assign the supplied SecIdentityRef to the specified + domain. + @param domain Identifies the domain to which the specified + SecIdentityRef will be assigned. + @param idRef (optional) The identity to be assigned to the specified + domain. Pass NULL to delete a possible entry for the specified + domain; in this case, it is not an error if no identity + exists for the specified domain. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion The caller must be running as root. +*/ +OSStatus SecIdentitySetSystemIdentity( + CFStringRef domain, + SecIdentityRef __nullable idRef) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); + +/* + * Defined system identity domains. + */ + +/*! + @const kSecIdentityDomainDefault The system-wide default identity. + */ +extern const CFStringRef kSecIdentityDomainDefault __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); + +/*! + @const kSecIdentityDomainKerberosKDC Kerberos KDC identity. +*/ +extern const CFStringRef kSecIdentityDomainKerberosKDC __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); + +#endif // SEC_OS_OSX + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECIDENTITY_H_ */ diff --git a/keychain/headers/SecIdentityPriv.h b/keychain/headers/SecIdentityPriv.h new file mode 100644 index 00000000..99a62abb --- /dev/null +++ b/keychain/headers/SecIdentityPriv.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2002-2011,2012-2013,2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecIdentityPriv + The functions provided in SecIdentityPriv.h implement a convenient way to + match private keys with certificates. +*/ + +#ifndef _SECURITY_SECIDENTITYPRIV_H_ +#define _SECURITY_SECIDENTITYPRIV_H_ + +#include +#include +#include + +__BEGIN_DECLS + +/*! @function SecIdentityCreate + @abstract create a new identity object from the provided certificate and its associated private key. + @param allocator CFAllocator to allocate the identity object. Pass NULL to use the default allocator. + @param certificate A certificate reference. + @param privateKey A private key reference. + @result An identity reference. +*/ +SecIdentityRef SecIdentityCreate( + CFAllocatorRef allocator, + SecCertificateRef certificate, + SecKeyRef privateKey) + __SEC_MAC_AND_IOS_UNKNOWN; + //__OSX_AVAILABLE_STARTING(__MAC_10_3, __SEC_IPHONE_UNKNOWN); + +#if SEC_OS_OSX +/*! + @function SecIdentityCompare + @abstract Compares two SecIdentityRef instances for equality. + @param identity1 An identity reference. + @param identity2 An identity reference. + @param compareOptions A value containing option flags. Currently there are no compare options, so 0 should be passed for this parameter. + @result An enumerated value of type CFComparisonResult. See CFBase.h. + @discussion Two identities are considered equal if they contain identical certificate and private key components. + @deprecated in Mac OS X 10.5 and later; the CFEqual function should be used instead (CFBase.h). + */ +CFComparisonResult SecIdentityCompare( + SecIdentityRef identity1, + SecIdentityRef identity2, + CFOptionFlags compareOptions) + DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER; + +/*! + @function SecIdentityFindPreferenceItem + @abstract Returns an identity preference item, given an identity string. + @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list. + @param idString A string containing a URI, hostname, or email (RFC822) address. + @param itemRef On return, a reference to the keychain item which was found. The caller is responsible for releasing this reference. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string. + @deprecated in Mac OS X 10.7 and later; use SecIdentityCopyPreferred() instead (SecIdentity.h) + + WARNING: This function is based on an implementation detail and will go away + in a future release; its use should be avoided at all costs. It does not + provide a way to find a preference item based on key usage, and it can only + find preferences which are stored as keychain items, so it may fail to find + the item you expect. Please use the public API functions to manipulate + identity preferences. +*/ +OSStatus SecIdentityFindPreferenceItem( + CFTypeRef keychainOrArray, + CFStringRef idString, + SecKeychainItemRef *itemRef) + API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreferred", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/*! + @function SecIdentityAddPreferenceItem + @abstract Adds a new identity preference item to the specified keychain. + @param keychainRef A reference to the keychain in which to store the preference item. Pass NULL to specify the user's default keychain. + @param identityRef An identity reference. + @param idString A string containing a URI, hostname, or email (RFC822) address. + @param itemRef On return, a reference to the new keychain item. The caller is responsible for releasing this reference. Pass NULL if the reference is not needed. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string. + @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h). +*/ +OSStatus SecIdentityAddPreferenceItem( + SecKeychainRef keychainRef, + SecIdentityRef identityRef, + CFStringRef idString, + SecKeychainItemRef *itemRef) + API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/*! + @function SecIdentityUpdatePreferenceItem + @abstract Given an existing identity preference keychain item, update it with the provided identity. + @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem. + @param identityRef An identity reference. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is used to update an existing preference item when a different identity is preferred. + @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h). +*/ +OSStatus SecIdentityUpdatePreferenceItem( + SecKeychainItemRef itemRef, + SecIdentityRef identityRef) + API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/*! + @function SecIdentityCopyFromPreferenceItem + @abstract Given an existing identity preference keychain item, obtain a SecIdentityRef for the identity it specifies. + @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem. + @param identityRef On return, an identity reference. The caller is responsible for releasing this reference. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is used to obtain a SecIdentityRef from an existing preference item. + @deprecated in Mac OS X 10.5; use SecIdentityCopyPreference() instead (SecIdentity.h). +*/ +OSStatus SecIdentityCopyFromPreferenceItem( + SecKeychainItemRef itemRef, + SecIdentityRef *identityRef) + API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/*! + @function ConvertArrayToKeyUsage + @abstract Given an array of key usages defined in SecItem.h return the equivalent CSSM_KEYUSE + @param usage An CFArrayRef containing CFTypeRefs defined in SecItem.h + kSecAttrCanEncrypt, + kSecAttrCanDecrypt, + kSecAttrCanDerive, + kSecAttrCanSign, + kSecAttrCanVerify, + kSecAttrCanWrap, + kSecAttrCanUnwrap + If the CFArrayRef is NULL then the CSSM_KEYUSAGE will be CSSM_KEYUSE_ANY + @result A CSSM_KEYUSE. Derived from the passed in Array +*/ +CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage) + __SEC_MAC_ONLY_UNKNOWN; +#endif // SEC_OS_OSX + +__END_DECLS + +#endif /* _SECURITY_SECIDENTITYPRIV_H_ */ diff --git a/keychain/headers/SecImportExport.h b/keychain/headers/SecImportExport.h new file mode 100644 index 00000000..c6c91c6a --- /dev/null +++ b/keychain/headers/SecImportExport.h @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2000-2011,2012-2014,2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecImportExport + contains import/export functionality for keys and certificates. +*/ +#ifndef _SECURITY_SECIMPORTEXPORT_H_ +#define _SECURITY_SECIMPORTEXPORT_H_ + +#include +#include +#include +#include +#include +#include + +#if SEC_OS_OSX +#include +#include +#include +#include +#endif /* SEC_OS_OSX */ + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +#if SEC_OS_OSX +/* + * Supported import/export Formats + */ +typedef CF_ENUM(uint32_t, SecExternalFormat) +{ + /* + * When importing: unknown format + * When exporting: default format for item + */ + kSecFormatUnknown = 0, + + /* + * Public and Private Key formats. + * Default for export is kSecFormatOpenSSL. + */ + kSecFormatOpenSSL, /* a.k.a. X509 for public keys */ + kSecFormatSSH, /* OpenSSH v.1 */ + kSecFormatBSAFE, + + /* Symmetric Key Formats */ + kSecFormatRawKey, /* raw unformatted key bits; default */ + + /* Formats for wrapped symmetric and private keys */ + kSecFormatWrappedPKCS8, + kSecFormatWrappedOpenSSL, /* traditional openssl */ + kSecFormatWrappedSSH, /* OpenSSH v.1 */ + kSecFormatWrappedLSH, + + /* Formats for certificates */ + kSecFormatX509Cert, /* DER encoded; default */ + + /* Aggregate Types */ + kSecFormatPEMSequence, /* sequence of certs and/or keys, implies PEM + * armour. Default format for multiple items */ + kSecFormatPKCS7, /* sequence of certs */ + kSecFormatPKCS12, /* set of certs and private keys */ + kSecFormatNetscapeCertSequence, /* sequence of certs, form netscape-cert-sequence */ + + /* Added in Mac OS X 10.5 */ + kSecFormatSSHv2 /* OpenSSH v.2. Note that OpenSSH v2 private keys + * are in format kSecFormatOpenSSL or + * kSecFormatWrappedOpenSSL. */ +}; + +/* + * Indication of basic item type when importing. + */ +typedef CF_ENUM(uint32_t, SecExternalItemType) { + kSecItemTypeUnknown, /* caller doesn't know what this is */ + kSecItemTypePrivateKey, + kSecItemTypePublicKey, + kSecItemTypeSessionKey, + kSecItemTypeCertificate, + kSecItemTypeAggregate /* PKCS7, PKCS12, kSecFormatPEMSequence, etc. */ +}; + +/* + * Flags passed to SecKeychainItemExport() and SecKeychainItemImport(). + */ +typedef CF_OPTIONS(uint32_t, SecItemImportExportFlags) +{ + kSecItemPemArmour = 0x00000001, /* exported blob is PEM formatted */ +}; + +/* + * SecKeyRef-specific flags, specified in SecKeyImportExportParameters.flags + */ +typedef CF_OPTIONS(uint32_t, SecKeyImportExportFlags) +{ + /* + * When true, prevents the importing of more than one private key + * in a given SecKeychainItemImport(). + */ + kSecKeyImportOnlyOne = 0x00000001, + + /* + * When true, passphrase for import/export is obtained by user prompt + * instead of by caller-supplied data (SecKeyImportExportParameters.passphrase). + * This is the preferred method for obtaining a user-supplied passphrase + * as it avoids having the cleartext passphrase appear in the app's + * address space at any time. + */ + kSecKeySecurePassphrase = 0x00000002, + + /* + * When true, imported private keys will have no Access Control List + * (ACL) attached to them. In the absence of both this bit and the accessRef + * field in SecKeyImportExportParameters (see below), imported private + * keys are given a default ACL. + */ + kSecKeyNoAccessControl = 0x00000004 +}; + +/* + * Version of a SecKeyImportExportParameters. + */ +#define SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION 0 + +/* + * Parameters specific to SecKeyRefs. + */ +typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) +{ + /* for import and export */ + uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ + SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ + CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* + * formats only. Legal types are + * CFStringRef and CFDataRef. */ + CFStringRef alertTitle; /* title of secure passphrase alert panel */ + CFStringRef alertPrompt; /* prompt in secure passphrase alert panel */ + + /* for import only */ + SecAccessRef __nullable accessRef; /* specifies the initial ACL of imported + * key(s) */ + CSSM_KEYUSE keyUsage; /* CSSM_KEYUSE_DECRYPT, CSSM_KEYUSE_SIGN, + * etc. */ + CSSM_KEYATTR_FLAGS keyAttributes; /* CSSM_KEYATTR_PERMANENT, etc. */ +} SecKeyImportExportParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + + +typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) +{ + /* for import and export */ + uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ + SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ + CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* + * formats only. Legal types are + * CFStringRef and CFDataRef. */ + CFStringRef __nullable alertTitle; /* title of secure passphrase alert panel */ + CFStringRef __nullable alertPrompt; /* prompt in secure passphrase alert panel */ + + /* for import only */ + SecAccessRef __nullable accessRef; /* specifies the initial ACL of imported + * key(s) */ + CFArrayRef __nullable keyUsage; /* An Array containing usage attributes from SecItem.h, e.g. + * kSecAttrCanEncrypt;, kSecAttrCanDecrypt, kSecAttrCanDerive, etc. + */ + CFArrayRef __nullable keyAttributes; /* An array containing zero or more key attributes + * for an imported key. Possible values (from SecItem.h): + * kSecAttrIsPermanent, kSecAttrIsSensitive, kSecAttrIsExtractable + * Pass NULL in this field to use default attributes: + * - kSecAttrIsPermanent if a keychain is specified + * - kSecAttrIsSensitive for private keys + * - kSecAttrIsExtractable by default + */ +} SecItemImportExportKeyParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/* + * SecKeychainItemExport() + * + * This function takes one or more SecKeychainItemRefs and creates an + * external representation of the item(s) in the form of a CFDataRef. + * Caller specifies the format of the external representation via a + * SecExternalFormat enum. Caller may specify kSecFormatUnknown for + * the format, in which case a the default format for the item + * being exported is used (as described in the SecExternalFormat enums). + * PEM armouring is optional and is specified by the kSecItemPemArmour + * flag in importFlags. + * + * If exactly one item is to be exported, the keychainItemOrArray argument + * can be a SecKeychainItem. Otherwise this argument is a CFArrayRef + * containing a number of SecKeychainItems. + * + * The exported item(s) is (are) returned to the caller via the + * CFDataRef *exportedData argument. Caller must CFRelease the result. + * + * The following SecKeychainItems may be exported: + * + * SecCertificateRef + * SecKeyRef + * SecIdentityRef + * + * + * Key-related SecKeyImportExportParameters fields + * ----------------------------------------------- + * + * When exporting SecKeyRefs in one of the wrapped formats + * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, + * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must + * either explicitly specify the passphrase field or set + * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. + * + * If kSecKeySecurePassphrase is selected, caller can optionally + * specify strings for the passphrase panel's title bar and for + * the prompt which appears in the panel via the alertTitle and + * alertPrompt fields in SecKeyImportExportParameters. + * + * If an explicit passphrase is specified, note that PKCS12 + * explicitly requires that passphrases are in Unicode format; + * passing in a CFStringRef as the passphrase is the safest way + * to ensure that this requirement is met (and that the result + * will be compatible with other implementations). If a CFDataRef + * is supplied as the passphrase for a PKCS12 export operation, + * the referent data is assumed to be in UTF8 form and will be + * converted as appropriate. + * + * If no key items are being exported, the keyParams argument may be NULL. + * @discussion This API has been deprecated. Please us the SecItemExport API instead. + */ +OSStatus SecKeychainItemExport( + CFTypeRef keychainItemOrArray, + SecExternalFormat outputFormat, + SecItemImportExportFlags flags, /* kSecItemPemArmour, etc. */ + const SecKeyImportExportParameters * __nullable keyParams, /* optional */ + CFDataRef * __nonnull CF_RETURNS_RETAINED exportedData) /* external representation returned here */ + API_DEPRECATED_WITH_REPLACEMENT("SecItemExport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/* + * SecItemExport() + * + * This function takes one or more SecItemRefs and creates an + * external representation of the item(s) in the form of a CFDataRef. + * Caller specifies the format of the external representation via a + * SecExternalFormat enum. Caller may specify kSecFormatUnknown for + * the format, in which case a the default format for the item + * being exported is used (as described in the SecExternalFormat enums). + * PEM armouring is optional and is specified by the kSecItemPemArmour + * flag in importFlags. + * + * If exactly one item is to be exported, the keychainItemOrArray argument + * can be a SecKeychainItem. Otherwise this argument is a CFArrayRef + * containing a number of SecKeychainItems. + * + * The exported item(s) is (are) returned to the caller via the + * CFDataRef *exportedData argument. Caller must CFRelease the result. + * + * The following SecKeychainItems may be exported: + * + * SecCertificateRef + * SecKeyRef + * SecIdentityRef + * + * + * Key-related SecItemExport fields + * ----------------------------------------------- + * + * When exporting SecKeyRefs in one of the wrapped formats + * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, + * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must + * either explicitly specify the passphrase field or set + * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. + * + * If kSecKeySecurePassphrase is selected, caller can optionally + * specify strings for the passphrase panel's title bar and for + * the prompt which appears in the panel via the alertTitle and + * alertPrompt fields in SecItemImportExportKeyParameters. + * + * If an explicit passphrase is specified, note that PKCS12 + * explicitly requires that passphrases are in Unicode format; + * passing in a CFStringRef as the passphrase is the safest way + * to ensure that this requirement is met (and that the result + * will be compatible with other implementations). If a CFDataRef + * is supplied as the passphrase for a PKCS12 export operation, + * the referent data is assumed to be in UTF8 form and will be + * converted as appropriate. + * + * If no key items are being exported, the keyParams argument may be NULL. + * + */ +OSStatus SecItemExport( + CFTypeRef secItemOrArray, + SecExternalFormat outputFormat, + SecItemImportExportFlags flags, /* kSecItemPemArmour, etc. */ + const SecItemImportExportKeyParameters * __nullable keyParams, /* optional */ + CFDataRef * __nonnull CF_RETURNS_RETAINED exportedData) /* external representation returned here */ + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +/* + * SecKeychainItemImport() + * + * This function takes a CFDataRef containing the external representation + * of one or more objects and creates SecKeychainItems corresponding to + * those objects and optionally imports those SecKeychainItems into a + * specified keychain. The format of the incoming representation is + * specified by one or more of the following: + * + * -- A SecExternalFormat. This optional in/out argument is used when + * the caller knows exactly what format the external representation + * is in. It's also used to return to the caller the format which the + * function actually determines the external representation to be in. + * A value of kSecFormatUnknown is specified on entry when the caller + * wishes to know the inferred format on return. + * + * -- A SecExternalItemType - optional, in/out. Used to specify what kind + * of item is in the incoming representation, if known by the caller. + * It's also used to return to the caller the item type which the + * function actually determines the external representation to contain. + * A value of kSecItemTypeUnknown is specified on entry when the caller + * wishes to know the inferred item type on return. + * + * -- fileNameOrExtension, a CFStringRef. This optional argument contains + * the name of the file from which the external representation was + * obtained; it can also be simply an extension like CFSTR(".p7r"). + * This is a convenience for apps like KeychainAccess which can import a + * number of different formats. + * + * The SecKeychainItemImport() call does its best to figure out what is + * in an incoming external item given the info provided by the above three + * arguments. In most cases, SecKeychainItemImport() can even figure out + * what's in an external item if none of these are specified, but it would + * be unwise for an application to count on that ability. + * + * PEM formatting is determined internally via inspection of the incoming + * data, so the kSecItemPemArmour in the flags field is ignored. + * + * Zero, one, or both of the following occurs upon successful completion + * of this function: + * + * -- The imported item(s) is (are) imported to the specified importKeychain. + * If importKeychain is NULL, this step does not occur. + * + * -- The imported item(s) is (are) returned to the caller via the + * CFArrayRef *outItems argument. If outItems is NULL, this step + * does not occur. If outItems is NON-NULL, then *outItems will be + * a CFArrayRef containing a number of SecKeychainItems upon return. + * Caller must CFRelease the result. + * + * The possible types of returned SecKeychainItems are: + * + * SecCertificateRef + * SecKeyRef + * SecIdentityRef + * + * Note that when importing a PKCS12 blob, typically one SecIdentityRef + * and zero or more additional SecCertificateRefs are returned in + * outItems. No SecKeyRefs will appear there unless a key + * is found in the incoming blob with does not have a matching + * certificate. + * + * A typical case in which an app specifies the outItems + * argument and a NULL for importKeychain is when the app wishes to + * perform some user interaction, perhaps on a per-item basis, before + * committing to actually import the item(s). In this case, if the app + * does wish to proceed with the import, the standard import calls + * (SecCertificateAddToKeychain(), SecKeyAddToKeychain (implementation + * TBD)) would be used. + * + * Passing in NULL for both outItems and importKeychain + * is a perfectly acceptable way of using this function to determine, + * in a non-intrusive way, what is inside a given data blob. No effect + * other than returning inputFormat and/or itemType occurs in this + * case. + + * + * Key-related SecKeyImportExportParameters fields + * ----------------------------------------------- + * + * If importKeychain is NULL, the kSecKeyImportOnlyOne bit in the flags + * argument is ignored. Otherwise, if the kSecKeyImportOnlyOne bit is set, and + * there is more than one key in the incoming external representation, no + * items will be imported to the specified keychain and errSecMultipleKeys will + * be returned. + * + * The accessRef field allows the caller to specify the initial SecAccessRef + * for imported private keys. If more than one private key is being imported, + * all private keys get the same initial SecAccessRef. If this field is NULL + * when private keys are being imported, then the ACL attached to imported + * private keys depends on the kSecKeyNoAccessControl bit in the specified + * keyParams->flags. If this bit is 0, or keyParams is NULL, the default ACL + * will be used. If this bit is 1, no ACL will be attached to imported + * private keys. + * + * keyUsage and keyAttributes specify the low-level usage and attribute flags + * of imported keys. Each is a word of bits. The default value for keyUsage + * (used when keyParams is NULL or if keyParams->keyUsage is zero) is + * CSSM_KEYUSE_ANY. The default value for keyAttributes defaults is + * CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE; the CSSM_KEYATTR_PERMANENT + * bit is also added to the default if a non-NULL importKeychain is provided. + * + * The following are valid bits in keyAttributes: + * + * CSSM_KEYATTR_PERMANENT + * CSSM_KEYATTR_SENSITIVE + * CSSM_KEYATTR_EXTRACTABLE + * + * If the CSSM_KEYATTR_PERMANENT is set then the importKeychain argument must + * be valid or errSecInvalidKeychain will be returned if in fact any keys are found + * in the external representation. + * + * Note that if the caller does not set the CSSM_KEYATTR_EXTRACTABLE, this key + * will never be able to be extracted from the keychain in any form, not even + * in wrapped form. The CSSM_KEYATTR_SENSITIVE indicates that the key can only + * be extracted in wrapped form. + * + * The CSSM_KEYATTR_RETURN_xxx bits are always forced to + * CSSM_KEYATTR_RETURN_REF regardless of the specified keyAttributes + * field. + * + * When importing SecKeyRefs in one of the wrapped formats + * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, + * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must + * either explicitly specify the passphrase field or set + * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. + * + * If kSecKeySecurePassphrase is selected, caller can optionally + * specify strings for the passphrase panel's title bar and for + * the prompt which appears in the panel via the alertTitle and + * alertPrompt fields in SecKeyImportExportParameters. + * + * If an explicit passphrase is specified, note that PKCS12 + * explicitly requires that passphrases are in Unicode format; + * passing in a CFStringRef as the passphrase is the safest way + * to ensure that this requirement is met (and that the result + * will be compatible with other implementations). If a CFDataRef + * is supplied as the passphrase for a PKCS12 export operation, + * the referent data is assumed to be in UTF8 form and will be + * converted as appropriate. + + * If no key items are being imported, the keyParams argument may be NULL. + * + * The SecItemImportExportFlags argument is currently unused; caller should pass + * in 0. + * + * @discussion This API has been deprecated. Please use the SecItemImport API instead. + */ +OSStatus SecKeychainItemImport( + CFDataRef importedData, + CFStringRef __nullable fileNameOrExtension, /* optional */ + SecExternalFormat * __nullable inputFormat, /* optional, IN/OUT */ + SecExternalItemType * __nullable itemType, /* optional, IN/OUT */ + SecItemImportExportFlags flags, + const SecKeyImportExportParameters * __nullable keyParams, /* optional */ + SecKeychainRef __nullable importKeychain, /* optional */ + CFArrayRef * __nullable CF_RETURNS_RETAINED outItems) /* optional */ + API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/* + * SecItemImport() + * + * This function takes a CFDataRef containing the external representation + * of one or more objects and creates SecKeychainItems corresponding to + * those objects and optionally imports those SecKeychainItems into a + * specified keychain. The format of the incoming representation is + * specified by one or more of the following: + * + * -- A SecExternalFormat. This optional in/out argument is used when + * the caller knows exactly what format the external representation + * is in. It's also used to return to the caller the format which the + * function actually determines the external representation to be in. + * A value of kSecFormatUnknown is specified on entry when the caller + * wishes to know the inferred format on return. + * + * -- A SecExternalItemType - optional, in/out. Used to specify what kind + * of item is in the incoming representation, if known by the caller. + * It's also used to return to the caller the item type which the + * function actually determines the external representation to contain. + * A value of kSecItemTypeUnknown is specified on entry when the caller + * wishes to know the inferred item type on return. + * + * -- fileNameOrExtension, a CFStringRef. This optional argument contains + * the name of the file from which the external representation was + * obtained; it can also be simply an extension like CFSTR(".p7r"). + * This is a convenience for apps like KeychainAccess which can import a + * number of different formats. + * + * The SecItemImport() call does its best to figure out what is + * in an incoming external item given the info provided by the above three + * arguments. In most cases, SecItemImport() can even figure out + * what's in an external item if none of these are specified, but it would + * be unwise for an application to count on that ability. + * + * PEM formatting is determined internally via inspection of the incoming + * data, so the kSecItemPemArmour in the flags field is ignored. + * + * Zero, one, or both of the following occurs upon successful completion + * of this function: + * + * -- The imported item(s) is (are) imported to the specified importKeychain. + * If importKeychain is NULL, this step does not occur. + * + * -- The imported item(s) is (are) returned to the caller via the + * CFArrayRef *outItems argument. If outItems is NULL, this step + * does not occur. If outItems is NON-NULL, then *outItems will be + * a CFArrayRef containing a number of SecKeychainItems upon return. + * Caller must CFRelease the result. + * + * The possible types of returned SecKeychainItems are: + * + * SecCertificateRef + * SecKeyRef + * SecIdentityRef + * + * Note that when importing a PKCS12 blob, typically one SecIdentityRef + * and zero or more additional SecCertificateRefs are returned in + * outItems. No SecKeyRefs will appear there unless a key + * is found in the incoming blob with does not have a matching + * certificate. + * + * A typical case in which an app specifies the outItems + * argument and a NULL for importKeychain is when the app wishes to + * perform some user interaction, perhaps on a per-item basis, before + * committing to actually import the item(s). In this case, if the app + * does wish to proceed with the import, the standard import calls + * (SecCertificateAddToKeychain(), SecKeyAddToKeychain (implementation + * TBD)) would be used. + * + * Passing in NULL for both outItems and importKeychain + * is a perfectly acceptable way of using this function to determine, + * in a non-intrusive way, what is inside a given data blob. No effect + * other than returning inputFormat and/or itemType occurs in this + * case. + + * + * Key-related SecItemImportExportKeyParameters fields + * ----------------------------------------------- + * + * If importKeychain is NULL, the kSecKeyImportOnlyOne bit in the flags + * argument is ignored. Otherwise, if the kSecKeyImportOnlyOne bit is set, and + * there is more than one key in the incoming external representation, no + * items will be imported to the specified keychain and errSecMultipleKeys will + * be returned. + * + * The accessRef field allows the caller to specify the initial SecAccessRef + * for imported private keys. If more than one private key is being imported, + * all private keys get the same initial SecAccessRef. If this field is NULL + * when private keys are being imported, then the ACL attached to imported + * private keys depends on the kSecKeyNoAccessControl bit in the specified + * keyParams->flags. If this bit is 0, or keyParams is NULL, the default ACL + * will be used. If this bit is 1, no ACL will be attached to imported + * private keys. + * + * keyUsage and keyAttributes specify the low-level usage and attribute flags + * of imported keys. These fields contain a CFArray whose values are constants + * from SecItem.h. + * + * Possible values in the keyUsage array: + * + * kSecAttrCanEncrypt + * kSecAttrCanDecrypt + * kSecAttrCanDerive + * kSecAttrCanSign + * kSecAttrCanVerify + * kSecAttrCanWrap + * kSecAttrCanUnwrap + * + * If keyUsage is set to NULL, then any key usage is permitted. + * + * Possible values in the keyAttributes array: + * + * kSecAttrIsPermanent + * kSecAttrIsSensitive + * kSecAttrIsExtractable + * + * If keyAttributes is set to NULL, then default values are used: + * kSecAttrIsPermanent if an import keychain is specified + * kSecAttrIsSensitive for non-public keys + * kSecAttrIsExtractable + * + * If the kSecAttrIsPermanent attribute is set, then the + * importKeychain argument must be valid or errSecInvalidKeychain + * will be returned even if keys were able to be imported. + * + * Note that if the caller provides a keyAttributes array but + * does not set kSecAttrIsExtractable, this key will never be + * able to be extracted from the keychain in any form, not even + * in wrapped form. kSecAttrIsSensitive indicates that the key + * can only be extracted in wrapped form. + * + * When importing SecKeyRefs in one of the wrapped formats + * (kSecFormatWrappedOpenSSL, kSecFormatWrappedSSH, + * kSecFormatWrappedPKCS8), or in PKCS12 format, caller must + * either explicitly specify the passphrase field or set + * the kSecKeySecurePassphrase bit in SecKeyImportExportFlags. + * + * If kSecKeySecurePassphrase is selected, caller can optionally + * specify strings for the passphrase panel's title bar and for + * the prompt which appears in the panel via the alertTitle and + * alertPrompt fields in SecItemImportExportKeyParameters. + * + * If an explicit passphrase is specified, note that PKCS12 + * explicitly requires that passphrases are in Unicode format; + * passing in a CFStringRef as the passphrase is the safest way + * to ensure that this requirement is met (and that the result + * will be compatible with other implementations). If a CFDataRef + * is supplied as the passphrase for a PKCS12 export operation, + * the referent data is assumed to be in UTF8 form and will be + * converted as appropriate. + + * If no key items are being imported, the keyParams argument may be NULL. + * + * The SecItemImportExportFlags argument is currently unused; caller should pass + * in 0. + */ +OSStatus SecItemImport( + CFDataRef importedData, + CFStringRef __nullable fileNameOrExtension, /* optional */ + SecExternalFormat * __nullable inputFormat, /* optional, IN/OUT */ + SecExternalItemType * __nullable itemType, /* optional, IN/OUT */ + SecItemImportExportFlags flags, + const SecItemImportExportKeyParameters * __nullable keyParams, /* optional */ + SecKeychainRef __nullable importKeychain, /* optional */ + CFArrayRef * __nullable CF_RETURNS_RETAINED outItems) /* optional */ + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +#endif /* SEC_OS_OSX */ + +/*! + @enum Import/Export options + @discussion Predefined key constants used when passing dictionary-based arguments to import/export functions. + @constant kSecImportExportPassphrase Specifies a passphrase represented by a CFStringRef to be used when exporting to (or importing from) PKCS#12 format. + @constant kSecImportExportKeychain On OSX, specifies a keychain represented by a SecKeychainRef to be used as the target when importing from PKCS#12 format. + @constant kSecImportExportAccess On OSX, specifies an access represented by a SecAccessRef for the initial access (ACL) of a key imported from PKCS#12 format. +*/ +extern const CFStringRef kSecImportExportPassphrase + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecImportExportKeychain + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecImportExportAccess + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); + +/*! + @enum Import/Export item description + @discussion Predefined key constants used to pass back a CFArray with a + CFDictionary per item. + + @constant kSecImportItemLabel a CFStringRef representing the item label. + This implementation specific identifier cannot be expected to have + any format. + @constant kSecImportItemKeyID a CFDataRef representing the key id. Often + the SHA-1 digest of the public key. + @constant kSecImportItemIdentity a SecIdentityRef representing the identity. + @constant kSecImportItemTrust a SecTrustRef set up with all relevant + certificates. Not guaranteed to succesfully evaluate. + @constant kSecImportItemCertChain a CFArrayRef holding all relevant + certificates for this item's identity +*/ +extern const CFStringRef kSecImportItemLabel + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecImportItemKeyID + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecImportItemTrust + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecImportItemCertChain + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecImportItemIdentity + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @function SecPKCS12Import + @abstract Imports the contents of a PKCS12 formatted blob. + @param pkcs12_data The PKCS#12 formatted data to be imported. + @param options A dictionary containing import options. A + kSecImportExportPassphrase entry is required at minimum. Only password-based + PKCS12 blobs are currently supported. + @param items On return, an array containing a dictionary for every item + extracted. Use kSecImportItem constants to access specific elements of + these dictionaries. Your code must CFRelease the array when it is no longer + needed. + @result errSecSuccess in case of success. errSecDecode means either the + blob can't be read or it is malformed. errSecAuthFailed means an + incorrect password was supplied, or data in the container is damaged. +*/ +OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items) + API_AVAILABLE(macos(10.6), ios(2.0)); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECIMPORTEXPORT_H_ */ diff --git a/keychain/headers/SecImportExportPriv.h b/keychain/headers/SecImportExportPriv.h new file mode 100644 index 00000000..6d43101f --- /dev/null +++ b/keychain/headers/SecImportExportPriv.h @@ -0,0 +1,21 @@ +#ifndef _SECURITY_SECIMPORTEXPORTPRIV_H_ +#define _SECURITY_SECIMPORTEXPORTPRIV_H_ + +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +#if TARGET_OS_OSX +OSStatus SecPKCS12Import_ios(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items) + SPI_AVAILABLE(macos(10.15), iosmac(13.0)) API_UNAVAILABLE(ios, watchos, tvos); +#endif + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECIMPORTEXPORTPRIV_H_ */ diff --git a/keychain/headers/SecItem.h b/keychain/headers/SecItem.h new file mode 100644 index 00000000..f39dabbc --- /dev/null +++ b/keychain/headers/SecItem.h @@ -0,0 +1,1255 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItem + SecItem defines CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) +*/ + +#ifndef _SECURITY_SECITEM_H_ +#define _SECURITY_SECITEM_H_ + +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @enum Class Key Constant + @discussion Predefined key constant used to get or set item class values in + a dictionary. Its value is one of the constants defined in the Value + Constants for kSecClass. + @constant kSecClass Specifies a dictionary key whose value is the item's + class code. You use this key to get or set a value of type CFTypeRef + that contains the item class code. +*/ +extern const CFStringRef kSecClass + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @enum Class Value Constants + @discussion Predefined item class constants used to get or set values in + a dictionary. The kSecClass constant is the key and its value is one + of the constants defined here. Note: on Mac OS X 10.6, only items + of class kSecClassInternetPassword are supported. + @constant kSecClassInternetPassword Specifies Internet password items. + @constant kSecClassGenericPassword Specifies generic password items. + @constant kSecClassCertificate Specifies certificate items. + @constant kSecClassKey Specifies key items. + @constant kSecClassIdentity Specifies identity items. +*/ +extern const CFStringRef kSecClassInternetPassword + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecClassGenericPassword + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecClassCertificate + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecClassKey + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecClassIdentity + API_AVAILABLE(macos(10.7), ios(2.0)); + +/*! + @enum Attribute Key Constants + @discussion Predefined item attribute keys used to get or set values in a + dictionary. Not all attributes apply to each item class. The table + below lists the currently defined attributes for each item class: + + kSecClassGenericPassword item attributes: + kSecAttrAccess (OS X only) + kSecAttrAccessControl + kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrCreationDate + kSecAttrModificationDate + kSecAttrDescription + kSecAttrComment + kSecAttrCreator + kSecAttrType + kSecAttrLabel + kSecAttrIsInvisible + kSecAttrIsNegative + kSecAttrAccount + kSecAttrService + kSecAttrGeneric + kSecAttrSynchronizable + + kSecClassInternetPassword item attributes: + kSecAttrAccess (OS X only) + kSecAttrAccessControl + kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrCreationDate + kSecAttrModificationDate + kSecAttrDescription + kSecAttrComment + kSecAttrCreator + kSecAttrType + kSecAttrLabel + kSecAttrIsInvisible + kSecAttrIsNegative + kSecAttrAccount + kSecAttrSecurityDomain + kSecAttrServer + kSecAttrProtocol + kSecAttrAuthenticationType + kSecAttrPort + kSecAttrPath + kSecAttrSynchronizable + + kSecClassCertificate item attributes: + kSecAttrAccessible (iOS only) + kSecAttrAccessControl (iOS only) + kSecAttrAccessGroup (iOS only) + kSecAttrCertificateType + kSecAttrCertificateEncoding + kSecAttrLabel + kSecAttrSubject + kSecAttrIssuer + kSecAttrSerialNumber + kSecAttrSubjectKeyID + kSecAttrPublicKeyHash + kSecAttrSynchronizable + + kSecClassKey item attributes: + kSecAttrAccess (OS X only) + kSecAttrAccessControl + kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable and/or kSecUseDataProtectionKeychain set) + kSecAttrKeyClass + kSecAttrLabel + kSecAttrApplicationLabel + kSecAttrIsPermanent + kSecAttrApplicationTag + kSecAttrKeyType + kSecAttrPRF (OS X only) + kSecAttrSalt (OS X only) + kSecAttrRounds (OS X only) + kSecAttrKeySizeInBits + kSecAttrEffectiveKeySize + kSecAttrCanEncrypt + kSecAttrCanDecrypt + kSecAttrCanDerive + kSecAttrCanSign + kSecAttrCanVerify + kSecAttrCanWrap + kSecAttrCanUnwrap + kSecAttrSynchronizable + + Note that the attributes kSecAttrCan* describe attributes of the + key itself at relatively high level. Some of these attributes are + mathematical -- for example, a DSA key cannot encrypt. Others are + key-level policy issues -- for example, it is good cryptographic + hygiene to use an RSA key either for encryption or signing but not + both. Compare these to the certificate-level policy values in + SecPolicy.h. + + kSecClassIdentity item attributes: + Since an identity is the combination of a private key and a + certificate, this class shares attributes of both kSecClassKey and + kSecClassCertificate. + + @constant kSecAttrAccessible Specifies a dictionary key whose value + indicates when your application needs access to an item's data. You + should choose the most restrictive option that meets your application's + needs to allow the system to protect that item in the best way possible. + See the "kSecAttrAccessible Value Constants" section for a list of + values which can be specified. + IMPORTANT: This attribute is currently not supported for OS X keychain + items, unless the kSecAttrSynchronizable attribute is also present. If + both attributes are specified on either OS X or iOS, the value for the + kSecAttrAccessible key may only be one whose name does not end with + "ThisDeviceOnly", as those cannot sync to another device. + + @constant kSecAttrAccessControl Specifies a dictionary key whose value + is SecAccessControl instance which contains access control conditions + for item. + IMPORTANT: This attribute is mutually exclusive with kSecAttrAccess + attribute. + + @constant kSecAttrAccess Specifies a dictionary key whose value + is a SecAccessRef describing the access control settings for this item. + This key is available on OS X only. + + @constant kSecAttrAccessGroup Specifies a dictionary key whose value is + a CFStringRef indicating which access group a item is in. The access + groups that a particular application has membership in are determined by + two entitlements for that application. The application-identifier + entitlement contains the application's single access group, unless + there is a keychain-access-groups entitlement present. The latter + has as its value a list of access groups; the first item in this list + is the default access group. Unless a specific access group is provided + as the value of kSecAttrAccessGroup when SecItemAdd is called, new items + are created in the application's default access group. Specifying this + attribute in SecItemCopyMatching, SecItemUpdate, or SecItemDelete calls + limits the search to the specified access group (of which the calling + application must be a member to obtain matching results.) To share + keychain items between multiple applications, each application must have + a common group listed in its keychain-access-groups entitlement, and each + must specify this shared access group name as the value for the + kSecAttrAccessGroup key in the dictionary passed to SecItem functions. + + @constant kSecAttrSynchronizable Specifies a dictionary key whose value is + a CFBooleanRef indicating whether the item in question can be synchronized. + To add a new item which can be synced to other devices, or to obtain + synchronizable results from a query, supply this key with a value of + kCFBooleanTrue. If the key is not supplied, or has a value of + kCFBooleanFalse, then no synchronizable items will be added or returned. + A predefined value, kSecAttrSynchronizableAny, may be provided instead of + kCFBooleanTrue if both synchronizable and non-synchronizable results are + desired. + + IMPORTANT: Specifying the kSecAttrSynchronizable key has several caveats: + + - Updating or deleting items using the kSecAttrSynchronizable key will + affect all copies of the item, not just the one on your local device. + Be sure that it makes sense to use the same password on all devices + before deciding to make a password synchronizable. + - Only password items can currently be synchronized. Keychain syncing + is not supported for certificates or cryptographic keys. + - Items stored or obtained using the kSecAttrSynchronizable key cannot + specify SecAccessRef-based access control with kSecAttrAccess. If a + password is intended to be shared between multiple applications, the + kSecAttrAccessGroup key must be specified, and each application + using this password must have a 'keychain-access-groups' entitlement + with the specified access group value. + - Items stored or obtained using the kSecAttrSynchronizable key may + not also specify a kSecAttrAccessible value which is incompatible + with syncing (namely, those whose names end with "ThisDeviceOnly".) + - Items stored or obtained using the kSecAttrSynchronizable key cannot + be specified by reference. You must pass kSecReturnAttributes and/or + kSecReturnData to retrieve results; kSecReturnRef is currently not + supported for synchronizable items. + - Persistent references to synchronizable items should be avoided; + while they may work locally, they cannot be moved between devices, + and may not resolve if the item is modified on some other device. + - When specifying a query that uses the kSecAttrSynchronizable key, + search keys are limited to the item's class and attributes. + The only search constant which may be used is kSecMatchLimit; other + constants using the kSecMatch prefix are not supported at this time. + + @constant kSecAttrSynchronizableAny Specifies that both synchronizable and + non-synchronizable results should be returned from this query. This may be + used as a value for the kSecAttrSynchronizable dictionary key in a call to + SecItemCopyMatching, SecItemUpdate, or SecItemDelete. + + @constant kSecAttrCreationDate (read-only) Specifies a dictionary key whose + value is the item's creation date. You use this key to get a value + of type CFDateRef that represents the date the item was created. + @constant kSecAttrModificationDate (read-only) Specifies a dictionary key + whose value is the item's modification date. You use this key to get + a value of type CFDateRef that represents the last time the item was + updated. + @constant kSecAttrDescription Specifies a dictionary key whose value is + the item's description attribute. You use this key to set or get a + value of type CFStringRef that represents a user-visible string + describing this particular kind of item (e.g., "disk image password"). + @constant kSecAttrComment Specifies a dictionary key whose value is the + item's comment attribute. You use this key to set or get a value of + type CFStringRef containing the user-editable comment for this item. + @constant kSecAttrCreator Specifies a dictionary key whose value is the + item's creator attribute. You use this key to set or get a value of + type CFNumberRef that represents the item's creator. This number is + the unsigned integer representation of a four-character code (e.g., + 'aCrt'). + @constant kSecAttrType Specifies a dictionary key whose value is the item's + type attribute. You use this key to set or get a value of type + CFNumberRef that represents the item's type. This number is the + unsigned integer representation of a four-character code (e.g., + 'aTyp'). + @constant kSecAttrLabel Specifies a dictionary key whose value is the + item's label attribute. You use this key to set or get a value of + type CFStringRef containing the user-visible label for this item. + @constant kSecAttrIsInvisible Specifies a dictionary key whose value is the + item's invisible attribute. You use this key to set or get a value + of type CFBooleanRef that indicates whether the item is invisible + (i.e., should not be displayed.) + @constant kSecAttrIsNegative Specifies a dictionary key whose value is the + item's negative attribute. You use this key to set or get a value of + type CFBooleanRef that indicates whether there is a valid password + associated with this keychain item. This is useful if your application + doesn't want a password for some particular service to be stored in + the keychain, but prefers that it always be entered by the user. + @constant kSecAttrAccount Specifies a dictionary key whose value is the + item's account attribute. You use this key to set or get a CFStringRef + that contains an account name. (Items of class + kSecClassGenericPassword, kSecClassInternetPassword have this + attribute.) + @constant kSecAttrService Specifies a dictionary key whose value is the + item's service attribute. You use this key to set or get a CFStringRef + that represents the service associated with this item. (Items of class + kSecClassGenericPassword have this attribute.) + @constant kSecAttrGeneric Specifies a dictionary key whose value is the + item's generic attribute. You use this key to set or get a value of + CFDataRef that contains a user-defined attribute. (Items of class + kSecClassGenericPassword have this attribute.) + @constant kSecAttrSecurityDomain Specifies a dictionary key whose value + is the item's security domain attribute. You use this key to set or + get a CFStringRef value that represents the Internet security domain. + (Items of class kSecClassInternetPassword have this attribute.) + @constant kSecAttrServer Specifies a dictionary key whose value is the + item's server attribute. You use this key to set or get a value of + type CFStringRef that contains the server's domain name or IP address. + (Items of class kSecClassInternetPassword have this attribute.) + @constant kSecAttrProtocol Specifies a dictionary key whose value is the + item's protocol attribute. You use this key to set or get a value of + type CFNumberRef that denotes the protocol for this item (see the + SecProtocolType enum in SecKeychainItem.h). (Items of class + kSecClassInternetPassword have this attribute.) + @constant kSecAttrAuthenticationType Specifies a dictionary key whose value + is the item's authentication type attribute. You use this key to set + or get a value of type CFNumberRef that denotes the authentication + scheme for this item (see the kSecAttrAuthenticationType value + constants below). + @constant kSecAttrPort Specifies a dictionary key whose value is the item's + port attribute. You use this key to set or get a CFNumberRef value + that represents an Internet port number. (Items of class + kSecClassInternetPassword have this attribute.) + @constant kSecAttrPath Specifies a dictionary key whose value is the item's + path attribute, typically this is the path component of the URL. You use + this key to set or get a CFStringRef value that represents a path. (Items + of class kSecClassInternetPassword have this attribute.) + @constant kSecAttrSubject (read-only) Specifies a dictionary key whose + value is the item's subject. You use this key to get a value of type + CFDataRef that contains the X.500 subject name of a certificate. + (Items of class kSecClassCertificate have this attribute.) + @constant kSecAttrIssuer (read-only) Specifies a dictionary key whose value + is the item's issuer. You use this key to get a value of type + CFDataRef that contains the X.500 issuer name of a certificate. (Items + of class kSecClassCertificate have this attribute.) + @constant kSecAttrSerialNumber (read-only) Specifies a dictionary key whose + value is the item's serial number. You use this key to get a value + of type CFDataRef that contains the serial number data of a + certificate. (Items of class kSecClassCertificate have this + attribute.) + @constant kSecAttrSubjectKeyID (read-only) Specifies a dictionary key whose + value is the item's subject key ID. You use this key to get a value + of type CFDataRef that contains the subject key ID of a certificate. + (Items of class kSecClassCertificate have this attribute.) + @constant kSecAttrPublicKeyHash (read-only) Specifies a dictionary key + whose value is the item's public key hash. You use this key to get a + value of type CFDataRef that contains the hash of a certificate's + public key. (Items of class kSecClassCertificate have this attribute.) + @constant kSecAttrCertificateType (read-only) Specifies a dictionary key + whose value is the item's certificate type. You use this key to get + a value of type CFNumberRef that denotes the certificate type + (On iOS, currently the value of this attribute must be equal to the + version of the X509 certificate. So, 1 for v1, 2 for v2, and 3 for v3 + certificates). (On OSX, see the CSSM_CERT_TYPE enum in cssmtype.h). + Only items of class kSecClassCertificate have this attribute. + @constant kSecAttrCertificateEncoding (read-only) Specifies a dictionary + key whose value is the item's certificate encoding. You use this key + to get a value of type CFNumberRef that denotes the certificate + encoding (On iOS, currently only the value 3 meaning + kSecAttrCertificateEncodingDER is supported). On OSX, see the + CSSM_CERT_ENCODING enum in cssmtype.h. Only items of class + kSecClassCertificate have this attribute. + @constant kSecAttrKeyClass (read only) Specifies a dictionary key whose + value is one of kSecAttrKeyClassPublic, kSecAttrKeyClassPrivate or + kSecAttrKeyClassSymmetric. + @constant kSecAttrApplicationLabel Specifies a dictionary key whose value + is the key's application label attribute. This is different from the + kSecAttrLabel (which is intended to be human-readable). This attribute + is used to look up a key programmatically; in particular, for keys of + class kSecAttrKeyClassPublic and kSecAttrKeyClassPrivate, the value of + this attribute is the hash of the public key. This item is a type of CFDataRef. + Legacy keys may contain a UUID in this field as a CFStringRef. + @constant kSecAttrIsPermanent Specifies a dictionary key whose value is a + CFBooleanRef indicating whether the key in question will be stored + permanently. + @constant kSecAttrIsSensitive Specifies a dictionary key whose value is a + CFBooleanRef indicating that the key in question can only be exported + in a wrapped (encrypted) format. OS X only. + @constant kSecAttrIsExtractable Specifies a dictionary key whose value is a + CFBooleanRef indicating whether the key in question can be exported from + its keychain container. OS X only. + @constant kSecAttrApplicationTag Specifies a dictionary key whose value is a + CFDataRef containing private tag data. + @constant kSecAttrKeyType Specifies a dictionary key whose value is a + CFNumberRef indicating the algorithm associated with this key + (On iOS, currently only the value 42 is supported, alternatively you can use + kSecAttrKeyTypeRSA). (On OSX, see the CSSM_ALGORITHMS enum in cssmtype.h). + + @constant kSecAttrPRF Specifies a dictionary key whose value is the PRF + (pseudo-random function) for this key (see "kSecAttrPRF Value Constants".) + OS X only. + @constant kSecAttrSalt Specifies a dictionary key whose value is a + CFData containing the salt to use for this key. OS X only. + @constant kSecAttrRounds Specifies a dictionary key whose value is the + number of rounds for the pseudo-random function specified by kSecAttrPRF. + OS X only. + @constant kSecAttrKeySizeInBits Specifies a dictionary key whose value + is a CFNumberRef indicating the number of bits in this key. + @constant kSecAttrEffectiveKeySize Specifies a dictionary key whose value + is a CFNumberRef indicating the effective number of bits in this key. + For example, a DES key has a kSecAttrKeySizeInBits of 64, but a + kSecAttrEffectiveKeySize of 56 bits. + @constant kSecAttrCanEncrypt Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + encrypt data. + @constant kSecAttrCanDecrypt Specifies a dictionary key whose value is a + CFBooleanRef indicating whether the key in question can be used to + decrypt data. + @constant kSecAttrCanDerive Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + derive another key. + @constant kSecAttrCanSign Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + create a digital signature. + @constant kSecAttrCanVerify Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + verify a digital signature. + @constant kSecAttrCanWrap Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + wrap another key. + @constant kSecAttrCanUnwrap Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + unwrap another key. + @constant kSecAttrSyncViewHint Specifies a dictionary key whose value is + a CFStringRef. This value is part of the primary key of each item, and + can be used to help distiguish Sync Views when defining their + queries. iOS and sychronizable items only. + @constant kSecAttrTokenID Specifies a dictionary key whose presence + indicates that item is backed by external token. Value of this attribute + is CFStringRef uniquely identifying containing token. When this attribute + is not present, item is stored in internal keychain database. + Note that once item is created, this attribute cannot be changed - in other + words it is not possible to migrate existing items to, from or between tokens. + Currently the only available value for this attribute is + kSecAttrTokenIDSecureEnclave, which indicates that item (private key) is + backed by device's Secure Enclave. + */ +extern const CFStringRef kSecAttrAccessible + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrAccess + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrAccessControl + API_AVAILABLE(macos(10.10), ios(8.0)); +extern const CFStringRef kSecAttrAccessGroup + API_AVAILABLE(macos(10.9), ios(3.0)); +extern const CFStringRef kSecAttrSynchronizable + API_AVAILABLE(macos(10.9), ios(7.0)); +extern const CFStringRef kSecAttrSynchronizableAny + API_AVAILABLE(macos(10.9), ios(7.0)); +extern const CFStringRef kSecAttrCreationDate + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrModificationDate + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrDescription + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrComment + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCreator + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrType + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrLabel + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIsInvisible + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIsNegative + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAccount + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrService + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrGeneric + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrSecurityDomain + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrServer + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocol + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationType + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrPort + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrPath + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrSubject + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIssuer + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrSerialNumber + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrSubjectKeyID + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrPublicKeyHash + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCertificateType + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCertificateEncoding + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrKeyClass + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrApplicationLabel + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIsPermanent + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIsSensitive + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrIsExtractable + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrApplicationTag + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrKeyType + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrPRF + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrSalt + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrRounds + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeySizeInBits + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrEffectiveKeySize + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanEncrypt + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanDecrypt + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanDerive + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanSign + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanVerify + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanWrap + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrCanUnwrap + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrSyncViewHint + API_AVAILABLE(macos(10.11), ios(9.0)); +extern const CFStringRef kSecAttrTokenID + API_AVAILABLE(macos(10.12), ios(9.0)); +extern const CFStringRef kSecAttrPersistantReference + API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); +extern const CFStringRef kSecAttrPersistentReference + API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); + +/*! + @enum kSecAttrAccessible Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecAttrAccessible constant is the key and its + value is one of the constants defined here. + When asking SecItemCopyMatching to return the item's data, the error + errSecInteractionNotAllowed will be returned if the item's data is not + available until a device unlock occurs. + @constant kSecAttrAccessibleWhenUnlocked Item data can only be accessed + while the device is unlocked. This is recommended for items that only + need be accesible while the application is in the foreground. Items + with this attribute will migrate to a new device when using encrypted + backups. + @constant kSecAttrAccessibleAfterFirstUnlock Item data can only be + accessed once the device has been unlocked after a restart. This is + recommended for items that need to be accesible by background + applications. Items with this attribute will migrate to a new device + when using encrypted backups. + @constant kSecAttrAccessibleAlways Item data can always be accessed + regardless of the lock state of the device. This is not recommended + for anything except system use. Items with this attribute will migrate + to a new device when using encrypted backups. + @constant kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly Item data can + only be accessed while the device is unlocked. This is recommended for + items that only need to be accessible while the application is in the + foreground and requires a passcode to be set on the device. Items with + this attribute will never migrate to a new device, so after a backup + is restored to a new device, these items will be missing. This + attribute will not be available on devices without a passcode. Disabling + the device passcode will cause all previously protected items to + be deleted. + @constant kSecAttrAccessibleWhenUnlockedThisDeviceOnly Item data can only + be accessed while the device is unlocked. This is recommended for items + that only need be accesible while the application is in the foreground. + Items with this attribute will never migrate to a new device, so after + a backup is restored to a new device, these items will be missing. + @constant kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly Item data can + only be accessed once the device has been unlocked after a restart. + This is recommended for items that need to be accessible by background + applications. Items with this attribute will never migrate to a new + device, so after a backup is restored to a new device these items will + be missing. + @constant kSecAttrAccessibleAlwaysThisDeviceOnly Item data can always + be accessed regardless of the lock state of the device. This option + is not recommended for anything except system use. Items with this + attribute will never migrate to a new device, so after a backup is + restored to a new device, these items will be missing. +*/ +extern const CFStringRef kSecAttrAccessibleWhenUnlocked + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrAccessibleAfterFirstUnlock + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrAccessibleAlways + API_DEPRECATED("Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlock", macos(10.9, 10.14), ios(4.0, 12.0)); +extern const CFStringRef kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly + API_AVAILABLE(macos(10.10), ios(8.0)); +extern const CFStringRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrAccessibleAlwaysThisDeviceOnly + API_DEPRECATED("Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly", macos(10.9, 10.14), ios(4.0, 12.0)); + +/*! + @enum kSecAttrProtocol Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecAttrProtocol constant is the key and its + value is one of the constants defined here. + @constant kSecAttrProtocolFTP. + @constant kSecAttrProtocolFTPAccount. + @constant kSecAttrProtocolHTTP. + @constant kSecAttrProtocolIRC. + @constant kSecAttrProtocolNNTP. + @constant kSecAttrProtocolPOP3. + @constant kSecAttrProtocolSMTP. + @constant kSecAttrProtocolSOCKS. + @constant kSecAttrProtocolIMAP. + @constant kSecAttrProtocolLDAP. + @constant kSecAttrProtocolAppleTalk. + @constant kSecAttrProtocolAFP. + @constant kSecAttrProtocolTelnet. + @constant kSecAttrProtocolSSH. + @constant kSecAttrProtocolFTPS. + @constant kSecAttrProtocolHTTPS. + @constant kSecAttrProtocolHTTPProxy. + @constant kSecAttrProtocolHTTPSProxy. + @constant kSecAttrProtocolFTPProxy. + @constant kSecAttrProtocolSMB. + @constant kSecAttrProtocolRTSP. + @constant kSecAttrProtocolRTSPProxy. + @constant kSecAttrProtocolDAAP. + @constant kSecAttrProtocolEPPC. + @constant kSecAttrProtocolIPP. + @constant kSecAttrProtocolNNTPS. + @constant kSecAttrProtocolLDAPS. + @constant kSecAttrProtocolTelnetS. + @constant kSecAttrProtocolIMAPS. + @constant kSecAttrProtocolIRCS. + @constant kSecAttrProtocolPOP3S. +*/ +extern const CFStringRef kSecAttrProtocolFTP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolFTPAccount + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolHTTP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolIRC + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolNNTP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolPOP3 + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolSMTP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolSOCKS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolIMAP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolLDAP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolAppleTalk + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolAFP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolTelnet + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolSSH + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolFTPS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolHTTPS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolHTTPProxy + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolHTTPSProxy + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolFTPProxy + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolSMB + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolRTSP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolRTSPProxy + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolDAAP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolEPPC + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolIPP + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolNNTPS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolLDAPS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolTelnetS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolIMAPS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolIRCS + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrProtocolPOP3S + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @enum kSecAttrAuthenticationType Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecAttrAuthenticationType constant is the key + and its value is one of the constants defined here. + @constant kSecAttrAuthenticationTypeNTLM. + @constant kSecAttrAuthenticationTypeMSN. + @constant kSecAttrAuthenticationTypeDPA. + @constant kSecAttrAuthenticationTypeRPA. + @constant kSecAttrAuthenticationTypeHTTPBasic. + @constant kSecAttrAuthenticationTypeHTTPDigest. + @constant kSecAttrAuthenticationTypeHTMLForm. + @constant kSecAttrAuthenticationTypeDefault. +*/ +extern const CFStringRef kSecAttrAuthenticationTypeNTLM + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeMSN + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeDPA + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeRPA + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeHTTPBasic + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeHTTPDigest + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeHTMLForm + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecAttrAuthenticationTypeDefault + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @enum kSecAttrKeyClass Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecAttrKeyClass constant is the key + and its value is one of the constants defined here. + @constant kSecAttrKeyClassPublic. + @constant kSecAttrKeyClassPrivate. + @constant kSecAttrKeyClassSymmetric. +*/ +extern const CFStringRef kSecAttrKeyClassPublic + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecAttrKeyClassPrivate + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecAttrKeyClassSymmetric + API_AVAILABLE(macos(10.7), ios(2.0)); + +/*! + @enum kSecAttrKeyType Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecAttrKeyType constant is the key + and its value is one of the constants defined here. + @constant kSecAttrKeyTypeECSECPrimeRandom. + @constant kSecAttrKeyTypeEC This is the legacy name for kSecAttrKeyTypeECSECPrimeRandom, new applications should not use it. + @constant kSecAttrKeyTypeDSA (OSX only) + @constant kSecAttrKeyTypeAES (OSX only) + @constant kSecAttrKeyType3DES (OSX only) + @constant kSecAttrKeyTypeRC4 (OSX only) + @constant kSecAttrKeyTypeRC2 (OSX only) + @constant kSecAttrKeyTypeCAST (OSX only) + @constant kSecAttrKeyTypeECDSA (deprecated; use kSecAttrKeyTypeECSECPrimeRandom instead.) (OSX only) +*/ +extern const CFStringRef kSecAttrKeyTypeRSA + API_AVAILABLE(macos(10.7), ios(2.0)); +extern const CFStringRef kSecAttrKeyTypeDSA + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeAES + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeDES + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyType3DES + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeRC4 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeRC2 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeCAST + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeECDSA + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrKeyTypeEC + API_AVAILABLE(macos(10.9), ios(4.0)); +extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandom + API_AVAILABLE(macos(10.12), ios(10.0)); + +/* + @enum kSecAttrPRF Value Constants + @discussion Predefined item attribute constants used to specify the PRF + to use with SecKeyDeriveFromPassword. OS X only. + @constant kSecAttrPRFHmacAlgSHA1 + @constant kSecAttrPRFHmacAlgSHA224 + @constant kSecAttrPRFHmacAlgSHA256 + @constant kSecAttrPRFHmacAlgSHA384 + @constant kSecAttrPRFHmacAlgSHA512 +*/ +extern const CFStringRef kSecAttrPRFHmacAlgSHA1 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrPRFHmacAlgSHA224 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrPRFHmacAlgSHA256 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrPRFHmacAlgSHA384 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecAttrPRFHmacAlgSHA512 + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); + + +/*! + @enum Search Constants + @discussion Predefined search constants used to set values in a query + dictionary. You can specify a combination of search attributes and + item attributes when looking for matching items with the + SecItemCopyMatching function. + @constant kSecMatchPolicy Specifies a dictionary key whose value is a + SecPolicyRef. If provided, returned certificates or identities must + verify with this policy. + @constant kSecMatchItemList OS X only. Specifies a dictionary key whose value is a + CFArray of SecKeychainItemRef items. If provided, returned items will be + limited to the subset which are contained in this list. + @constant kSecMatchSearchList Specifies a dictionary key whose value is a + CFArray of SecKeychainRef items. If provided, the search will be limited + to the keychains contained in this list. + @constant kSecMatchIssuers Specifies a dictionary key whose value is a + CFArray of X.500 names (of type CFDataRef). If provided, returned + certificates or identities will be limited to those whose + certificate chain contains one of the issuers provided in this list. + @constant kSecMatchEmailAddressIfPresent Specifies a dictionary key whose + value is a CFStringRef containing an RFC822 email address. If + provided, returned certificates or identities will be limited to those + that contain the address, or do not contain any email address. + @constant kSecMatchSubjectContains Specifies a dictionary key whose value + is a CFStringRef. If provided, returned certificates or identities + will be limited to those containing this string in the subject. + @constant kSecMatchSubjectStartsWith OS X only. Specifies a dictionary key whose value + is a CFStringRef. If provided, returned certificates or identities + will be limited to those with subject names that start with this string. + @constant kSecMatchSubjectEndsWith OS X only. Specifies a dictionary key whose value + is a CFStringRef. If provided, returned certificates or identities + will be limited to those with subject names that end with this string. + @constant kSecMatchSubjectWholeString OS X only. Specifies a dictionary key whose + value is a CFStringRef. If provided, returned certificates or identities + will be limited to those matching this string exactly in the subject. + @constant kSecMatchCaseInsensitive Specifies a dictionary key whose value + is a CFBooleanRef. If this value is kCFBooleanFalse, or is not + provided, then case-sensitive string matching is performed. + @constant kSecMatchDiacriticInsensitive OS X only. Specifies a dictionary key whose + value is a CFBooleanRef. If this value is kCFBooleanFalse, or is not + provided, then diacritic-sensitive string matching is performed. + @constant kSecMatchWidthInsensitive OS X only. Specifies a dictionary key whose + value is a CFBooleanRef. If this value is kCFBooleanFalse, or is not + provided, then string matching is width-sensitive (e.g. 'a' != 0xFF41). + @constant kSecMatchTrustedOnly Specifies a dictionary key whose value is + a CFBooleanRef. If provided with a value of kCFBooleanTrue, only + certificates which can be verified back to a trusted anchor will be + returned. If this value is kCFBooleanFalse, or is not provided, then + both trusted and untrusted certificates may be returned. + @constant kSecMatchValidOnDate Specifies a dictionary key whose value is + of type CFDateRef. If provided, returned keys, certificates or + identities will be limited to those which are valid for the given date. + Pass a value of kCFNull to indicate the current date. + @constant kSecMatchLimit Specifies a dictionary key whose value is a + CFNumberRef. If provided, this value specifies the maximum number of + results to return. If not provided, results are limited to the first + item found. Predefined values are provided for a single item + (kSecMatchLimitOne) and all matching items (kSecMatchLimitAll). + @constant kSecMatchLimitOne Specifies that results are limited to the first + item found; used as a value for the kSecMatchLimit dictionary key. + @constant kSecMatchLimitAll Specifies that an unlimited number of results + may be returned; used as a value for the kSecMatchLimit dictionary + key. +*/ +extern const CFStringRef kSecMatchPolicy + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchItemList + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchSearchList + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchIssuers + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchEmailAddressIfPresent + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchSubjectContains + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchSubjectStartsWith + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecMatchSubjectEndsWith + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecMatchSubjectWholeString + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecMatchCaseInsensitive + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchDiacriticInsensitive + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecMatchWidthInsensitive + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecMatchTrustedOnly + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchValidOnDate + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchLimit + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchLimitOne + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecMatchLimitAll + API_AVAILABLE(macos(10.6), ios(2.0)); + + +/*! + @enum Return Type Key Constants + @discussion Predefined return type keys used to set values in a dictionary. + You use these keys to specify the type of results which should be + returned by the SecItemCopyMatching or SecItemAdd function. You can + specify zero or more of these return types. If more than one of these + result types is specified, the result is returned as a CFDictionaryRef + whose keys are the result types and values are the requested data. + @constant kSecReturnData Specifies a dictionary key whose value is of type + CFBooleanRef. A value of kCFBooleanTrue indicates that the data of + an item (CFDataRef) should be returned. For keys and password + items, data is secret (encrypted) and may require the user to enter + a password for access. + @constant kSecReturnAttributes Specifies a dictionary key whose value is + of type CFBooleanRef. A value of kCFBooleanTrue indicates that the + (non-encrypted) attributes of an item (CFDictionaryRef) should be + returned. + @constant kSecReturnRef Specifies a dictionary key whose value is a + CFBooleanRef. A value of kCFBooleanTrue indicates that a reference + should be returned. Depending on the item class requested, the + returned reference(s) may be of type SecKeychainItemRef, SecKeyRef, + SecCertificateRef, or SecIdentityRef. + @constant kSecReturnPersistentRef Specifies a dictionary key whose value + is of type CFBooleanRef. A value of kCFBooleanTrue indicates that a + persistent reference to an item (CFDataRef) should be returned. +*/ +extern const CFStringRef kSecReturnData + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecReturnAttributes + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecReturnRef + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecReturnPersistentRef + API_AVAILABLE(macos(10.6), ios(2.0)); + + +/*! + @enum Value Type Key Constants + @discussion Predefined value type keys used to pass values in a dictionary. + You can specify zero or more of these types depending on the function + you are calling. For SecItemCopyMatching or SecItemAdd these are + used as keys in the results dictionary. + @constant kSecValueData Specifies a dictionary key whose value is of type + CFDataRef. For keys and password items, data is secret (encrypted) + and may require the user to enter a password for access. + @constant kSecValueRef Specifies a dictionary key whose value, depending + on the item class requested, is of type SecKeychainItemRef, SecKeyRef, + SecCertificateRef, or SecIdentityRef. + @constant kSecValuePersistentRef Specifies a dictionary key whose value + is of type CFDataRef. The bytes in this CFDataRef can be stored by + the caller and used on a subsequent invocation of the application (or + even a different application) to retrieve the item referenced by it. +*/ +extern const CFStringRef kSecValueData + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecValueRef + API_AVAILABLE(macos(10.6), ios(2.0)); +extern const CFStringRef kSecValuePersistentRef + API_AVAILABLE(macos(10.6), ios(2.0)); + + +/*! + @enum Other Constants + @discussion Predefined constants used to set values in a dictionary. + @constant kSecUseItemList Specifies a dictionary key whose value is a + CFArray of items. If provided, this array is treated as the set of + all possible items to search, or add if the API being called is + SecItemAdd. The items in this array may be of type SecKeyRef, + SecCertificateRef, SecIdentityRef, or CFDataRef (for a persistent + item reference.) The items in the array must all be of the same + type. When this attribute is provided, no keychains are searched. + @constant kSecUseKeychain OS X only. Specifies a dictionary key whose value is a + keychain reference. You use this key to specify a value of type + SecKeychainRef to which SecItemAdd will add the provided item(s). + @constant kSecUseOperationPrompt Specifies a dictionary key whose value + is a CFStringRef that represents a user-visible string describing + the operation for which the application is attempting to authenticate. + The application is responsible for the text localization. + @constant kSecUseNoAuthenticationUI OS X only. Specifies a dictionary key whose value + is a CFBooleanRef. If provided with a value of kCFBooleanTrue, the error + errSecInteractionNotAllowed will be returned if the item is attempting + to authenticate with UI. + @constant kSecUseAuthenticationUI Specifies a dictionary key whose value + is one of kSecUseAuthenticationUIAllow, kSecUseAuthenticationUIFail, kSecUseAuthenticationUISkip. + @constant kSecUseAuthenticationContext Specifies a dictionary key whose value + is LAContext to be used for keychain item authentication. + * If the item requires authentication and this key is omitted, a new context + will be created just for the purpose of the single call. + * If the specified context has been previously authenticated, the operation + will succeed without asking user for authentication. + * If the specified context has not been previously authenticated, the new + authentication will be started on this context, allowing caller to + eventually reuse the successfully authenticated context in subsequent + keychain operations. + @constant kSecUseDataProtectionKeychain Specifies a dictionary key whose value + is a CFBooleanRef. Set to kCFBooleanTrue to use kSecAttrAccessGroup and/or + kSecAttrAccessible on macOS without requiring the item to be marked synchronizable. +*/ +extern const CFStringRef kSecUseItemList + API_AVAILABLE(macos(10.6)) + API_DEPRECATED("Not implemented on this platform", ios(2.0, 12.0), tvos(9.0, 12.0), watchos(1.0, 5.0)) + API_UNAVAILABLE(bridgeos, iosmac); +extern const CFStringRef kSecUseKeychain + API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA)); +extern const CFStringRef kSecUseOperationPrompt + API_AVAILABLE(macos(10.10), ios(8.0)); +extern const CFStringRef kSecUseNoAuthenticationUI + API_DEPRECATED("Use kSecUseAuthenticationUI instead.", macos(10.10, 10.11), ios(8.0, 9.0)); +extern const CFStringRef kSecUseAuthenticationUI + API_AVAILABLE(macos(10.11), ios(9.0)); +extern const CFStringRef kSecUseAuthenticationContext + API_AVAILABLE(macos(10.11), ios(9.0)); +extern const CFStringRef kSecUseDataProtectionKeychain + API_AVAILABLE(macos(10.15), ios(13.0)); + +/*! + @enum kSecUseAuthenticationUI Value Constants + @discussion Predefined item attribute constants used to get or set values + in a dictionary. The kSecUseAuthenticationUI constant is the key and its + value is one of the constants defined here. + If the key kSecUseAuthenticationUI not provided then kSecUseAuthenticationUIAllow + is used as default. + @constant kSecUseAuthenticationUIAllow Specifies that authenticate UI can appear. + @constant kSecUseAuthenticationUIFail Specifies that the error + errSecInteractionNotAllowed will be returned if an item needs + to authenticate with UI + @constant kSecUseAuthenticationUIAllowSkip Specifies that all items which need + to authenticate with UI will be silently skipped. This value can be used + only with SecItemCopyMatching. +*/ +extern const CFStringRef kSecUseAuthenticationUIAllow + API_AVAILABLE(macos(10.11), ios(9.0)); +extern const CFStringRef kSecUseAuthenticationUIFail + API_AVAILABLE(macos(10.11), ios(9.0)); +extern const CFStringRef kSecUseAuthenticationUISkip + API_AVAILABLE(macos(10.11), ios(9.0)); + +/*! + @enum kSecAttrTokenID Value Constants + @discussion Predefined item attribute constant used to get or set values + in a dictionary. The kSecAttrTokenID constant is the key and its value + can be kSecAttrTokenIDSecureEnclave. + @constant kSecAttrTokenIDSecureEnclave Specifies well-known identifier of the + token implemented using device's Secure Enclave. The only keychain items + supported by the Secure Enclave token are 256-bit elliptic curve keys + (kSecAttrKeyTypeECSecPrimeRandom). Keys must be generated on the secure enclave using + SecKeyGenerateKeyPair call with kSecAttrTokenID set to + kSecAttrTokenIDSecureEnclave in the parameters dictionary, it is not + possible to import pregenerated keys to kSecAttrTokenIDSecureEnclave token. +*/ +extern const CFStringRef kSecAttrTokenIDSecureEnclave + API_AVAILABLE(macos(10.12), ios(9.0)); + +/*! + @enum kSecAttrAccessGroup Value Constants + @constant kSecAttrAccessGroupToken Represents well-known access group + which contains items provided by external token (typically smart card). + This may be used as a value for kSecAttrAccessGroup attribute. Every + application has access to this access group so it is not needed to + explicitly list it in keychain-access-groups entitlement, but application + must explicitly state this access group in keychain queries in order to + be able to access items from external tokens. +*/ +extern const CFStringRef kSecAttrAccessGroupToken + API_AVAILABLE(macos(10.12), ios(10.0)); + +/*! + @function SecItemCopyMatching + @abstract Returns one or more items which match a search query. + @param query A dictionary containing an item class specification and + optional attributes for controlling the search. See the "Keychain + Search Attributes" section for a description of currently defined + search attributes. + @param result On return, a CFTypeRef reference to the found item(s). The + exact type of the result is based on the search attributes supplied + in the query, as discussed below. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Attributes defining a search are specified by adding key/value + pairs to the query dictionary. + + A typical query consists of: + + * a kSecClass key, whose value is a constant from the Class + Constants section that specifies the class of item(s) to be searched + * one or more keys from the "Attribute Key Constants" section, whose value + is the attribute data to be matched + * one or more keys from the "Search Constants" section, whose value is + used to further refine the search + * a key from the "Return Type Key Constants" section, specifying the type of + results desired + + Result types are specified as follows: + + * To obtain the data of a matching item (CFDataRef), specify + kSecReturnData with a value of kCFBooleanTrue. + * To obtain the attributes of a matching item (CFDictionaryRef), specify + kSecReturnAttributes with a value of kCFBooleanTrue. + * To obtain a reference to a matching item (SecKeychainItemRef, + SecKeyRef, SecCertificateRef, or SecIdentityRef), specify kSecReturnRef + with a value of kCFBooleanTrue. + * To obtain a persistent reference to a matching item (CFDataRef), + specify kSecReturnPersistentRef with a value of kCFBooleanTrue. Note + that unlike normal references, a persistent reference may be stored + on disk or passed between processes. + * If more than one of these result types is specified, the result is + returned as a CFDictionaryRef containing all the requested data. + * If a result type is not specified, no results are returned. + + By default, this function returns only the first match found. To obtain + more than one matching item at a time, specify kSecMatchLimit with a value + greater than 1. The result will be a CFArrayRef containing up to that + number of matching items; the items' types are described above. + + To filter a provided list of items down to those matching the query, + specify a kSecMatchItemList whose value is a CFArray of SecKeychainItemRef, + SecKeyRef, SecCertificateRef, or SecIdentityRef items. The objects in the + provided array must be of the same type. + + On iOS, to convert from a persistent item reference to a normal item reference, + specify a kSecValuePersistentRef whose value a CFDataRef (the persistent + reference), and a kSecReturnRef whose value is kCFBooleanTrue. + + On OSX, to convert from persistent item references to normal item references, + specify a kSecMatchItemList whose value is a CFArray containing one or + more CFDataRef elements (the persistent reference), and a kSecReturnRef + whose value is kCFBooleanTrue. The objects in the provided array must be + of the same type. +*/ +OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result) + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @function SecItemAdd + @abstract Add one or more items to a keychain. + @param attributes A dictionary containing an item class specification and + optional entries specifying the item's attribute values. See the + "Attribute Key Constants" section for a description of currently defined + attributes. + @param result On return, a CFTypeRef reference to the newly added item(s). + The exact type of the result is based on the values supplied + in attributes, as discussed below. Pass NULL if this result is not + required. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Attributes defining an item are specified by adding key/value + pairs to the attributes dictionary. To add multiple items to a keychain + at once use the kSecUseItemList key with an array of items as its value. + This is currently only supported for non password items. + + On OSX, To add an item to a particular keychain, supply kSecUseKeychain + with a SecKeychainRef as its value. + + Result types are specified as follows: + + * To obtain the data of the added item (CFDataRef), specify + kSecReturnData with a value of kCFBooleanTrue. + * To obtain all the attributes of the added item (CFDictionaryRef), + specify kSecReturnAttributes with a value of kCFBooleanTrue. + * To obtain a reference to the added item (SecKeychainItemRef, SecKeyRef, + SecCertiicateRef, or SecIdentityRef), specify kSecReturnRef with a + value of kCFBooleanTrue. + * To obtain a persistent reference to the added item (CFDataRef), specify + kSecReturnPersistentRef with a value of kCFBooleanTrue. Note that + unlike normal references, a persistent reference may be stored on disk + or passed between processes. + * If more than one of these result types is specified, the result is + returned as a CFDictionaryRef containing all the requested data. + * On iOS, if a result type is not specified, no results are returned. + On OSX, the added item is returned. +*/ +OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result) + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @function SecItemUpdate + @abstract Modify zero or more items which match a search query. + @param query A dictionary containing an item class specification and + optional attributes for controlling the search. See the "Attribute + Constants" and "Search Constants" sections for a description of + currently defined search attributes. + @param attributesToUpdate A dictionary containing one or more attributes + whose values should be set to the ones specified. Only real keychain + attributes are permitted in this dictionary (no "meta" attributes are + allowed.) See the "Attribute Key Constants" section for a description of + currently defined value attributes. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Attributes defining a search are specified by adding key/value + pairs to the query dictionary. +*/ +OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) + API_AVAILABLE(macos(10.6), ios(2.0)); + +/*! + @function SecItemDelete + @abstract Delete zero or more items which match a search query. + @param query A dictionary containing an item class specification and + optional attributes for controlling the search. See the "Attribute + Constants" and "Search Constants" sections for a description of + currently defined search attributes. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Attributes defining a search are specified by adding key/value + pairs to the query dictionary. + + By default, this function deletes all items matching the specified query. + You can change this behavior by specifying one of the follow keys: + + * To delete an item identified by a transient reference, on iOS, specify + kSecValueRef with a item reference. On OS X, give a kSecMatchItemList + containing an item reference. + * To delete an item identified by a persistent reference, on iOS, specify + kSecValuePersistentRef with a persistent reference returned by + using the kSecReturnPersistentRef key to SecItemCopyMatching or + SecItemAdd. on OSX, use kSecMatchItemList with a persistent reference + returned by using the kSecReturnPersistentRef key with + SecItemCopyMatching or SecItemAdd. + * To delete multiple items specify kSecMatchItemList with an array + of references. + * If more than one of these result keys is specified, the behavior is + undefined. +*/ +OSStatus SecItemDelete(CFDictionaryRef query) + API_AVAILABLE(macos(10.6), ios(2.0)); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECITEM_H_ */ diff --git a/keychain/headers/SecItemPriv.h b/keychain/headers/SecItemPriv.h new file mode 100644 index 00000000..c458816d --- /dev/null +++ b/keychain/headers/SecItemPriv.h @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemPriv + SecItemPriv defines private constants and SPI functions for access to + Security items (certificates, identities, keys, and keychain items.) +*/ + +#ifndef _SECURITY_SECITEMPRIV_H_ +#define _SECURITY_SECITEMPRIV_H_ + +#include +#include +#include +#include +#include +#include + +#if TARGET_OS_OSX +#include +#endif + +#if __OBJC__ +#import +#endif + +__BEGIN_DECLS + +/*! + @enum Class Value Constants (Private) + @discussion Predefined item class constants used to get or set values in + a dictionary. The kSecClass constant is the key and its value is one + of the constants defined here. + @constant kSecClassAppleSharePassword Specifies AppleShare password items. +*/ +extern const CFStringRef kSecClassAppleSharePassword; + + +/*! + @enum Attribute Key Constants (Private) + @discussion Predefined item attribute keys used to get or set values in a + dictionary. Not all attributes apply to each item class. The table + below lists the currently defined attributes for each item class: + + kSecClassGenericPassword item attributes: + kSecAttrAccessGroup + kSecAttrCreationDate + kSecAttrModificationDate + kSecAttrDescription + kSecAttrComment + kSecAttrCreator + kSecAttrType + kSecAttrScriptCode (private) + kSecAttrLabel + kSecAttrAlias (private) + kSecAttrIsInvisible + kSecAttrIsNegative + kSecAttrHasCustomIcon (private) + kSecAttrProtected (private) + kSecAttrAccount + kSecAttrService + kSecAttrGeneric + kSecAttrSynchronizable + kSecAttrSyncViewHint + + kSecClassInternetPassword item attributes: + kSecAttrAccessGroup + kSecAttrCreationDate + kSecAttrModificationDate + kSecAttrDescription + kSecAttrComment + kSecAttrCreator + kSecAttrType + kSecAttrScriptCode (private) + kSecAttrLabel + kSecAttrAlias (private) + kSecAttrIsInvisible + kSecAttrIsNegative + kSecAttrHasCustomIcon (private) + kSecAttrProtected (private) + kSecAttrAccount + kSecAttrSecurityDomain + kSecAttrServer + kSecAttrProtocol + kSecAttrAuthenticationType + kSecAttrPort + kSecAttrPath + kSecAttrSynchronizable + kSecAttrSyncViewHint + + kSecClassAppleSharePassword item attributes: + kSecAttrAccessGroup + kSecAttrCreationDate + kSecAttrModificationDate + kSecAttrDescription + kSecAttrComment + kSecAttrCreator + kSecAttrType + kSecAttrScriptCode (private) + kSecAttrLabel + kSecAttrAlias (private) + kSecAttrIsInvisible + kSecAttrIsNegative + kSecAttrHasCustomIcon (private) + kSecAttrProtected (private) + kSecAttrAccount + kSecAttrVolume + kSecAttrAddress + kSecAttrAFPServerSignature + kSecAttrSynchronizable + kSecAttrSyncViewHint + + kSecClassCertificate item attributes: + kSecAttrAccessGroup + kSecAttrCertificateType + kSecAttrCertificateEncoding + kSecAttrLabel + kSecAttrAlias (private) + kSecAttrSubject + kSecAttrIssuer + kSecAttrSerialNumber + kSecAttrSubjectKeyID + kSecAttrPublicKeyHash + kSecAttrSynchronizable + kSecAttrSyncViewHint + + kSecClassKey item attributes: + kSecAttrAccessGroup + kSecAttrKeyClass + kSecAttrLabel + kSecAttrAlias (private) + kSecAttrApplicationLabel + kSecAttrIsPermanent + kSecAttrIsPrivate (private) + kSecAttrIsModifiable (private) + kSecAttrApplicationTag + kSecAttrKeyCreator (private) + kSecAttrKeyType + kSecAttrKeySizeInBits + kSecAttrEffectiveKeySize + kSecAttrStartDate (private) + kSecAttrEndDate (private) + kSecAttrIsSensitive (private) + kSecAttrWasAlwaysSensitive (private) + kSecAttrIsExtractable (private) + kSecAttrWasNeverExtractable (private) + kSecAttrCanEncrypt + kSecAttrCanDecrypt + kSecAttrCanDerive + kSecAttrCanSign + kSecAttrCanVerify + kSecAttrCanSignRecover (private) + kSecAttrCanVerifyRecover (private) + kSecAttrCanWrap + kSecAttrCanUnwrap + kSecAttrSynchronizable + kSecAttrSyncViewHint + + kSecClassIdentity item attributes: + Since an identity is the combination of a private key and a + certificate, this class shares attributes of both kSecClassKey and + kSecClassCertificate. + + @constant kSecAttrScriptCode Specifies a dictionary key whose value is the + item's script code attribute. You use this tag to set or get a value + of type CFNumberRef that represents a script code for this item's + strings. (Note: use of this attribute is deprecated; string attributes + should always be stored in UTF-8 encoding. This is currently private + for use by syncing; new code should not ever access this attribute.) + @constant kSecAttrAlias Specifies a dictionary key whose value is the + item's alias. You use this key to get or set a value of type CFDataRef + which represents an alias. For certificate items, the alias is either + a single email address, an array of email addresses, or the common + name of the certificate if it does not contain any email address. + (Items of class kSecClassCertificate have this attribute.) + @constant kSecAttrHasCustomIcon Specifies a dictionary key whose value is the + item's custom icon attribute. You use this tag to set or get a value + of type CFBooleanRef that indicates whether the item should have an + application-specific icon. (Note: use of this attribute is deprecated; + custom item icons are not supported in Mac OS X. This is currently + private for use by syncing; new code should not use this attribute.) + @constant kSecAttrVolume Specifies a dictionary key whose value is the + item's volume attribute. You use this key to set or get a CFStringRef + value that represents an AppleShare volume name. (Items of class + kSecClassAppleSharePassword have this attribute.) + @constant kSecAttrAddress Specifies a dictionary key whose value is the + item's address attribute. You use this key to set or get a CFStringRef + value that contains the AppleTalk zone name, or the IP or domain name + that represents the server address. (Items of class + kSecClassAppleSharePassword have this attribute.) + @constant kSecAttrAFPServerSignature Specifies a dictionary key whose value + is the item's AFP server signature attribute. You use this key to set + or get a CFDataRef value containing 16 bytes that represents the + server's signature block. (Items of class kSecClassAppleSharePassword + have this attribute.) + @constant kSecAttrCRLType (read-only) Specifies a dictionary key whose + value is the item's certificate revocation list type. You use this + key to get a value of type CFNumberRef that denotes the CRL type (see + the CSSM_CRL_TYPE enum in cssmtype.h). (Items of class + kSecClassCertificate have this attribute.) + @constant kSecAttrCRLEncoding (read-only) Specifies a dictionary key whose + value is the item's certificate revocation list encoding. You use + this key to get a value of type CFNumberRef that denotes the CRL + encoding (see the CSSM_CRL_ENCODING enum in cssmtype.h). (Items of + class kSecClassCertificate have this attribute.) + @constant kSecAttrKeyCreator Specifies a dictionary key whose value is a + CFDataRef containing a CSSM_GUID structure representing the module ID of + the CSP that owns this key. + @constant kSecAttrIsPrivate Specifies a dictionary key whose value is a + CFBooleanRef indicating whether the raw key material of the key in + question is private. + @constant kSecAttrIsModifiable Specifies a dictionary key whose value is a + CFBooleanRef indicating whether any of the attributes of this key are + modifiable. + @constant kSecAttrStartDate Specifies a dictionary key whose value is a + CFDateRef indicating the earliest date on which this key may be used. + If kSecAttrStartDate is not present, the restriction does not apply. + @constant kSecAttrEndDate Specifies a dictionary key whose value is a + CFDateRef indicating the last date on which this key may be used. + If kSecAttrEndDate is not present, the restriction does not apply. + @constant kSecAttrIsSensitive Specifies a dictionary key whose value + is a CFBooleanRef indicating whether the key in question must be wrapped + with an algorithm other than CSSM_ALGID_NONE. + @constant kSecAttrWasAlwaysSensitive Specifies a dictionary key whose value + is a CFBooleanRef indicating that the key in question has always been + marked as sensitive. + @constant kSecAttrIsExtractable Specifies a dictionary key whose value + is a CFBooleanRef indicating whether the key in question may be wrapped. + @constant kSecAttrWasNeverExtractable Specifies a dictionary key whose value + is a CFBooleanRef indicating that the key in question has never been + marked as extractable. + @constant kSecAttrCanSignRecover Specifies a dictionary key whole value is a + CFBooleanRef indicating whether the key in question can be used to + perform sign recovery. + @constant kSecAttrCanVerifyRecover Specifies a dictionary key whole value is + a CFBooleanRef indicating whether the key in question can be used to + perform verify recovery. + @constant kSecAttrTombstone Specifies a dictionary key whose value is + a CFBooleanRef indicating that the item in question is a tombstone. + @constant kSecAttrNoLegacy Specifies a dictionary key whose + value is a CFBooleanRef indicating that the query must be run on the + syncable backend even for non syncable items. This attribute is deprecated + in favor of the kSecUseDataProtectionKeychain API attribute. +*/ +extern const CFStringRef kSecAttrScriptCode; +extern const CFStringRef kSecAttrAlias; +extern const CFStringRef kSecAttrHasCustomIcon; +extern const CFStringRef kSecAttrVolume; +extern const CFStringRef kSecAttrAddress; +extern const CFStringRef kSecAttrAFPServerSignature; +extern const CFStringRef kSecAttrCRLType; +extern const CFStringRef kSecAttrCRLEncoding; +extern const CFStringRef kSecAttrKeyCreator; +extern const CFStringRef kSecAttrIsPrivate; +extern const CFStringRef kSecAttrIsModifiable; +extern const CFStringRef kSecAttrStartDate; +extern const CFStringRef kSecAttrEndDate; +extern const CFStringRef kSecAttrIsSensitive; +extern const CFStringRef kSecAttrWasAlwaysSensitive; +extern const CFStringRef kSecAttrIsExtractable; +extern const CFStringRef kSecAttrWasNeverExtractable; +extern const CFStringRef kSecAttrCanSignRecover; +extern const CFStringRef kSecAttrCanVerifyRecover; +extern const CFStringRef kSecAttrTombstone; +extern const CFStringRef kSecAttrNoLegacy + __API_DEPRECATED_WITH_REPLACEMENT("kSecUseDataProtectionKeychain", macos(10.11, 10.15), ios(9.3, 13.0), tvos(9.3, 13.0), watchos(2.3, 6.0)); +extern const CFStringRef kSecAttrSyncViewHint + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecAttrMultiUser + __OSX_AVAILABLE(10.11.5) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); + +/* This will force the syncing system to derive an item's plaintext synchronization id from its primary key. + * This might leak primary key information, but will cause syncing devices to discover sync conflicts sooner. + * Protected by the kSecEntitlementPrivateCKKSPlaintextFields entitlement. + * + * Will only be respected during a SecItemAdd. + */ +extern const CFStringRef kSecAttrDeriveSyncIDFromItemAttributes +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextServiceIdentifier + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextPublicKey + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextPublicIdentity + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +// ObjectID of item stored on the token. Token-type specific BLOB. +// For kSecAttrTokenIDSecureEnclave and kSecAttrTokenIDAppleKeyStore, ObjectID is libaks's blob representation of encoded key. +extern const CFStringRef kSecAttrTokenOID + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const CFStringRef kSecAttrUUID + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrSysBound + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +#define kSecSecAttrSysBoundNot 0 +#define kSecSecAttrSysBoundPreserveDuringRestore 1 + + +extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandomPKA + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrKeyTypeSecureEnclaveAttestation + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +// Should not be used, use kSecAttrTokenOID instead. +extern const CFStringRef kSecAttrSecureEnclaveKeyBlob + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @enum kSecAttrAccessible Value Constants (Private) + @constant kSecAttrAccessibleAlwaysPrivate Private alias for kSecAttrAccessibleAlways, + which is going to be deprecated for 3rd party use. + @constant kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate for kSecAttrAccessibleAlwaysThisDeviceOnly, + which is going to be deprecated for 3rd party use. + @constant kSecAttrAccessibleUntilReboot Not usable for keychain item. Can be used only + for generating non-permanent SEP-based SecKey. Such key does not need any keybag loaded and + is valid only until next reboot. Also known as class F protection. +*/ +extern const CFStringRef kSecAttrAccessibleAlwaysPrivate +;//%%% __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate +;//%%% __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecAttrAccessibleUntilReboot +API_AVAILABLE(macos(10.14.1), ios(12.1), tvos(12.1), watchos(5.1)); + +/* View Hint Constants */ + +extern const CFStringRef kSecAttrViewHintPCSMasterKey; +extern const CFStringRef kSecAttrViewHintPCSiCloudDrive; +extern const CFStringRef kSecAttrViewHintPCSPhotos; +extern const CFStringRef kSecAttrViewHintPCSCloudKit; +extern const CFStringRef kSecAttrViewHintPCSEscrow; +extern const CFStringRef kSecAttrViewHintPCSFDE; +extern const CFStringRef kSecAttrViewHintPCSMailDrop; +extern const CFStringRef kSecAttrViewHintPCSiCloudBackup; +extern const CFStringRef kSecAttrViewHintPCSNotes; +extern const CFStringRef kSecAttrViewHintPCSiMessage; +extern const CFStringRef kSecAttrViewHintPCSFeldspar; +extern const CFStringRef kSecAttrViewHintPCSSharing; + +extern const CFStringRef kSecAttrViewHintAppleTV; +extern const CFStringRef kSecAttrViewHintHomeKit; +extern const CFStringRef kSecAttrViewHintContinuityUnlock; +extern const CFStringRef kSecAttrViewHintAccessoryPairing; +extern const CFStringRef kSecAttrViewHintNanoRegistry; +extern const CFStringRef kSecAttrViewHintWatchMigration; +extern const CFStringRef kSecAttrViewHintEngram; +extern const CFStringRef kSecAttrViewHintManatee; +extern const CFStringRef kSecAttrViewHintAutoUnlock; +extern const CFStringRef kSecAttrViewHintHealth; +extern const CFStringRef kSecAttrViewHintApplePay; +extern const CFStringRef kSecAttrViewHintHome; +extern const CFStringRef kSecAttrViewHintLimitedPeersAllowed; + + +extern const CFStringRef kSecUseSystemKeychain + __TVOS_AVAILABLE(9.2) + __WATCHOS_AVAILABLE(3.0) + __OSX_AVAILABLE(10.11.4) + __IOS_AVAILABLE(9.3); + +extern const CFStringRef kSecUseSyncBubbleKeychain + __TVOS_AVAILABLE(9.2) + __WATCHOS_AVAILABLE(3.0) + __OSX_AVAILABLE(10.11.4) + __IOS_AVAILABLE(9.3); + +/*! + @enum Other Constants (Private) + @discussion Predefined constants used to set values in a dictionary. + @constant kSecUseTombstones Specifies a dictionary key whose value is a + CFBooleanRef if present this overrides the default behaviour for when + we make tombstones. The default being we create tombstones for + synchronizable items unless we are explicitly deleting or updating a + tombstone. Setting this to false when calling SecItemDelete or + SecItemUpdate will ensure no tombstones are created. Setting it to + true will ensure we create tombstones even when deleting or updating non + synchronizable items. + @constant kSecUseKeychain Specifies a dictionary key whose value is a + keychain reference. You use this key to specify a value of type + SecKeychainRef that indicates the keychain to which SecItemAdd + will add the provided item(s). + @constant kSecUseKeychainList Specifies a dictionary key whose value is + either an array of keychains to search (CFArrayRef), or a single + keychain (SecKeychainRef). If not provided, the user's default + keychain list is searched. kSecUseKeychainList is ignored if an + explicit kSecUseItemList is also provided. This key can be used + for the SecItemCopyMatching, SecItemUpdate and SecItemDelete calls. + @constant kSecUseCredentialReference Specifies a CFDataRef containing + AppleCredentialManager reference handle to be used when authorizing access + to the item. + @constant kSecUseCallerName Specifies a dictionary key whose value + is a CFStringRef that represents a user-visible string describing + the caller name for which the application is attempting to authenticate. + The caller must have 'com.apple.private.LocalAuthentication.CallerName' + entitlement set to YES to use this feature, otherwise it is ignored. + @constant kSecUseTokenRawItems If set to true, token-based items (i.e. those + which have non-empty kSecAttrTokenID are not going through client-side + postprocessing, only raw form stored in the database is listed. This + flag is ignored in other operations than SecItemCopyMatching(). + @constant kSecUseCertificatesWithMatchIssuers If set to true, + SecItemCopyMatching allows to return certificates when kSecMatchIssuers is specified. +*/ +extern const CFStringRef kSecUseTombstones + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecUseCredentialReference + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); +extern const CFStringRef kSecUseCallerName + __OSX_AVAILABLE(10.11.4) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); +extern const CFStringRef kSecUseTokenRawItems + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecUseCertificatesWithMatchIssuers + __OSX_AVAILABLE(10.14) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); + +extern const CFStringRef kSOSInternalAccessGroup + __OSX_AVAILABLE(10.9) __IOS_AVAILABLE(7.0) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); + +/*! + @enum kSecAttrTokenID Value Constants + @discussion Predefined item attribute constant used to get or set values + in a dictionary. The kSecAttrTokenID constant is the key and its value + can be kSecAttrTokenIDSecureEnclave. + @constant kSecAttrTokenIDKeyAppleStore Specifies well-known identifier of + the token implemented using libaks (AppleKeyStore). This token is identical to + kSecAttrTokenIDSecureEnclave for devices which support Secure Enclave and + silently falls back to in-kernel emulation for those devices which do not + have Secure Enclave support. + */ +extern const CFStringRef kSecAttrTokenIDAppleKeyStore + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(3.0); + + +extern const CFStringRef kSecNetworkExtensionAccessGroupSuffix; + +/*! + @function SecItemCopyDisplayNames + @abstract Returns an array containing unique display names for each of the + certificates, keys, identities, or passwords in the provided items + array. + @param items An array containing items of type SecKeychainItemRef, + SecKeyRef, SecCertificateRef, or SecIdentityRef. All items in the + array should be of the same type. + @param displayNames On return, an array of CFString references containing + unique names for the supplied items. You are responsible for releasing + this array reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Use this function to obtain item names which are suitable for + display in a menu or list view. The returned names are guaranteed to + be unique across the set of provided items. +*/ +OSStatus SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames); + +/*! + @function SecItemDeleteAll + @abstract Removes all items from the keychain. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecItemDeleteAll(void); + +/*! + @function _SecItemAddAndNotifyOnSync + @abstract Adds an item to the keychain, and calls syncCallback when the item has synced + @param attributes Attributes dictionary to be passed to SecItemAdd + @param result Result reference to be passed to SecItemAdd + @param syncCallback Block to be executed after the item has synced or failed to sync + @result The result code returned from SecItemAdd + */ +OSStatus _SecItemAddAndNotifyOnSync(CFDictionaryRef attributes, CFTypeRef * CF_RETURNS_RETAINED result, void (^syncCallback)(bool didSync, CFErrorRef error)); + +/*! + @function SecItemSetCurrentItemAcrossAllDevices + @abstract Sets 'new current item' to be the 'current' item in CloudKit for the given identifier. + */ +void SecItemSetCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + CFDataRef newCurrentItemReference, + CFDataRef newCurrentItemHash, + CFDataRef oldCurrentItemReference, + CFDataRef oldCurrentItemHash, + void (^complete)(CFErrorRef error)); + +/*! + @function SecItemFetchCurrentItemAcrossAllDevices + @abstract Fetches the locally cached idea of which keychain item is 'current' across this iCloud account + for the given access group and identifier. + @param accessGroup The accessGroup of your process and the expected current item + @param identifier Which 'current' item you're interested in. Freeform, but should match the ID given to + SecItemSetCurrentItemAcrossAllDevices. + @param viewHint The keychain view hint for your items. + @param fetchCloudValue If false, will return the local machine's cached idea of which item is current. If true, + performs a CloudKit operation to determine the most up-to-date version. + @param complete Called to return values: a persistent ref to the current item, if such an item exists. Otherwise, error. + */ +void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + bool fetchCloudValue, + void (^complete)(CFDataRef persistentRef, CFErrorRef error)); + +#if __OBJC__ +/*! + @function SecItemVerifyBackupIntegrity + @abstract Verifies the presence and integrity of all key material required + to restore a backup of the keychain. + @param lightweight Only verify the item keys wrapped by backup keys instead + of the default rigorous pass. This mode can be run in any + security class. + @param completion Called to indicate results: a dictionary containing information about the the infrastructure + and of the backup state of keychain items. Error is set when at least one failure occurred. + */ +void SecItemVerifyBackupIntegrity(BOOL lightweight, + void(^completion)(NSDictionary* resultsPerKeyclass, NSError* error)); +void _SecItemFetchDigests(NSString *itemClass, NSString *accessGroup, void (^complete)(NSArray *, NSError *)); +void _SecKeychainDeleteMultiUser(NSString *musrUUID, void (^complete)(bool, NSError *)); +#endif + +/*! + @function SecItemDeleteAllWithAccessGroups + @abstract Deletes all items for each class for the given access groups + @param accessGroups An array of access groups for the items + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Provided for use by MobileInstallation to allow cleanup after uninstall + Requires entitlement "com.apple.private.uninstall.deletion" + */ +bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error); + +/* + Ensure the escrow keybag has been used to unlock the system keybag before + calling either of these APIs. + The password argument is optional, passing NULL implies no backup password + was set. We're assuming there will always be a backup keybag, except in + the OTA case where the loaded OTA backup bag will be used. + */ +CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password); +CFDataRef _SecKeychainCopyOTABackup(void); +OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag, + CFDataRef password); +/* + EMCS backups are similar to regular backups but we do not want to unlock the keybag + */ +CFDataRef _SecKeychainCopyEMCSBackup(CFDataRef backupKeybag); + +bool +_SecKeychainWriteBackupToFileDescriptor(CFDataRef backupKeybag, CFDataRef password, int fd, CFErrorRef *error); + +bool +_SecKeychainRestoreBackupFromFileDescriptor(int fd, CFDataRef backupKeybag, CFDataRef password, CFErrorRef *error); + +CFStringRef +_SecKeychainCopyKeybagUUIDFromFileDescriptor(int fd, CFErrorRef *error); + +OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out); +OSStatus _SecKeychainRestoreSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in); + +/* Called by clients to push sync circle and message changes to us. + Requires caller to have the kSecEntitlementKeychainSyncUpdates entitlement. */ +CFArrayRef _SecKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error); + +#if !TARGET_OS_IPHONE +CFDataRef _SecItemGetPersistentReference(CFTypeRef raw_item); +#endif + +/* Returns an OSStatus value for the given CFErrorRef, returns errSecInternal if the + domain of the provided error is not recognized. Passing NULL returns errSecSuccess (0). */ +OSStatus SecErrorGetOSStatus(CFErrorRef error); + +bool _SecKeychainRollKeys(bool force, CFErrorRef *error); + +CFDictionaryRef _SecSecuritydCopyWhoAmI(CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopySFKeychainEndpoint(CFErrorRef* error); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyKeychainControlEndpoint(CFErrorRef* error); + +bool _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error); + +bool _SecSystemKeychainTransfer(CFErrorRef *error); +bool _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error); + + + +OSStatus SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes); + +#if SEC_OS_OSX +CFTypeRef SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes); +#endif + +/*! + * @function SecCopyLastError + * @abstract return the last CFErrorRef for this thread + * @param status the error code returned from the API call w/o CFErrorRef or 0 + * @result NULL or a retained CFError of the matching error code + * + * @discussion There are plenty of API calls in Security.framework that + * doesn't return an CFError in case of an error, many of them actually have + * a CFErrorRef internally, but throw it away at the last moment. + * This might be your chance to get hold of it. The status code pass in is there + * to avoid stale copies of CFErrorRef. + + * Note, not all interfaces support returning a CFErrorRef on the thread local + * storage. This is especially true when going though old CDSA style API. + */ + +CFErrorRef +SecCopyLastError(OSStatus status) + __TVOS_AVAILABLE(10.0) + __WATCHOS_AVAILABLE(3.0) + __IOS_AVAILABLE(10.0); + + +bool +SecItemUpdateWithError(CFDictionaryRef inQuery, + CFDictionaryRef inAttributesToUpdate, + CFErrorRef *error) + __TVOS_AVAILABLE(10.0) + __WATCHOS_AVAILABLE(3.0) + __IOS_AVAILABLE(10.0); + +#if SEC_OS_OSX +/*! + @function SecItemParentCachePurge + @abstract Clear the cache of parent certificates used in SecItemCopyParentCertificates_osx. + */ +void SecItemParentCachePurge(void); +#endif + + +#if SEC_OS_OSX_INCLUDES +/*! + @function SecItemCopyParentCertificates_osx + @abstract Retrieve an array of possible issuing certificates for a given certificate. + @param certificate A reference to a certificate whose issuers are being sought. + @param context Pass NULL in this parameter to indicate that the default certificate + source(s) should be searched. The default is to search all available keychains. + Values of context other than NULL are currently ignored. + @result An array of zero or more certificates whose normalized subject matches the + normalized issuer of the provided certificate. Note that no cryptographic validation + of the signature is performed by this function; its purpose is only to provide a list + of candidate certificates. + */ +CFArrayRef SecItemCopyParentCertificates_osx(SecCertificateRef certificate, void *context) +__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); + +/*! + @function SecItemCopyStoredCertificate + @abstract Retrieve the first stored instance of a given certificate. + @param certificate A reference to a certificate. + @param context Pass NULL in this parameter to indicate that the default certificate + source(s) should be searched. The default is to search all available keychains. + Values of context other than NULL are currently ignored. + @result Returns a certificate reference if the given certificate exists in a keychain, + or NULL if the certificate cannot be found in any keychain. The caller is responsible + for releasing the returned certificate reference when finished with it. + */ +SecCertificateRef SecItemCopyStoredCertificate(SecCertificateRef certificate, void *context) +__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); +#endif /* SEC_OS_OSX */ + +/*! + @enum kSecAttrTokenID Value Constants + @discussion Predefined item attribute constant used to get or set values + in a dictionary. The kSecAttrTokenID constant is the key and its value + can be kSecAttrTokenIDSecureEnclave or kSecAttrTokenIDSecureElement. + @constant kSecAttrTokenIDSecureElement Specifies well-known identifier of the + token implemented using device's Secure Element. The only keychain items + supported by the Secure Element token are 256-bit elliptic curve keys + (kSecAttrKeyTypeECSecPrimeRandom). Keys must be generated on the secure element using + SecKeyCreateRandomKey call with kSecAttrTokenID set to + kSecAttrTokenIDSecureElement in the parameters dictionary, it is not + possible to import pregenerated keys to kSecAttrTokenIDSecureElement token. + */ +extern const CFStringRef kSecAttrTokenIDSecureElement +SPI_AVAILABLE(ios(10.13)); + +__END_DECLS + +#endif /* !_SECURITY_SECITEMPRIV_H_ */ diff --git a/keychain/headers/SecKey.h b/keychain/headers/SecKey.h new file mode 100644 index 00000000..021a672a --- /dev/null +++ b/keychain/headers/SecKey.h @@ -0,0 +1,1558 @@ +/* + * Copyright (c) 2006-2014,2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecKey + The functions provided in SecKey.h implement and manage a particular + type of keychain item that represents a key. A key can be stored in a + keychain, but a key can also be a transient object. + + On OSX, you can use a SecKey as a SecKeychainItem in most functions. +*/ + +#ifndef _SECURITY_SECKEY_H_ +#define _SECURITY_SECKEY_H_ + +#include +#include +#include +#include +#include + +#if SEC_OS_OSX +#include +#include +#endif /* SEC_OS_OSX */ + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +#if SEC_OS_OSX +/*! + @enum KeyItemAttributeConstants + @abstract Specifies keychain item attributes for keys. + @constant kSecKeyKeyClass type uint32 (CSSM_KEYCLASS), value + is one of CSSM_KEYCLASS_PUBLIC_KEY, CSSM_KEYCLASS_PRIVATE_KEY + or CSSM_KEYCLASS_SESSION_KEY. + @constant kSecKeyPrintName type blob, human readable name of + the key. Same as kSecLabelItemAttr for normal keychain items. + @constant kSecKeyAlias type blob, currently unused. + @constant kSecKeyPermanent type uint32, value is nonzero iff + this key is permanent (stored in some keychain). This is always + 1. + @constant kSecKeyPrivate type uint32, value is nonzero iff this + key is protected by a user login or a password, or both. + @constant kSecKeyModifiable type uint32, value is nonzero iff + attributes of this key can be modified. + @constant kSecKeyLabel type blob, for private and public keys + this contains the hash of the public key. This is used to + associate certificates and keys. Its value matches the value + of the kSecPublicKeyHashItemAttr of a certificate and it's used + to construct an identity from a certificate and a key. + For symmetric keys this is whatever the creator of the key + passed in during the generate key call. + @constant kSecKeyApplicationTag type blob, currently unused. + @constant kSecKeyKeyCreator type data, the data points to a + CSSM_GUID structure representing the moduleid of the csp owning + this key. + @constant kSecKeyKeyType type uint32, value is a CSSM_ALGORITHMS + representing the algorithm associated with this key. + @constant kSecKeyKeySizeInBits type uint32, value is the number + of bits in this key. + @constant kSecKeyEffectiveKeySize type uint32, value is the + effective number of bits in this key. For example a des key + has a kSecKeyKeySizeInBits of 64 but a kSecKeyEffectiveKeySize + of 56. + @constant kSecKeyStartDate type CSSM_DATE. Earliest date from + which this key may be used. If the value is all zeros or not + present, no restriction applies. + @constant kSecKeyEndDate type CSSM_DATE. Latest date at + which this key may be used. If the value is all zeros or not + present, no restriction applies. + @constant kSecKeySensitive type uint32, iff value is nonzero + this key cannot be wrapped with CSSM_ALGID_NONE. + @constant kSecKeyAlwaysSensitive type uint32, value is nonzero + iff this key has always been marked sensitive. + @constant kSecKeyExtractable type uint32, value is nonzero iff + this key can be wrapped. + @constant kSecKeyNeverExtractable type uint32, value is nonzero + iff this key was never marked extractable. + @constant kSecKeyEncrypt type uint32, value is nonzero iff this + key can be used in an encrypt operation. + @constant kSecKeyDecrypt type uint32, value is nonzero iff this + key can be used in a decrypt operation. + @constant kSecKeyDerive type uint32, value is nonzero iff this + key can be used in a deriveKey operation. + @constant kSecKeySign type uint32, value is nonzero iff this + key can be used in a sign operation. + @constant kSecKeyVerify type uint32, value is nonzero iff this + key can be used in a verify operation. + @constant kSecKeySignRecover type uint32. + @constant kSecKeyVerifyRecover type uint32. + key can unwrap other keys. + @constant kSecKeyWrap type uint32, value is nonzero iff this + key can wrap other keys. + @constant kSecKeyUnwrap type uint32, value is nonzero iff this + key can unwrap other keys. + @discussion + The use of these enumerations has been deprecated. Please + use the equivalent items defined in SecItem.h + @@@. +*/ +CF_ENUM(int) +{ + kSecKeyKeyClass = 0, + kSecKeyPrintName = 1, + kSecKeyAlias = 2, + kSecKeyPermanent = 3, + kSecKeyPrivate = 4, + kSecKeyModifiable = 5, + kSecKeyLabel = 6, + kSecKeyApplicationTag = 7, + kSecKeyKeyCreator = 8, + kSecKeyKeyType = 9, + kSecKeyKeySizeInBits = 10, + kSecKeyEffectiveKeySize = 11, + kSecKeyStartDate = 12, + kSecKeyEndDate = 13, + kSecKeySensitive = 14, + kSecKeyAlwaysSensitive = 15, + kSecKeyExtractable = 16, + kSecKeyNeverExtractable = 17, + kSecKeyEncrypt = 18, + kSecKeyDecrypt = 19, + kSecKeyDerive = 20, + kSecKeySign = 21, + kSecKeyVerify = 22, + kSecKeySignRecover = 23, + kSecKeyVerifyRecover = 24, + kSecKeyWrap = 25, + kSecKeyUnwrap = 26 +}; + + /*! + @enum SecCredentialType + @abstract Determines the type of credential returned by SecKeyGetCredentials. + @constant kSecCredentialTypeWithUI Operations with this key are allowed to present UI if required. + @constant kSecCredentialTypeNoUI Operations with this key are not allowed to present UI, and will fail if UI is required. + @constant kSecCredentialTypeDefault The default setting for determining whether to present UI is used. This setting can be changed with a call to SecKeychainSetUserInteractionAllowed. +*/ +typedef CF_ENUM(uint32, SecCredentialType) +{ + kSecCredentialTypeDefault = 0, + kSecCredentialTypeWithUI, + kSecCredentialTypeNoUI +}; +#endif /* SEC_OS_OSX */ + +/*! + @typedef SecPadding + @abstract Supported padding types. +*/ +typedef CF_OPTIONS(uint32_t, SecPadding) +{ + kSecPaddingNone = 0, + kSecPaddingPKCS1 = 1, + kSecPaddingOAEP = 2, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0), + + /* For SecKeyRawSign/SecKeyRawVerify only, + ECDSA signature is raw byte format {r,s}, big endian. + First half is r, second half is s */ + kSecPaddingSigRaw = 0x4000, + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD2 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1MD2 = 0x8000, // __OSX_DEPRECATED(10.0, 10.12, "MD2 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD2 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE, + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD5 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1MD5 = 0x8001, // __OSX_DEPRECATED(10.0, 10.12, "MD5 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD5 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE, + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA1 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1SHA1 = 0x8002, + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA224 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1SHA224 = 0x8003, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA256 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1SHA256 = 0x8004, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA384 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1SHA384 = 0x8005, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), + + /* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA512 + hash; standard ASN.1 padding will be done, as well as PKCS1 padding + of the underlying RSA operation. */ + kSecPaddingPKCS1SHA512 = 0x8006, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0), +}; + +#if SEC_OS_OSX +/*! + @typedef SecKeySizes + @abstract Supported key lengths. +*/ +typedef CF_ENUM(uint32_t, SecKeySizes) +{ + kSecDefaultKeySize = 0, + + // Symmetric Keysizes - default is currently kSecAES128 for AES. + kSec3DES192 = 192, + kSecAES128 = 128, + kSecAES192 = 192, + kSecAES256 = 256, + + // Supported ECC Keys for Suite-B from RFC 4492 section 5.1.1. + // default is currently kSecp256r1 + kSecp192r1 = 192, + kSecp256r1 = 256, + kSecp384r1 = 384, + kSecp521r1 = 521, // Yes, 521 + + // Boundaries for RSA KeySizes - default is currently 2048 + // RSA keysizes must be multiples of 8 + kSecRSAMin = 1024, + kSecRSAMax = 4096 +}; +#endif /* SEC_OS_OSX */ + +/*! + @enum Key Parameter Constants + @discussion Predefined key constants used to get or set values in a dictionary. + These are used to provide explicit parameters to key generation functions + when non-default values are desired. See the description of the + SecKeyGeneratePair API for usage information. + @constant kSecPrivateKeyAttrs The value for this key is a CFDictionaryRef + containing attributes specific for the private key to be generated. + @constant kSecPublicKeyAttrs The value for this key is a CFDictionaryRef + containing attributes specific for the public key to be generated. +*/ +extern const CFStringRef kSecPrivateKeyAttrs + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_2_0); +extern const CFStringRef kSecPublicKeyAttrs + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_2_0); + +/*! + @function SecKeyGetTypeID + @abstract Returns the type identifier of SecKey instances. + @result The CFTypeID of SecKey instances. +*/ +CFTypeID SecKeyGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + + +#if SEC_OS_OSX +/*! + @function SecKeyCreatePair + @abstract Creates an asymmetric key pair and stores it in a specified keychain. + @param keychainRef A reference to the keychain in which to store the private and public key items. Specify NULL for the default keychain. + @param algorithm An algorithm for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. + @param keySizeInBits A key size for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. + @param contextHandle (optional) A CSSM_CC_HANDLE, or 0. If this argument is supplied, the algorithm and keySizeInBits parameters are ignored. If extra parameters are needed to generate a key (some algorithms require this), you should create a context using CSSM_CSP_CreateKeyGenContext, using the CSPHandle obtained by calling SecKeychainGetCSPHandle. Then use CSSM_UpdateContextAttributes to add parameters, and dispose of the context using CSSM_DeleteContext after calling this function. + @param publicKeyUsage A bit mask indicating all permitted uses for the new public key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. + @param publicKeyAttr A bit mask defining attribute values for the new public key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. + @param privateKeyUsage A bit mask indicating all permitted uses for the new private key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. + @param privateKeyAttr A bit mask defining attribute values for the new private key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. + @param initialAccess (optional) A SecAccess object that determines the initial access rights to the private key. The public key is given "any/any" access rights by default. + @param publicKey (optional) On return, the keychain item reference of the generated public key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. Pass NULL if a reference to this key is not required. + @param privateKey (optional) On return, the keychain item reference of the generated private key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. Pass NULL if a reference to this key is not required. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated for 10.7. Please use the SecKeyGeneratePair API instead. +*/ +OSStatus SecKeyCreatePair( + SecKeychainRef _Nullable keychainRef, + CSSM_ALGORITHMS algorithm, + uint32 keySizeInBits, + CSSM_CC_HANDLE contextHandle, + CSSM_KEYUSE publicKeyUsage, + uint32 publicKeyAttr, + CSSM_KEYUSE privateKeyUsage, + uint32 privateKeyAttr, + SecAccessRef _Nullable initialAccess, + SecKeyRef* _Nullable CF_RETURNS_RETAINED publicKey, + SecKeyRef* _Nullable CF_RETURNS_RETAINED privateKey) + CSSM_DEPRECATED; + +/*! + @function SecKeyGenerate + @abstract Creates a symmetric key and optionally stores it in a specified keychain. + @param keychainRef (optional) A reference to the keychain in which to store the generated key. Specify NULL to generate a transient key. + @param algorithm An algorithm for the symmetric key. This parameter is ignored if a valid (non-zero) contextHandle is supplied. + @param keySizeInBits A key size for the key pair. This parameter is ignored if a valid (non-zero) contextHandle is supplied. + @param contextHandle (optional) A CSSM_CC_HANDLE, or 0. If this argument is supplied, the algorithm and keySizeInBits parameters are ignored. If extra parameters are needed to generate a key (some algorithms require this), you should create a context using CSSM_CSP_CreateKeyGenContext, using the CSPHandle obtained by calling SecKeychainGetCSPHandle. Then use CSSM_UpdateContextAttributes to add parameters, and dispose of the context using CSSM_DeleteContext after calling this function. + @param keyUsage A bit mask indicating all permitted uses for the new key. CSSM_KEYUSE bit mask values are defined in cssmtype.h. + @param keyAttr A bit mask defining attribute values for the new key. The bit mask values are equivalent to a CSSM_KEYATTR_FLAGS and are defined in cssmtype.h. + @param initialAccess (optional) A SecAccess object that determines the initial access rights for the key. This parameter is ignored if the keychainRef is NULL. + @param keyRef On return, a reference to the generated key. Use the SecKeyGetCSSMKey function to obtain the CSSM_KEY. The caller must call CFRelease on this value if it is returned. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated for 10.7. Please use the SecKeyGenerateSymmetric API instead. +*/ +OSStatus SecKeyGenerate( + SecKeychainRef _Nullable keychainRef, + CSSM_ALGORITHMS algorithm, + uint32 keySizeInBits, + CSSM_CC_HANDLE contextHandle, + CSSM_KEYUSE keyUsage, + uint32 keyAttr, + SecAccessRef _Nullable initialAccess, + SecKeyRef* _Nullable CF_RETURNS_RETAINED keyRef) + CSSM_DEPRECATED; + +/*! + @function SecKeyGetCSSMKey + @abstract Returns a pointer to the CSSM_KEY for the given key item reference. + @param key A keychain key item reference. The key item must be of class type kSecPublicKeyItemClass, kSecPrivateKeyItemClass, or kSecSymmetricKeyItemClass. + @param cssmKey On return, a pointer to a CSSM_KEY structure for the given key. This pointer remains valid until the key reference is released. The caller should not attempt to modify or free this data. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion The CSSM_KEY is valid until the key item reference is released. This API is deprecated in 10.7. Its use should no longer be needed. +*/ +OSStatus SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY * _Nullable * __nonnull cssmKey) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;; + +/*! + @function SecKeyGetCSPHandle + @abstract Returns the CSSM_CSP_HANDLE for the given key reference. The handle is valid until the key reference is released. + @param keyRef A key reference. + @param cspHandle On return, the CSSM_CSP_HANDLE for the given keychain. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Its use should no longer be needed. +*/ +OSStatus SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecKeyGetCredentials + @abstract For a given key, return a pointer to a CSSM_ACCESS_CREDENTIALS structure which will allow the key to be used. + @param keyRef The key for which a credential is requested. + @param operation The type of operation to be performed with this key. See "Authorization tag type" for defined operations (cssmtype.h). + @param credentialType The type of credential requested. + @param outCredentials On return, a pointer to a CSSM_ACCESS_CREDENTIALS structure. This pointer remains valid until the key reference is released. The caller should not attempt to modify or free this data. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecKeyGetCredentials( + SecKeyRef keyRef, + CSSM_ACL_AUTHORIZATION_TAG operation, + SecCredentialType credentialType, + const CSSM_ACCESS_CREDENTIALS * _Nullable * __nonnull outCredentials) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecKeyGenerateSymmetric + @abstract Generates a random symmetric key with the specified length + and algorithm type. + + @param parameters A dictionary containing one or more key-value pairs. + See the discussion sections below for a complete overview of options. + @param error An optional pointer to a CFErrorRef. This value is set + if an error occurred. If not NULL, the caller is responsible for + releasing the CFErrorRef. + @result On return, a SecKeyRef reference to the symmetric key, or + NULL if the key could not be created. + + @discussion In order to generate a symmetric key, the parameters dictionary + must at least contain the following keys: + + * kSecAttrKeyType with a value of kSecAttrKeyTypeAES or any other + kSecAttrKeyType defined in SecItem.h + * kSecAttrKeySizeInBits with a value being a CFNumberRef containing + the requested key size in bits. Example sizes for AES keys are: + 128, 192, 256, 512. + + To store the generated symmetric key in a keychain, set these keys: + * kSecUseKeychain (value is a SecKeychainRef) + * kSecAttrLabel (a user-visible label whose value is a CFStringRef, + e.g. "My App's Encryption Key") + * kSecAttrApplicationLabel (a label defined by your application, whose + value is a CFDataRef and which can be used to find this key in a + subsequent call to SecItemCopyMatching, e.g. "ID-1234567890-9876-0151") + + To specify the generated key's access control settings, set this key: + * kSecAttrAccess (value is a SecAccessRef) + + The keys below may be optionally set in the parameters dictionary + (with a CFBooleanRef value) to override the default usage values: + + * kSecAttrCanEncrypt (defaults to true if not explicitly specified) + * kSecAttrCanDecrypt (defaults to true if not explicitly specified) + * kSecAttrCanWrap (defaults to true if not explicitly specified) + * kSecAttrCanUnwrap (defaults to true if not explicitly specified) + +*/ +_Nullable CF_RETURNS_RETAINED +SecKeyRef SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecKeyCreateFromData + @abstract Creates a symmetric key with the given data and sets the + algorithm type specified. + + @param parameters A dictionary containing one or more key-value pairs. + See the discussion sections below for a complete overview of options. + @result On return, a SecKeyRef reference to the symmetric key. + + @discussion In order to generate a symmetric key the parameters dictionary must + at least contain the following keys: + + * kSecAttrKeyType with a value of kSecAttrKeyTypeAES or any other + kSecAttrKeyType defined in SecItem.h + + The keys below may be optionally set in the parameters dictionary + (with a CFBooleanRef value) to override the default usage values: + + * kSecAttrCanEncrypt (defaults to true if not explicitly specified) + * kSecAttrCanDecrypt (defaults to true if not explicitly specified) + * kSecAttrCanWrap (defaults to true if not explicitly specified) + * kSecAttrCanUnwrap (defaults to true if not explicitly specified) + +*/ +_Nullable +SecKeyRef SecKeyCreateFromData(CFDictionaryRef parameters, + CFDataRef keyData, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + + +#ifdef __BLOCKS__ +/*! + @typedef SecKeyGeneratePairBlock + @abstract Delivers the result from an asynchronous key pair generation. + @param publicKey - the public key generated. You must retain publicKey if you wish to use it after your block returns. + @param privateKey - the private key generated. You must retain publicKey if you wish to use it after your block returns. + @param error - Any errors returned. You must retain error if you wish to use it after your block returns. + */ + +typedef void (^SecKeyGeneratePairBlock)(SecKeyRef publicKey, SecKeyRef privateKey, CFErrorRef error); + +/*! + @function SecKeyGeneratePairAsync + @abstract Generate a private/public keypair returning the values in a callback. + @param parameters A dictionary containing one or more key-value pairs. + @param deliveryQueue A dispatch queue to be used to deliver the results. + @param result A callback function to result when the operation has completed. + + @discussion In order to generate a keypair the parameters dictionary must + at least contain the following keys: + + * kSecAttrKeyType with a value being kSecAttrKeyTypeRSA or any other + kSecAttrKeyType defined in SecItem.h + * kSecAttrKeySizeInBits with a value being a CFNumberRef or CFStringRef + containing the requested key size in bits. Example sizes for RSA + keys are: 512, 768, 1024, 2048. + + Setting the following attributes explicitly will override the defaults below. + See SecItem.h for detailed information on these attributes including the types + of the values. + + * kSecAttrLabel default NULL + * kSecAttrIsPermanent if this key is present and has a Boolean + value of true, the key or key pair will be added to the default + keychain. + * kSecAttrApplicationTag default NULL + * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits + * kSecAttrCanEncrypt default false for private keys, true for public keys + * kSecAttrCanDecrypt default true for private keys, false for public keys + * kSecAttrCanDerive default true + * kSecAttrCanSign default true for private keys, false for public keys + * kSecAttrCanVerify default false for private keys, true for public keys + * kSecAttrCanWrap default false for private keys, true for public keys + * kSecAttrCanUnwrap default true for private keys, false for public keys + +*/ +void SecKeyGeneratePairAsync(CFDictionaryRef parameters, + dispatch_queue_t deliveryQueue, SecKeyGeneratePairBlock result) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +#endif /* __BLOCKS__ */ + +// Derive, Wrap, and Unwrap + +/*! + @function SecKeyDeriveFromPassword + @abstract Derives a symmetric key from a password. + + @param password The password from which the keyis to be derived. + @param parameters A dictionary containing one or more key-value pairs. + @param error If the call fails this will contain the error code. + + @discussion In order to derive a key the parameters dictionary must contain at least contain the following keys: + * kSecAttrSalt - a CFData for the salt value for mixing in the pseudo-random rounds. + * kSecAttrPRF - the algorithm to use for the pseudo-random-function. + If 0, this defaults to kSecAttrPRFHmacAlgSHA1. Possible values are: + + * kSecAttrPRFHmacAlgSHA1 + * kSecAttrPRFHmacAlgSHA224 + * kSecAttrPRFHmacAlgSHA256 + * kSecAttrPRFHmacAlgSHA384 + * kSecAttrPRFHmacAlgSHA512 + + * kSecAttrRounds - the number of rounds to call the pseudo random function. + If 0, a count will be computed to average 1/10 of a second. + * kSecAttrKeySizeInBits with a value being a CFNumberRef + containing the requested key size in bits. Example sizes for RSA keys are: + 512, 768, 1024, 2048. + + @result On success a SecKeyRef is returned. On failure this result is NULL and the + error parameter contains the reason. + +*/ +_Nullable CF_RETURNS_RETAINED +SecKeyRef SecKeyDeriveFromPassword(CFStringRef password, + CFDictionaryRef parameters, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecKeyWrapSymmetric + @abstract Wraps a symmetric key with a symmetric key. + + @param keyToWrap The key which is to be wrapped. + @param wrappingKey The key wrapping key. + @param parameters The parameter list to use for wrapping the key. + @param error If the call fails this will contain the error code. + + @result On success a CFDataRef is returned. On failure this result is NULL and the + error parameter contains the reason. + + @discussion In order to wrap a key the parameters dictionary may contain the following key: + * kSecSalt - a CFData for the salt value for the encrypt. + +*/ +_Nullable +CFDataRef SecKeyWrapSymmetric(SecKeyRef keyToWrap, + SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecKeyUnwrapSymmetric + @abstract Unwrap a wrapped symmetric key. + + @param keyToUnwrap The wrapped key to unwrap. + @param unwrappingKey The key unwrapping key. + @param parameters The parameter list to use for unwrapping the key. + @param error If the call fails this will contain the error code. + + @result On success a SecKeyRef is returned. On failure this result is NULL and the + error parameter contains the reason. + + @discussion In order to unwrap a key the parameters dictionary may contain the following key: + * kSecSalt - a CFData for the salt value for the decrypt. + +*/ +_Nullable +SecKeyRef SecKeyUnwrapSymmetric(CFDataRef _Nullable * __nonnull keyToUnwrap, + SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +#endif /* SEC_OS_OSX */ + +/*! + @function SecKeyGeneratePair + @abstract Generate a private/public keypair. + @param parameters A dictionary containing one or more key-value pairs. + See the discussion sections below for a complete overview of options. + @param publicKey On return, a SecKeyRef reference to the public key. + @param privateKey On return, a SecKeyRef reference to the private key. + @result A result code. See "Security Error Codes" (SecBase.h). + + @discussion In order to generate a keypair the parameters dictionary must + at least contain the following keys: + + * kSecAttrKeyType with a value of kSecAttrKeyTypeRSA or any other + kSecAttrKeyType defined in SecItem.h + * kSecAttrKeySizeInBits with a value being a CFNumberRef containing + the requested key size in bits. Example sizes for RSA keys are: + 512, 768, 1024, 2048. + + The values below may be set either in the top-level dictionary or in a + dictionary that is the value of the kSecPrivateKeyAttrs or + kSecPublicKeyAttrs key in the top-level dictionary. Setting these + attributes explicitly will override the defaults below. See SecItem.h + for detailed information on these attributes including the types of + the values. + + * kSecAttrLabel default NULL + * kSecUseKeychain default NULL, which specifies the default keychain + * kSecAttrIsPermanent default false + if this key is present and has a Boolean value of true, the key or + key pair will be added to the keychain. + * kSecAttrTokenID default NULL + The CFStringRef ID of the token to generate the key or keypair on. This + attribute can contain CFStringRef and can be present only in the top-level + parameters dictionary. + * kSecAttrApplicationTag default NULL + * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits + * kSecAttrCanEncrypt default false for private keys, true for public keys + * kSecAttrCanDecrypt default true for private keys, false for public keys + * kSecAttrCanDerive default true + * kSecAttrCanSign default true for private keys, false for public keys + * kSecAttrCanVerify default false for private keys, true for public keys + * kSecAttrCanWrap default false for private keys, true for public keys + * kSecAttrCanUnwrap default true for private keys, false for public keys + + NOTE: The function always saves keys in the keychain on macOS and as such attribute + kSecAttrIsPermanent is ignored. The function respects attribute kSecAttrIsPermanent + on iOS, tvOS and watchOS. + It is recommended to use SecKeyCreateRandomKey() which respects kSecAttrIsPermanent + on all platforms. +*/ +OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, + SecKeyRef * _Nullable CF_RETURNS_RETAINED publicKey, SecKeyRef * _Nullable CF_RETURNS_RETAINED privateKey) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + + +#if SEC_OS_IPHONE +/*! + @function SecKeyRawSign + @abstract Given a private key and data to sign, generate a digital + signature. + @param key Private key with which to sign. + @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. + @param dataToSign The data to be signed, typically the digest of the + actual data. + @param dataToSignLen Length of dataToSign in bytes. + @param sig Pointer to buffer in which the signature will be returned. + @param sigLen IN/OUT maximum length of sig buffer on input, actualy + length of sig on output. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be performed prior to signing. If this argument is kSecPaddingNone, + the incoming data will be signed "as is". + + When PKCS1 padding is performed, the maximum length of data that can + be signed is the value returned by SecKeyGetBlockSize() - 11. + + NOTE: The behavior this function with kSecPaddingNone is undefined if the + first byte of dataToSign is zero; there is no way to verify leading zeroes + as they are discarded during the calculation. + + If you want to generate a proper PKCS1 style signature with DER encoding + of the digest type - and the dataToSign is a SHA1 digest - use + kSecPaddingPKCS1SHA1. + */ +OSStatus SecKeyRawSign( + SecKeyRef key, + SecPadding padding, + const uint8_t *dataToSign, + size_t dataToSignLen, + uint8_t *sig, + size_t *sigLen) +__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + + +/*! + @function SecKeyRawVerify + @abstract Given a public key, data which has been signed, and a signature, + verify the signature. + @param key Public key with which to verify the signature. + @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. + @param signedData The data over which sig is being verified, typically + the digest of the actual data. + @param signedDataLen Length of signedData in bytes. + @param sig Pointer to the signature to verify. + @param sigLen Length of sig in bytes. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be checked during verification. If this argument is kSecPaddingNone, + the incoming data will be compared directly to sig. + + If you are verifying a proper PKCS1-style signature, with DER encoding + of the digest type - and the signedData is a SHA1 digest - use + kSecPaddingPKCS1SHA1. + */ +OSStatus SecKeyRawVerify( + SecKeyRef key, + SecPadding padding, + const uint8_t *signedData, + size_t signedDataLen, + const uint8_t *sig, + size_t sigLen) +__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + + +/*! + @function SecKeyEncrypt + @abstract Encrypt a block of plaintext. + @param key Public key with which to encrypt the data. + @param padding See Padding Types above, typically kSecPaddingPKCS1. + @param plainText The data to encrypt. + @param plainTextLen Length of plainText in bytes, this must be less + or equal to the value returned by SecKeyGetBlockSize(). + @param cipherText Pointer to the output buffer. + @param cipherTextLen On input, specifies how much space is available at + cipherText; on return, it is the actual number of cipherText bytes written. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP, + PKCS1 (respectively kSecPaddingOAEP) padding will be performed prior to encryption. + If this argument is kSecPaddingNone, the incoming data will be encrypted "as is". + kSecPaddingOAEP is the recommended value. Other value are not recommended + for security reason (Padding attack or malleability). + + When PKCS1 padding is performed, the maximum length of data that can + be encrypted is the value returned by SecKeyGetBlockSize() - 11. + + When memory usage is a critical issue, note that the input buffer + (plainText) can be the same as the output buffer (cipherText). + */ +OSStatus SecKeyEncrypt( + SecKeyRef key, + SecPadding padding, + const uint8_t *plainText, + size_t plainTextLen, + uint8_t *cipherText, + size_t *cipherTextLen) +__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + + +/*! + @function SecKeyDecrypt + @abstract Decrypt a block of ciphertext. + @param key Private key with which to decrypt the data. + @param padding See Padding Types above, typically kSecPaddingPKCS1. + @param cipherText The data to decrypt. + @param cipherTextLen Length of cipherText in bytes, this must be less + or equal to the value returned by SecKeyGetBlockSize(). + @param plainText Pointer to the output buffer. + @param plainTextLen On input, specifies how much space is available at + plainText; on return, it is the actual number of plainText bytes written. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP, + the corresponding padding will be removed after decryption. + If this argument is kSecPaddingNone, the decrypted data will be returned "as is". + + When memory usage is a critical issue, note that the input buffer + (plainText) can be the same as the output buffer (cipherText). + */ +OSStatus SecKeyDecrypt( + SecKeyRef key, /* Private key */ + SecPadding padding, /* kSecPaddingNone, + kSecPaddingPKCS1, + kSecPaddingOAEP */ + const uint8_t *cipherText, + size_t cipherTextLen, /* length of cipherText */ + uint8_t *plainText, + size_t *plainTextLen) /* IN/OUT */ +__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + +#endif // SEC_OS_IPHONE + +/*! + @function SecKeyCreateRandomKey + @abstract Generates a new public/private key pair. + @param parameters A dictionary containing one or more key-value pairs. + See the discussion sections below for a complete overview of options. + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @return Newly generated private key. To get associated public key, use SecKeyCopyPublicKey(). + @discussion In order to generate a keypair the parameters dictionary must + at least contain the following keys: + + * kSecAttrKeyType with a value being kSecAttrKeyTypeRSA or any other + kSecAttrKeyType defined in SecItem.h + * kSecAttrKeySizeInBits with a value being a CFNumberRef or CFStringRef + containing the requested key size in bits. Example sizes for RSA + keys are: 512, 768, 1024, 2048. + + The values below may be set either in the top-level dictionary or in a + dictionary that is the value of the kSecPrivateKeyAttrs or + kSecPublicKeyAttrs key in the top-level dictionary. Setting these + attributes explicitly will override the defaults below. See SecItem.h + for detailed information on these attributes including the types of + the values. + + * kSecAttrLabel default NULL + * kSecAttrIsPermanent if this key is present and has a Boolean value of true, + the key or key pair will be added to the default keychain. + * kSecAttrTokenID if this key should be generated on specified token. This + attribute can contain CFStringRef and can be present only in the top-level + parameters dictionary. + * kSecAttrApplicationTag default NULL + * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits + * kSecAttrCanEncrypt default false for private keys, true for public keys + * kSecAttrCanDecrypt default true for private keys, false for public keys + * kSecAttrCanDerive default true + * kSecAttrCanSign default true for private keys, false for public keys + * kSecAttrCanVerify default false for private keys, true for public keys + * kSecAttrCanWrap default false for private keys, true for public keys + * kSecAttrCanUnwrap default true for private keys, false for public keys + */ +SecKeyRef _Nullable SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCreateWithData + @abstract Create a SecKey from a well-defined external representation. + @param keyData CFData representing the key. The format of the data depends on the type of key being created. + @param attributes Dictionary containing attributes describing the key to be imported. The keys in this dictionary + are kSecAttr* constants from SecItem.h. Mandatory attributes are: + * kSecAttrKeyType + * kSecAttrKeyClass + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result A SecKey object representing the key, or NULL on failure. + @discussion This function does not add keys to any keychain, but the SecKey object it returns can be added + to keychain using the SecItemAdd function. + The requested data format depend on the type of key (kSecAttrKeyType) being created: + * kSecAttrKeyTypeRSA PKCS#1 format, public key can be also in x509 public key format + * kSecAttrKeyTypeECSECPrimeRandom ANSI X9.63 format (04 || X || Y [ || K]) + */ +SecKeyRef _Nullable SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef attributes, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyGetBlockSize + @abstract Returns block length of the key in bytes. + @param key The key for which the block length is requested. + @result The block length of the key in bytes. + @discussion If for example key is an RSA key the value returned by + this function is the size of the modulus. + */ +size_t SecKeyGetBlockSize(SecKeyRef key) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecKeyCopyExternalRepresentation + @abstract Create an external representation for the given key suitable for the key's type. + @param key The key to be exported. + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result A CFData representing the key in a format suitable for that key type. + @discussion This function may fail if the key is not exportable (e.g., bound to a smart card or Secure Enclave). + The format in which the key will be exported depends on the type of key: + * kSecAttrKeyTypeRSA PKCS#1 format + * kSecAttrKeyTypeECSECPrimeRandom ANSI X9.63 format (04 || X || Y [ || K]) + */ +CFDataRef _Nullable SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCopyAttributes + @abstract Retrieve keychain attributes of a key. + @param key The key whose attributes are to be retrieved. + @result Dictionary containing attributes of the key. The keys that populate this dictionary are defined + and discussed in SecItem.h. + @discussion The attributes provided by this function are: + * kSecAttrCanEncrypt + * kSecAttrCanDecrypt + * kSecAttrCanDerive + * kSecAttrCanSign + * kSecAttrCanVerify + * kSecAttrKeyClass + * kSecAttrKeyType + * kSecAttrKeySizeInBits + * kSecAttrTokenID + * kSecAttrApplicationLabel + Other values returned in that dictionary are RFU. + */ +CFDictionaryRef _Nullable SecKeyCopyAttributes(SecKeyRef key) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCopyPublicKey + @abstract Retrieve the public key from a key pair or private key. + @param key The key from which to retrieve a public key. + @result The public key or NULL if public key is not available for specified key. + @discussion Fails if key does not contain a public key or no public key can be computed from it. + */ +SecKeyRef _Nullable SecKeyCopyPublicKey(SecKeyRef key) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @enum SecKeyAlgorithm + @abstract Available algorithms for performing cryptographic operations with SecKey object. String representation + of constant can be used for logging or debugging purposes, because they contain human readable names of the algorithm. + + @constant kSecKeyAlgorithmRSASignatureRaw + Raw RSA sign/verify operation, size of input data must be the same as value returned by SecKeyGetBlockSize(). + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw + RSA sign/verify operation, assumes that input data is digest and OID and digest algorithm as specified in PKCS# v1.5. + This algorithm is typically not used directly, instead use algorithm with specified digest, like + kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256. + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 + RSA signature with PKCS#1 padding, input data must be SHA-1 generated digest. + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 + RSA signature with PKCS#1 padding, input data must be SHA-224 generated digest. + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 + RSA signature with PKCS#1 padding, input data must be SHA-256 generated digest. + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 + RSA signature with PKCS#1 padding, input data must be SHA-384 generated digest. + + @constant kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 + RSA signature with PKCS#1 padding, input data must be SHA-512 generated digest. + + @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 + RSA signature with PKCS#1 padding, SHA-1 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 + RSA signature with PKCS#1 padding, SHA-224 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 + RSA signature with PKCS#1 padding, SHA-256 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 + RSA signature with PKCS#1 padding, SHA-384 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 + RSA signature with PKCS#1 padding, SHA-512 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA1 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-1 generated digest. + PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA224 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-224 generated digest. + PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA256 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-256 generated digest. + PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA384 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-384 generated digest. + PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA512 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-512 generated digest. + PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size). + + @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA1 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-1 digest is generated from input data of any size. + PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size). + + @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA224 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-224 digest is generated from input data of any size. + PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size). + + @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA256 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-256 digest is generated from input data of any size. + PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size). + + @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA384 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-384 digest is generated from input data of any size. + PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size). + + @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA512 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-512 digest is generated from input data of any size. + PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size). + + @constant kSecKeyAlgorithmECDSASignatureRFC4754 + ECDSA algorithm, signature is concatenated r and s, big endian, data is message digest. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA1 algorithm. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA224 algorithm. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA256 algorithm. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA384 algorithm. + + @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA512 algorithm. + + @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA1 + ECDSA algorithm, signature is in DER x9.62 encoding, SHA-1 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA224 + ECDSA algorithm, signature is in DER x9.62 encoding, SHA-224 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA256 + ECDSA algorithm, signature is in DER x9.62 encoding, SHA-256 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA384 + ECDSA algorithm, signature is in DER x9.62 encoding, SHA-384 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA512 + ECDSA algorithm, signature is in DER x9.62 encoding, SHA-512 digest is generated from input data of any size. + + @constant kSecKeyAlgorithmRSAEncryptionRaw + Raw RSA encryption or decryption, size of data must match RSA key modulus size. Note that direct + use of this algorithm without padding is cryptographically very weak, it is important to always introduce + some kind of padding. Input data size must be less or equal to the key block size and returned block has always + the same size as block size, as returned by SecKeyGetBlockSize(). + + @constant kSecKeyAlgorithmRSAEncryptionPKCS1 + RSA encryption or decryption, data is padded using PKCS#1 padding scheme. This algorithm should be used only for + backward compatibility with existing protocols and data. New implementations should choose cryptographically + stronger algorithm instead (see kSecKeyAlgorithmRSAEncryptionOAEP). Input data must be at most + "key block size - 11" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA1 + RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA1. Input data must be at most + "key block size - 42" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM to be able to encrypt and decrypt arbitrary long data. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA224 + RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA224. Input data must be at most + "key block size - 58" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM to be able to encrypt and decrypt arbitrary long data. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA256 + RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA256. Input data must be at most + "key block size - 66" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM to be able to encrypt and decrypt arbitrary long data. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA384 + RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA384. Input data must be at most + "key block size - 98" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM to be able to encrypt and decrypt arbitrary long data. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA512 + RSA encryption or decryption, data is padded using OAEP padding scheme internally using SHA512. Input data must be at most + "key block size - 130" bytes long and returned block has always the same size as block size, as returned + by SecKeyGetBlockSize(). Use kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM to be able to encrypt and decrypt arbitrary long data. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM + Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM + mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. + 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used + as authentication data for AES-GCM encryption. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM + Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM + mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. + 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used + as authentication data for AES-GCM encryption. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM + Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM + mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. + 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used + as authentication data for AES-GCM encryption. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM + Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM + mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. + 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used + as authentication data for AES-GCM encryption. + + @constant kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM + Randomly generated AES session key is encrypted by RSA with OAEP padding. User data are encrypted using session key in GCM + mode with all-zero 16 bytes long IV (initialization vector). Finally 16 byte AES-GCM tag is appended to ciphertext. + 256bit AES key is used if RSA key is 4096bit or bigger, otherwise 128bit AES key is used. Raw public key data is used + as authentication data for AES-GCM encryption. + + @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF. + AES-GCM uses 16 bytes long TAG, AES key is first half of KDF output and 16 byte long IV (initialization vector) is second half + of KDF output. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactor + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys. + This algorithm does not accept any parameters, length of output raw shared secret is given by the length of the key. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1 + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA1 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224 + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA224 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256 + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384 + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA384 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512 + Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA512 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandard + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys. + This algorithm does not accept any parameters, length of output raw shared secret is given by the length of the key. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA1 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224 + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA224 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256 + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384 + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA384 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + + @constant kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512 + Compute shared secret using ECDH algorithm without cofactor, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys + and apply ANSI X9.63 KDF with SHA512 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows + kSecKeyKeyExchangeParameterSharedInfo parameters to be used. + */ + +typedef CFStringRef SecKeyAlgorithm CF_STRING_ENUM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureRaw +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA224 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA256 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA384 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA512 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA224 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA256 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA384 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA512 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureRFC4754 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureMessageX962SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionRaw +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionPKCS1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandard +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactor +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512 +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCreateSignature + @abstract Given a private key and data to sign, generate a digital signature. + @param key Private key with which to sign. + @param algorithm One of SecKeyAlgorithm constants suitable to generate signature with this key. + @param dataToSign The data to be signed, typically the digest of the actual data. + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result The signature over dataToSign represented as a CFData, or NULL on failure. + @discussion Computes digital signature using specified key over input data. The operation algorithm + further defines the exact format of input data, operation to be performed and output signature. + */ +CFDataRef _Nullable SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyVerifySignature + @abstract Given a public key, data which has been signed, and a signature, verify the signature. + @param key Public key with which to verify the signature. + @param algorithm One of SecKeyAlgorithm constants suitable to verify signature with this key. + @param signedData The data over which sig is being verified, typically the digest of the actual data. + @param signature The signature to verify. + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result True if the signature was valid, False otherwise. + @discussion Verifies digital signature operation using specified key and signed data. The operation algorithm + further defines the exact format of input data, signature and operation to be performed. + */ +Boolean SecKeyVerifySignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef signedData, CFDataRef signature, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCreateEncryptedData + @abstract Encrypt a block of plaintext. + @param key Public key with which to encrypt the data. + @param algorithm One of SecKeyAlgorithm constants suitable to perform encryption with this key. + @param plaintext The data to encrypt. The length and format of the data must conform to chosen algorithm, + typically be less or equal to the value returned by SecKeyGetBlockSize(). + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result The ciphertext represented as a CFData, or NULL on failure. + @discussion Encrypts plaintext data using specified key. The exact type of the operation including the format + of input and output data is specified by encryption algorithm. + */ +CFDataRef _Nullable SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, + CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCreateDecryptedData + @abstract Decrypt a block of ciphertext. + @param key Private key with which to decrypt the data. + @param algorithm One of SecKeyAlgorithm constants suitable to perform decryption with this key. + @param ciphertext The data to decrypt. The length and format of the data must conform to chosen algorithm, + typically be less or equal to the value returned by SecKeyGetBlockSize(). + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result The plaintext represented as a CFData, or NULL on failure. + @discussion Decrypts ciphertext data using specified key. The exact type of the operation including the format + of input and output data is specified by decryption algorithm. + */ +CFDataRef _Nullable SecKeyCreateDecryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, + CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @enum SecKeyKeyExchangeParameter SecKey Key Exchange parameters + @constant kSecKeyKeyExchangeParameterRequestedSize Contains CFNumberRef with requested result size in bytes. + @constant kSecKeyKeyExchangeParameterSharedInfo Contains CFDataRef with additional shared info + for KDF (key derivation function). + */ +typedef CFStringRef SecKeyKeyExchangeParameter CF_STRING_ENUM +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyKeyExchangeParameter kSecKeyKeyExchangeParameterRequestedSize +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyKeyExchangeParameter kSecKeyKeyExchangeParameterSharedInfo +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyCopyKeyExchangeResult + @abstract Perform Diffie-Hellman style of key exchange operation, optionally with additional key-derivation steps. + @param algorithm One of SecKeyAlgorithm constants suitable to perform this operation. + @param publicKey Remote party's public key. + @param parameters Dictionary with parameters, see SecKeyKeyExchangeParameter constants. Used algorithm + determines the set of required and optional parameters to be used. + @param error Pointer to an error object on failure. + See "Security Error Codes" (SecBase.h). + @result Result of key exchange operation as a CFDataRef, or NULL on failure. + */ +CFDataRef _Nullable SecKeyCopyKeyExchangeResult(SecKeyRef privateKey, SecKeyAlgorithm algorithm, SecKeyRef publicKey, CFDictionaryRef parameters, CFErrorRef *error) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @enum SecKeyOperationType + @abstract Defines types of cryptographic operations available with SecKey instance. + + @constant kSecKeyOperationTypeSign + Represents SecKeyCreateSignature() + + @constant kSecKeyOperationTypeVerify + Represents SecKeyVerifySignature() + + @constant kSecKeyOperationTypeEncrypt + Represents SecKeyCreateEncryptedData() + + @constant kSecKeyOperationTypeDecrypt + Represents SecKeyCreateDecryptedData() + + @constant kSecKeyOperationTypeKeyExchange + Represents SecKeyCopyKeyExchangeResult() + */ +typedef CF_ENUM(CFIndex, SecKeyOperationType) { + kSecKeyOperationTypeSign = 0, + kSecKeyOperationTypeVerify = 1, + kSecKeyOperationTypeEncrypt = 2, + kSecKeyOperationTypeDecrypt = 3, + kSecKeyOperationTypeKeyExchange = 4, +} __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecKeyIsAlgorithmSupported + @abstract Checks whether key supports specified algorithm for specified operation. + @param key Key to query + @param operation Operation type for which the key is queried + @param algorithm Algorithm which is queried + @return True if key supports specified algorithm for specified operation, False otherwise. + */ +Boolean SecKeyIsAlgorithmSupported(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECKEY_H_ */ diff --git a/keychain/headers/SecKeyPriv.h b/keychain/headers/SecKeyPriv.h new file mode 100644 index 00000000..1f22315a --- /dev/null +++ b/keychain/headers/SecKeyPriv.h @@ -0,0 +1,912 @@ +/* + * Copyright (c) 2006-2010,2012-2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecKeyPriv + The functions provided in SecKeyPriv.h implement and manage a particular + type of keychain item that represents a key. A key can be stored in a + keychain, but a key can also be a transient object. + + You can use a key as a keychain item in most functions. +*/ + +#ifndef _SECURITY_SECKEYPRIV_H_ +#define _SECURITY_SECKEYPRIV_H_ + +#include +#include +#include +#include + +#if TARGET_OS_OSX +#include +#endif + +#if SEC_OS_OSX +#include +#include +#endif + +__BEGIN_DECLS + +typedef struct __SecDERKey { + uint8_t *oid; + CFIndex oidLength; + + uint8_t *parameters; + CFIndex parametersLength; + + /* Contents of BIT STRING in DER Encoding */ + uint8_t *key; + CFIndex keyLength; +} SecDERKey; + +typedef struct SecRSAPublicKeyParams { + uint8_t *modulus; /* modulus */ + CFIndex modulusLength; + uint8_t *exponent; /* public exponent */ + CFIndex exponentLength; +} SecRSAPublicKeyParams; + +typedef uint32_t SecKeyEncoding; +enum { + /* Typically only used for symmetric keys. */ + kSecKeyEncodingRaw = 0, + + /* RSA keys are DER-encoded according to PKCS1. */ + kSecKeyEncodingPkcs1 = 1, + + /* RSA keys are DER-encoded according to PKCS1 with Apple Extensions. */ + kSecKeyEncodingApplePkcs1 = 2, + + /* RSA public key in SecRSAPublicKeyParams format. keyData is a pointer + to a SecRSAPublicKeyParams and keyDataLength is + sizeof(SecRSAPublicKeyParams). */ + kSecKeyEncodingRSAPublicParams = 3, + + /* RSA public key in SecRSAPublicKeyParams format. keyData is a pointer + to a SecRSAPublicKeyParams and keyDataLength is + sizeof(SecRSAPublicKeyParams). */ + kSecDERKeyEncoding = 4, + + /* Internal "encodings to send other data" */ + kSecGenerateKey = 5, + kSecExtractPublicFromPrivate = 6, + + /* Encoding came from SecKeyCopyPublicBytes for a public key, + or internally from a private key */ + kSecKeyEncodingBytes = 7, + + /* Handing in a private key from corecrypto directly. */ + kSecKeyCoreCrypto = 8, + +}; + +typedef uint32_t SecKeyWrapType; +enum { + /* wrap key in RFC3394 (AESWrap) */ + kSecKeyWrapRFC3394 = 0, + + /* wrap key in PGP style (support EC keys only right now) */ + kSecKeyWrapPublicKeyPGP = 1, + +}; + +typedef CF_ENUM(CFIndex, SecKeyOperationMode) { + kSecKeyOperationModePerform = 0, + kSecKeyOperationModeCheckIfSupported = 1, +}; + +typedef OSStatus (*SecKeyInitMethod)(SecKeyRef, const uint8_t *, CFIndex, + SecKeyEncoding); +typedef void (*SecKeyDestroyMethod)(SecKeyRef); +typedef OSStatus (*SecKeyRawSignMethod)(SecKeyRef key, SecPadding padding, + const uint8_t *dataToSign, size_t dataToSignLen, + uint8_t *sig, size_t *sigLen); +typedef OSStatus (*SecKeyRawVerifyMethod)( + SecKeyRef key, SecPadding padding, const uint8_t *signedData, + size_t signedDataLen, const uint8_t *sig, size_t sigLen); +typedef OSStatus (*SecKeyEncryptMethod)(SecKeyRef key, SecPadding padding, + const uint8_t *plainText, size_t plainTextLen, + uint8_t *cipherText, size_t *cipherTextLen); +typedef OSStatus (*SecKeyDecryptMethod)(SecKeyRef key, SecPadding padding, + const uint8_t *cipherText, size_t cipherTextLen, + uint8_t *plainText, size_t *plainTextLen); +typedef OSStatus (*SecKeyComputeMethod)(SecKeyRef key, + const uint8_t *pub_key, size_t pub_key_len, + uint8_t *computed_key, size_t *computed_key_len); +typedef size_t (*SecKeyBlockSizeMethod)(SecKeyRef key); +typedef CFDictionaryRef (*SecKeyCopyDictionaryMethod)(SecKeyRef key); +typedef CFIndex (*SecKeyGetAlgorithmIDMethod)(SecKeyRef key); +typedef OSStatus (*SecKeyCopyPublicBytesMethod)(SecKeyRef key, CFDataRef *serialization); +typedef CFDataRef (*SecKeyCopyWrapKeyMethod)(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error); +typedef CFDataRef (*SecKeyCopyUnwrapKeyMethod)(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error); +typedef CFStringRef (*SecKeyDescribeMethod)(SecKeyRef key); + +typedef CFDataRef (*SecKeyCopyExternalRepresentationMethod)(SecKeyRef key, CFErrorRef *error); +typedef SecKeyRef (*SecKeyCopyPublicKeyMethod)(SecKeyRef key); +typedef Boolean (*SecKeyIsEqualMethod)(SecKeyRef key1, SecKeyRef key2); +typedef SecKeyRef (*SecKeyCreateDuplicateMethod)(SecKeyRef key); +typedef Boolean (*SecKeySetParameterMethod)(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error); + +/*! + @abstract Performs cryptographic operation with the key. + @param key Key to perform the operation on. + @param operation Type of operation to be performed. + @param algorithm Algorithm identifier for the operation. Determines format of input and output data. + @param allAlgorithms Array of algorithms which were traversed until we got to this operation. The last member of this array is always the same as @c algorithm parameter. + @param mode Mode in which the operation is performed. Two available modes are checking only if the operation can be performed or actually performing the operation. + @param in1 First input parameter for the operation, meaningful only in ModePerform. + @param in2 Second input parameter for the operation, meaningful only in ModePerform. + @param error Error details when NULL is returned. + @return NULL if some failure occured. kCFNull if operation/algorithm/key combination is not supported, otherwise the result of the operation or kCFBooleanTrue in ModeCheckIfSupported. + */ +typedef CFTypeRef(*SecKeyCopyOperationResultMethod)(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, CFArrayRef allAlgorithms, SecKeyOperationMode mode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error); + +#define kSecKeyDescriptorVersion (4) + +typedef struct __SecKeyDescriptor { + /* Version of this SecKeyDescriptor. Must be kSecKeyDescriptorVersion. */ + uint32_t version; + + /* Name of this key class for use by SecKeyShow(). */ + const char *name; + + /* If nonzero, SecKeyCreate will allocate this many bytes for the key + field in the SecKeyRef it creates. If zero key is NULL and the + implementor can choose to dynamically allocate it in the init + function and free it in the destroy function. */ + uint32_t extraBytes; + + /* Called by SecKeyCreate(). */ + SecKeyInitMethod init; + /* Called by destructor (final CFRelease() or gc if using). */ + SecKeyDestroyMethod destroy; + /* Called by SecKeyRawSign(). */ + SecKeyRawSignMethod rawSign; + /* Called by SecKeyRawVerify(). */ + SecKeyRawVerifyMethod rawVerify; + /* Called by SecKeyEncrypt(). */ + SecKeyEncryptMethod encrypt; + /* Called by SecKeyDecrypt(). */ + SecKeyDecryptMethod decrypt; + /* Reserved for future use. */ + SecKeyComputeMethod compute; + /* Called by SecKeyGetBlockSize(). */ + SecKeyBlockSizeMethod blockSize; + /* Called by SecKeyCopyAttributeDictionary(), which is private. */ + SecKeyCopyDictionaryMethod copyDictionary; + /* Called by SecKeyDescribeMethod(). */ + SecKeyDescribeMethod describe; +#if kSecKeyDescriptorVersion > 0 + /* Called by SecKeyCopyAttributeDictionary(), which is private. */ + SecKeyGetAlgorithmIDMethod getAlgorithmID; +#endif +#if kSecKeyDescriptorVersion > 1 + SecKeyCopyPublicBytesMethod copyPublic; +#endif +#if kSecKeyDescriptorVersion > 2 + SecKeyCopyWrapKeyMethod copyWrapKey; + SecKeyCopyUnwrapKeyMethod copyUnwrapKey; +#endif +#if kSecKeyDescriptorVersion > 3 + SecKeyCopyExternalRepresentationMethod copyExternalRepresentation; + SecKeyCopyPublicKeyMethod copyPublicKey; + SecKeyCopyOperationResultMethod copyOperationResult; + SecKeyIsEqualMethod isEqual; + SecKeyCreateDuplicateMethod createDuplicate; + SecKeySetParameterMethod setParameter; +#endif +} SecKeyDescriptor; + +struct __SecKey { + CFRuntimeBase _base; + + const SecKeyDescriptor *key_class; + + /* The actual key handled by class. */ + void *key; +}; + +/* Create a public key from a CFData containing a SubjectPublicKeyInfo in DER format. */ +SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, + CFDataRef subjectPublicKeyInfoData); + +/* Crete a SubjectPublicKeyInfo in DER format from a SecKey */ +CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key); + + +/*! + @function SecKeyCreate + @abstract Given a private key and data to sign, generate a digital signature. + @param allocator allocator to use when allocating this key instance. + @param key_class pointer to a SecKeyDescriptor. + @param keyData The second argument to the init() function in the key_class. + @param keyDataLength The third argument to the init() function in the key_class. + @param encoding The fourth argument to the init() function in the key_class. + @result A newly allocated SecKeyRef. + */ +SecKeyRef SecKeyCreate(CFAllocatorRef allocator, + const SecKeyDescriptor *key_class, const uint8_t *keyData, + CFIndex keyDataLength, SecKeyEncoding encoding); + +/* Create a public key from an oid, params and keyData all in DER format. */ +SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, + const SecAsn1Oid *oid1, const SecAsn1Item *params, + const SecAsn1Item *keyData); + +/* Create public key from private key */ +SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); + +/* Get Private Key (if present) by publicKey. */ +SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error); + +OSStatus SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey, CFErrorRef *error); +CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error); + +/* Return an attribute dictionary used to find a private key by public key hash */ +CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef); + +/* Return a key from an attribute dictionary that was used to store this item + in a keychain. */ +SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes); + +// SecAsn1AlgId is deprecated, but we still need to use it. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +OSStatus SecKeyDigestAndVerify( + SecKeyRef key, /* Public key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *dataToDigest, /* signature over this data */ + size_t dataToDigestLen,/* length of dataToDigest */ + const uint8_t *sig, /* signature to verify */ + size_t sigLen); /* length of sig */ + +/* Return an attribute dictionary used to store this item in a keychain. */ +CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key); + +OSStatus SecKeyDigestAndSign( + SecKeyRef key, /* Private key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *dataToDigest, /* signature over this data */ + size_t dataToDigestLen,/* length of dataToDigest */ + uint8_t *sig, /* signature, RETURNED */ + size_t *sigLen); /* IN/OUT */ + +OSStatus SecKeyVerifyDigest( + SecKeyRef key, /* Private key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *digestData, /* signature over this digest */ + size_t digestDataLen,/* length of dataToDigest */ + const uint8_t *sig, /* signature to verify */ + size_t sigLen); /* length of sig */ + +OSStatus SecKeySignDigest( + SecKeyRef key, /* Private key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *digestData, /* signature over this digest */ + size_t digestDataLen,/* length of digestData */ + uint8_t *sig, /* signature, RETURNED */ + size_t *sigLen); /* IN/OUT */ + +#pragma clang diagnostic pop + +OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic); +SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength); +SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized); +CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key); + +/* This function directly creates an iOS-format SecKeyRef from public key bytes. */ +SecKeyRef SecKeyCreateRSAPublicKey_ios(CFAllocatorRef allocator, + const uint8_t *keyData, CFIndex keyDataLength, + SecKeyEncoding encoding); + + +CF_RETURNS_RETAINED +CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, + CFTypeRef keyType, + CFDataRef privateBlob); +CF_RETURNS_RETAINED +CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType); + +enum { + kSecNullAlgorithmID = 0, + kSecRSAAlgorithmID = 1, + kSecDSAAlgorithmID = 2, /* unsupported, just here for reference. */ + kSecECDSAAlgorithmID = 3, +}; + +/*! + @function SecKeyGetAlgorithmId + @abstract Returns an enumerated constant value which identifies the algorithm for the given key. + @param key A key reference. + @result An algorithm identifier. + */ +CFIndex SecKeyGetAlgorithmId(SecKeyRef key) +SPI_AVAILABLE(macos(10.8), ios(9.0)); + +#if TARGET_OS_IPHONE +/*! + @function SecKeyGetAlgorithmID + @abstract Returns an enumerated constant value which identifies the algorithm for the given key. + @param key A key reference. + @result An algorithm identifier. + @discussion Deprecated in iOS 9.0. Note that SecKeyGetAlgorithmID also exists on OS X + with different arguments for CDSA-based SecKeyRefs, and returns different values. + For compatibility, your code should migrate to use SecKeyGetAlgorithmId instead. +*/ +CFIndex SecKeyGetAlgorithmID(SecKeyRef key) +API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", ios(5.0, 9.0)) API_UNAVAILABLE(iosmac); +#endif // TARGET_OS_IPHONE + +#if TARGET_OS_OSX +/*! + @function SecKeyGetAlgorithmID + @abstract Returns a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure for the given key. + @param key A key reference. + @param algid On return, a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Deprecated in OS X 10.8 and later. Continued use is strongly discouraged, + since there is a naming conflict with a similar function (also deprecated) on iOS that + had different arguments and a different return value. Use SecKeyGetAlgorithmId instead. + */ +OSStatus SecKeyGetAlgorithmID(SecKeyRef key, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) +API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", macos(10.2, 10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); +#endif + +#if !SEC_OS_OSX +typedef CF_ENUM(int, SecKeySize) { + kSecKeyKeySizeInBits = 0, + kSecKeySignatureSize = 1, + kSecKeyEncryptedDataSize = 2, + // More might belong here, but we aren't settled on how + // to take into account padding and/or digest types. +}; + +/*! + @function SecKeyGetSize + @abstract Returns a size in bytes. + @param key The key for which the block length is requested. + @param whichSize The size that you want evaluated. + @result The block length of the key in bytes. + @discussion If for example key is an RSA key the value returned by + this function is the size of the modulus. + */ +size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) +__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_0); +#endif + +/*! + @function SecKeyLookupPersistentRef + @abstract Looks up a SecKeyRef via persistent ref. + @param persistentRef The persistent ref data for looking up. + @param lookedUpData retained SecKeyRef for the found object. + @result Errors when using SecItemFind for the persistent ref. + */ +OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) +__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecKeyCopyPersistentRef + @abstract Gets a persistent reference for a key. + @param key Key to make a persistent ref for. + @param persistentRef Allocated data representing the persistent ref. + @result Errors when using SecItemFind for the persistent ref. + */ +OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) +__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +extern const CFStringRef _kSecKeyWrapPGPSymAlg; /* CFNumber */ +extern const CFStringRef _kSecKeyWrapPGPFingerprint; /* CFDataRef, at least 20 bytes */ +extern const CFStringRef _kSecKeyWrapPGPWrapAlg; /* kSecKeyWrapRFC6637WrapNNN, or any of the other PGP wrap algs */ +extern const CFStringRef _kSecKeyWrapRFC6637Flags; +extern const CFStringRef _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128; +extern const CFStringRef _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256; + +enum { kSecKeyWrapPGPFingerprintMinSize = 20 }; +/*! + @function _SecKeyCopyWrapKey + @abstract Wrap a key + */ + +CFDataRef +_SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) +__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +/*! + @function _SecKeyWrapKey + @abstract Unwrap a key + */ + +CFDataRef +_SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) +__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +#if SEC_OS_OSX_INCLUDES +/*! + @function SecKeyGetStrengthInBits + @abstract Returns key strength in bits for the given key. + @param key A key reference. + @param algid A pointer to a CSSM_X509_ALGORITHM_IDENTIFIER structure, as returned from a call to SecKeyGetAlgorithmID. + @param strength On return, the key strength in bits. + @result A result code. See "Security Error Codes" (SecBase.h). +*/ +OSStatus SecKeyGetStrengthInBits(SecKeyRef key, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength) API_DEPRECATED("CSSM_X509_ALGORITHM_IDENTIFIER is deprecated", macos(10.4, 10.14)); + +/*! + @function SecKeyImportPair + @abstract Takes an asymmetric key pair and stores it in the keychain specified by the keychain parameter. + @param keychainRef A reference to the keychain in which to store the private and public key items. Specify NULL for the default keychain. + @param publicCssmKey A CSSM_KEY which is valid for the CSP returned by SecKeychainGetCSPHandle(). This may be a normal key or reference key. + @param privateCssmKey A CSSM_KEY which is valid for the CSP returned by SecKeychainGetCSPHandle(). This may be a normal key or reference key. + @param initialAccess A SecAccess object that determines the initial access rights to the private key. The public key is given an any/any acl by default. + @param publicKey Optional output pointer to the keychain item reference of the imported public key. The caller must call CFRelease on this value if it is returned. + @param privateKey Optional output pointer to the keychain item reference of the imported private key. The caller must call CFRelease on this value if it is returned. + @result A result code. See "Security Error Codes" (SecBase.h). + @deprecated in 10.5 and later. Use the SecItemImport function instead; see +*/ +OSStatus SecKeyImportPair( + SecKeychainRef keychainRef, + const CSSM_KEY *publicCssmKey, + const CSSM_KEY *privateCssmKey, + SecAccessRef initialAccess, + SecKeyRef* publicKey, + SecKeyRef* privateKey) + API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); + +/*! + @function SecKeyCreate + @abstract Create a key reference from the supplied key data. + @param allocator CFAllocator to allocate the key data. Pass NULL to use the default allocator. + @param keyClass A descriptor for the particular class of key that is being created. + @param keyData Data from which to create the key. Specify the format of this data in the encoding parameter. + @param keyDataLength Length of the data pointed to by keyData. + @param encoding A value of type SecKeyEncoding which describes the format of keyData. + @result A key reference. + @discussion Warning: this function is NOT intended for use outside the Security stack in its current state. + IMPORTANT: on Mac OS X 10.5 and earlier, the SecKeyCreate function had a different parameter list. + The current parameter list matches the iPhone OS implementation. Existing clients of this function + on Mac OS X (and there should not be any outside the Security stack, per the warning above) must + migrate to the replacement function, SecKeyCreateWithCSSMKey. +*/ +SecKeyRef SecKeyCreate(CFAllocatorRef allocator, + const SecKeyDescriptor *keyClass, const uint8_t *keyData, + CFIndex keyDataLength, SecKeyEncoding encoding); + +/*! + @function SecKeyCreateWithCSSMKey + @abstract Generate a temporary floating key reference for a CSSM_KEY. + @param key A pointer to a CSSM_KEY structure. + @param keyRef On return, a key reference. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Warning: this function is NOT intended for use outside the Security stack in its current state. +*/ +OSStatus SecKeyCreateWithCSSMKey(const CSSM_KEY *key, SecKeyRef* keyRef) API_DEPRECATED("CSSM_KEY is deprecated", macos(10.11, 10.14)); + +// Alias macOS versions of this deprecated SPI to unique macOS names. Undecorated names are used for iosmac. +#define SecKeyRawSign SecKeyRawSign_macOS +#define SecKeyRawVerify SecKeyRawVerify_macOS + +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @function SecKeyRawSign + @abstract Given a private key and data to sign, generate a digital signature. + @param key Private key with which to sign. + @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. + @param dataToSign The data to be signed, typically the digest of the actual data. + @param dataToSignLen Length of dataToSign in bytes. + @param sig Pointer to buffer in which the signature will be returned. + @param sigLen IN/OUT maximum length of sig buffer on input, actualy length of sig on output. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be performed prior to signing. If this argument is kSecPaddingNone, + the incoming data will be signed "as is". + + When PKCS1 padding is performed, the maximum length of data that can + be signed is the value returned by SecKeyGetBlockSize() - 11. + + NOTE: The behavior this function with kSecPaddingNone is undefined if the + first byte of dataToSign is zero; there is no way to verify leading zeroes + as they are discarded during the calculation. + + If you want to generate a proper PKCS1 style signature with DER encoding of + the digest type - and the dataToSign is a SHA1 digest - use kSecPaddingPKCS1SHA1. +*/ +OSStatus SecKeyRawSign( + SecKeyRef key, + SecPadding padding, + const uint8_t *dataToSign, + size_t dataToSignLen, + uint8_t *sig, + size_t *sigLen) +SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateSignature", macos(10.7, 10.15)); + + +/*! + @function SecKeyRawVerify + @abstract Given a public key, data which has been signed, and a signature, verify the signature. + @param key Public key with which to verify the signature. + @param padding See Padding Types above, typically kSecPaddingPKCS1SHA1. + @param signedData The data over which sig is being verified, typically the digest of the actual data. + @param signedDataLen Length of signedData in bytes. + @param sig Pointer to the signature to verify. + @param sigLen Length of sig in bytes. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be checked during verification. If this argument is kSecPaddingNone, + the incoming data will be compared directly to sig. + + If you are verifying a proper PKCS1-style signature, with DER encoding of the digest + type - and the signedData is a SHA1 digest - use kSecPaddingPKCS1SHA1. +*/ +OSStatus SecKeyRawVerify( + SecKeyRef key, + SecPadding padding, + const uint8_t *signedData, + size_t signedDataLen, + const uint8_t *sig, + size_t sigLen) +SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyVerifySignature", macos(10.7, 10.15)); + +CF_IMPLICIT_BRIDGING_DISABLED + +/*! + @function SecKeyEncrypt + @abstract Encrypt a block of plaintext. + @param key Public key with which to encrypt the data. + @param padding See Padding Types above, typically kSecPaddingPKCS1. + @param plainText The data to encrypt. + @param plainTextLen Length of plainText in bytes, this must be less + or equal to the value returned by SecKeyGetBlockSize(). + @param cipherText Pointer to the output buffer. + @param cipherTextLen On input, specifies how much space is available at + cipherText; on return, it is the actual number of cipherText bytes written. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be performed prior to encryption. If this argument is kSecPaddingNone, + the incoming data will be encrypted "as is". + + When PKCS1 padding is performed, the maximum length of data that can + be encrypted is the value returned by SecKeyGetBlockSize() - 11. + + When memory usage is a critical issue, note that the input buffer + (plainText) can be the same as the output buffer (cipherText). +*/ +OSStatus SecKeyEncrypt( + SecKeyRef key, + SecPadding padding, + const uint8_t *plainText, + size_t plainTextLen, + uint8_t *cipherText, + size_t *cipherTextLen) +SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateEncryptedData", macos(10.7, 10.15)); + + +/*! + @function SecKeyDecrypt + @abstract Decrypt a block of ciphertext. + @param key Private key with which to decrypt the data. + @param padding See SecPadding types above; typically kSecPaddingPKCS1. + @param cipherText The data to decrypt. + @param cipherTextLen Length of cipherText in bytes; this must be less + or equal to the value returned by SecKeyGetBlockSize(). + @param plainText Pointer to the output buffer. + @param plainTextLen On input, specifies how much space is available at + plainText; on return, it is the actual number of plainText bytes written. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the padding argument is kSecPaddingPKCS1, PKCS1 padding + will be removed after decryption. If this argument is kSecPaddingNone, + the decrypted data will be returned "as is". + + When memory usage is a critical issue, note that the input buffer + (plainText) can be the same as the output buffer (cipherText). +*/ +OSStatus SecKeyDecrypt( + SecKeyRef key, /* Private key */ + SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ + const uint8_t *cipherText, + size_t cipherTextLen, /* length of cipherText */ + uint8_t *plainText, + size_t *plainTextLen) /* IN/OUT */ +SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyCreateDecryptedData", macos(10.7, 10.15)); + +// SecAsn1AlgId is deprecated, but we still need to use it. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +OSStatus SecKeyVerifyDigest( + SecKeyRef key, /* Private key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *digestData, /* signature over this digest */ + size_t digestDataLen, /* length of dataToDigest */ + const uint8_t *sig, /* signature to verify */ + size_t sigLen); /* length of sig */ + +OSStatus SecKeySignDigest( + SecKeyRef key, /* Private key */ + const SecAsn1AlgId *algId, /* algorithm oid/params */ + const uint8_t *digestData, /* signature over this digest */ + size_t digestDataLen, /* length of digestData */ + uint8_t *sig, /* signature, RETURNED */ + size_t *sigLen); /* IN/OUT */ +#pragma clang diagnostic pop + +#endif // SEC_OS_OSX_INCLUDES + + +/* These are the named curves we support. These values come from RFC 4492 + section 5.1.1, with the exception of SSL_Curve_None which means + "ECDSA not negotiated". */ +typedef enum +{ + kSecECCurveNone = -1, + kSecECCurveSecp256r1 = 23, + kSecECCurveSecp384r1 = 24, + kSecECCurveSecp521r1 = 25 +} SecECNamedCurve; + +/* Return a named curve enum for ecPrivateKey. */ +SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef ecPrivateKey); +CFDataRef SecECKeyCopyPublicBits(SecKeyRef key); + +/* Given an RSA public key in encoded form return a SecKeyRef representing + that key. Supported encodings are kSecKeyEncodingPkcs1. */ +SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, + const uint8_t *keyData, CFIndex keyDataLength, + SecKeyEncoding encoding); + +CFDataRef SecKeyCopyModulus(SecKeyRef rsaPublicKey); +CFDataRef SecKeyCopyExponent(SecKeyRef rsaPublicKey); + +/*! + @function SecKeyCopyPublicBytes + @abstract Gets the bits of a public key + @param key Key to retrieve the bits. + @param publicBytes An out parameter to receive the public key bits + @result Errors if any when retrieving the public key bits.. + */ +OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes); + +/*! + @function SecKeyCreatePublicFromPrivate + @abstract Create a public SecKeyRef from a private SecKeyRef + @param privateKey The private SecKeyRef for which you want the public key + @result A public SecKeyRef, or NULL if the conversion failed + @discussion This is a "best attempt" function, hence the SPI nature. If the public + key bits are not in memory, it attempts to load from the keychain. If the public + key was not tracked on the keychain, it will fail. +*/ +SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); + +/*! + @function SecKeyCreateFromPublicData +*/ +SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef publicBytes); + +#if SEC_OS_OSX_INCLUDES +OSStatus SecKeyRawVerifyOSX( + SecKeyRef key, + SecPadding padding, + const uint8_t *signedData, + size_t signedDataLen, + const uint8_t *sig, + size_t sigLen) +SPI_DEPRECATED_WITH_REPLACEMENT("SecKeyVerifySignature", macos(10.7, 10.15)); + +#endif // SEC_OS_OSX_INCLUDES + +/*! + @constant kSecKeyApplePayEnabled If set to kCFBooleanTrue during SecKeyCreateRandomKey, then the SEP-based key is ApplePay-enabled, + which means that it can be used for ECIES to re-crypt. + */ +extern const CFStringRef kSecKeyApplePayEnabled +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @constant kSecKeyEncryptionParameterSymmetricKeySizeInBits CFNumberRef with size in bits for ephemeral + symmetric key used for encryption/decryption. + */ +extern const CFStringRef kSecKeyEncryptionParameterSymmetricKeySizeInBits +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @constant kSecKeyEncryptionParameterSymmetricAAD CFDataRef with additional authentiction data for AES-GCM encryption. + */ +extern const CFStringRef kSecKeyEncryptionParameterSymmetricAAD +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @constant kSecKeyEncryptionParameterRecryptParameters Usable only for SecKeyCreateDecryptedDataWithParameters. + Contains dictionary with parameters for re-encryption using the same algorithm and encryption parameters + specified inside this dictionary. + */ +extern const CFStringRef kSecKeyEncryptionParameterRecryptParameters +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @constant kSecKeyEncryptionParameterRecryptCertificate Usable only inside kSecKeyEncryptionParameterRecryptParameters. + Specifies certificate whose public key is used to re-crypt previously decrypted data. This parameter should contain + CFDataRef with X509 DER-encoded data of the certificate chain {leaf, intermediate, root}, leaf's public key is + to be used for re-encryption. + */ +extern const CFStringRef kSecKeyEncryptionParameterRecryptCertificate +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @function SecKeyCreateEncryptedDataWithParameters + @abstract Encrypt a block of plaintext. + @param key Public key with which to encrypt the data. + @param algorithm One of SecKeyAlgorithm constants suitable to perform encryption with this key. + @param plaintext The data to encrypt. The length and format of the data must conform to chosen algorithm, + typically be less or equal to the value returned by SecKeyGetBlockSize(). + @param parameters Dictionary with additional parameters for encryption. Supported parameters are: + - kSecKeyKeyExchangeParameterSharedInfo: additional SharedInfo value for ECIES encryptions + - kSecKeyEncryptionParameterSymmetricKeySizeInBits: 128 or 256, size of ephemeral AES key used for symmetric encryption + - kSecKeyEncryptionParameterSymmetricAAD: optional CFDataRef with additiona authentication data for AES-GCM encryption + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result The ciphertext represented as a CFData, or NULL on failure. + @discussion Encrypts plaintext data using specified key. The exact type of the operation including the format + of input and output data is specified by encryption algorithm. + */ +CFDataRef SecKeyCreateEncryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, + CFDictionaryRef parameters, CFErrorRef *error) +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @function SecKeyCreateDecryptedDataWithParameters + @abstract Decrypt a block of ciphertext. + @param key Private key with which to decrypt the data. + @param algorithm One of SecKeyAlgorithm constants suitable to perform decryption with this key. + @param ciphertext The data to decrypt. The length and format of the data must conform to chosen algorithm, + typically be less or equal to the value returned by SecKeyGetBlockSize(). + @param parameters Dictionary with additional parameters for decryption.Supported parameters are: + - kSecKeyKeyExchangeParameterSharedInfo: additional SharedInfo value for ECIES encryptions + - kSecKeyEncryptionParameterSymmetricKeySizeInBits: 128 or 256, size of ephemeral AES key used for symmetric encryption + - kSecKeyEncryptionParameterSymmetricAAD: optional CFDataRef with additiona authentication data for AES-GCM encryption + - kSecKeyEncryptionParameterRecryptParameters: optional CFDictionaryRef with parameters for immediate re-encryption + of decrypted data. If present, the dictionary *must* contain at least kSecKeyEncryptionParameterRecryptCertificate parameter. + + @param error On error, will be populated with an error object describing the failure. + See "Security Error Codes" (SecBase.h). + @result The plaintext represented as a CFData, or NULL on failure. + @discussion Decrypts ciphertext data using specified key. The exact type of the operation including the format + of input and output data is specified by decryption algorithm. + */ +CFDataRef SecKeyCreateDecryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, + CFDictionaryRef parameters, CFErrorRef *error) +SPI_AVAILABLE(macos(10.14.4), ios(12.2), tvos(12.2), watchos(5.2)); + +/*! + @enum SecKeyAttestationKeyType + @abstract Defines types of builtin attestation keys. +*/ +typedef CF_ENUM(uint32_t, SecKeyAttestationKeyType) +{ + kSecKeyAttestationKeyTypeSIK = 0, + kSecKeyAttestationKeyTypeGID = 1, + kSecKeyAttestationKeyTypeUIKCommitted SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 2, + kSecKeyAttestationKeyTypeUIKProposed SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 3, + kSecKeyAttestationKeyTypeSecureElement SPI_AVAILABLE(ios(13.0)) = 4, +} SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); + +/*! + @function SecKeyCopyAttestationKey + @abstract Returns a copy of a builtin attestation key. + + @param keyType Type of the requested builtin key. + @param error An optional pointer to a CFErrorRef. This value is set if an error occurred. + + @result On success a SecKeyRef containing the requested key is returned, on failure it returns NULL. +*/ +SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef *error) +SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); + +/*! + @function SecKeyCreateAttestation + @abstract Attests a key with another key. + + @param key The attesting key. + @param keyToAttest The key which is to be attested. + @param error An optional pointer to a CFErrorRef. This value is set if an error occurred. + + @result On success a CFDataRef containing the attestation data is returned, on failure it returns NULL. + + @discussion Key attestation only works for CTK SEP keys, i.e. keys created with kSecAttrTokenID=kSecAttrTokenIDSecureEnclave. +*/ +CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) +SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); + +/*! + @function SecKeySetParameter + @abstract Sets unspecified key parameter for the backend. + + @param key Key to set the parameter to. + @param name Identifies parameter to be set. + @param value New value for the parameter. + @param error Error which gathers more information when something went wrong. + + @discussion Serves as channel between SecKey client and backend for passing additional sideband data send from SecKey caller + to SecKey implementation backend. Parameter names and types are either generic kSecUse*** attributes or are a contract between + SecKey user (application) and backend and in this case are not interpreted by SecKey layer in any way. + */ +Boolean SecKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) +SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); + +extern const CFStringRef kSecKeyParameterSETokenAttestationNonce +SPI_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); + +/*! + Available lifetime operations for SEP system keys. + */ +typedef CF_ENUM(int, SecKeyControlLifetimeType) { + kSecKeyControlLifetimeTypeBump = 0, + kSecKeyControlLifetimeTypeCommit = 1, +} SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); + +/*! + @function SecKeyControlLifetime + @abstract Performs key lifetime control operations for SEP system keys. + + @param key Key to be controlled, currently must be either proposed or committed system UIK. + @param type Type of the control operation to be performed. + @param error Error which gathers more information when something went wrong. + */ +Boolean SecKeyControlLifetime(SecKeyRef key, SecKeyControlLifetimeType type, CFErrorRef *error) +SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); + +/*! + @function SecKeyCreateDuplicate + @abstract Creates duplicate fo the key. + + @param key Source key to be duplicated + + @discussion Only memory representation of the key is duplicated, so if the key is backed by keychain, only one instance + stays in the keychain. Duplicating key is useful for setting 'temporary' key parameters using SecKeySetParameter. + If the key is immutable (i.e. does not support SecKeySetParameter), calling this method is identical to calling CFRetain(). + */ +SecKeyRef SecKeyCreateDuplicate(SecKeyRef key) +SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)); + +/*! + Algorithms for converting between bigendian and core-crypto ccunit data representation. + */ +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureRawCCUnit; +extern const SecKeyAlgorithm kSecKeyAlgorithmRSAEncryptionRawCCUnit; + +/*! + Internal algorithm for RSA-MD5. We do not want to export MD5 in new API, but we need it + for implementing legacy interfaces. + */ +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5; +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5; + +/*! + Algorithms for interoperability with libaks smartcard support. + */ +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionAKSSmartCard; + +__END_DECLS + +#endif /* !_SECURITY_SECKEYPRIV_H_ */ diff --git a/keychain/headers/SecKeyProxy.h b/keychain/headers/SecKeyProxy.h new file mode 100644 index 00000000..00018298 --- /dev/null +++ b/keychain/headers/SecKeyProxy.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecKeyProxy + Declaration of SecKey proxy object allowing SecKeyRef to be accessed remotely through XPC. + */ + +#ifndef _SECURITY_SECKEYPROXY_H_ +#define _SECURITY_SECKEYPROXY_H_ + +#import +#include +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface SecKeyProxy : NSObject { +@private + id _key; + NSData * _Nullable _certificate; + NSXPCListener *_listener; +} + +// Creates new proxy instance. Proxy holds reference to the target key or identity and allows remote access to that target key as long as the proxy instance is kept alive. +- (instancetype)initWithKey:(SecKeyRef)key; +- (instancetype)initWithIdentity:(SecIdentityRef)identity; + +// Retrieve endpoint to this proxy instance. Endpoint can be transferred over NSXPCConnection and passed to +[createKeyFromEndpoint:error:] method. +@property (readonly, nonatomic) NSXPCListenerEndpoint *endpoint; + +// Invalidates all connections to this proxy. +- (void)invalidate; + +// Creates new SecKey/SecIdentity object which forwards all operations to the target SecKey identified by endpoint. Returned SecKeyRef can be used as long as target SecKeyProxy instance is kept alive. ++ (nullable SecKeyRef)createKeyFromEndpoint:(NSXPCListenerEndpoint *)endpoint error:(NSError **)error; ++ (nullable SecIdentityRef)createIdentityFromEndpoint:(NSXPCListenerEndpoint *)endpoint error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* !_SECURITY_SECKEYPROXY_H_ */ diff --git a/keychain/headers/SecSharedCredential.h b/keychain/headers/SecSharedCredential.h new file mode 100644 index 00000000..21a89444 --- /dev/null +++ b/keychain/headers/SecSharedCredential.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecSharedCredential + SecSharedCredential defines CoreFoundation-based functions for + storing and requesting shared password-based credentials. + These credentials are currently able to be shared with Safari and + applications which have a 'com.apple.developer.associated-domains' + entitlement that includes the domain being requested. + */ + +#ifndef _SECURITY_SECSHAREDCREDENTIAL_H_ +#define _SECURITY_SECSHAREDCREDENTIAL_H_ + +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +#ifdef __BLOCKS__ + +/*! + @enum Credential Key Constants + @discussion Predefined key constants used to get values in a dictionary + of credentials returned by SecRequestWebCredential. + @constant kSecSharedPassword Specifies a dictionary key whose value is a + shared password. You use this key to get a value of type CFStringRef + that contains a password. +*/ +extern const CFStringRef kSecSharedPassword API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); + +/*! + @function SecAddSharedWebCredential + @abstract Asynchronously store (or update) a shared password for a website. + @param fqdn The fully qualified domain name of the website requiring the password. + @param account The account name associated with this password. + @param password The password to be stored. Pass NULL to remove a shared password if it exists. + @param completionHandler A block which will be invoked when the function has completed. If the shared password was successfully added (or removed), the CFErrorRef parameter passed to the block will be NULL. If the error parameter is non-NULL, an error occurred and the error reference will hold the result. Note: the error reference will be automatically released after this handler is called, though you may optionally retain it for as long as needed. + @discussion This function adds a shared password item which will be accessible by Safari and applications that have the specified fully-qualified domain name in their 'com.apple.developer.associated-domains' entitlement. If a shared password item already exists for the specified website and account, it will be updated with the provided password. To remove a password, pass NULL for the password parameter. + + Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available. + */ +void SecAddSharedWebCredential(CFStringRef fqdn, CFStringRef account, CFStringRef __nullable password, + void (^completionHandler)(CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); + +/*! + @function SecRequestSharedWebCredential + @abstract Asynchronously obtain one or more shared passwords for a website. + @param fqdn (Optional) Fully qualified domain name of the website for which passwords are being requested. If NULL is passed in this argument, the domain name(s) listed in the calling application's 'com.apple.developer.associated-domains' entitlement are searched implicitly. + @param account (Optional) Account name for which passwords are being requested. The account may be NULL to request all shared credentials which are available for the site, allowing the caller to discover an existing account. + @param completionHandler A block which will be called to deliver the requested credentials. If no matching items were found, the credentials array will be empty, and the CFErrorRef parameter will provide the error result. Note: the credentials and error references will be automatically released after this handler is called, though you may optionally retain either for as long as needed. + @discussion This function requests one or more shared passwords for a given website, depending on whether the optional account parameter is supplied. To obtain results, the website specified in the fqdn parameter must be one which matches an entry in the calling application's 'com.apple.developer.associated-domains' entitlement. + + If matching shared password items are found, the credentials provided to the completionHandler will be a CFArrayRef containing CFDictionaryRef entries. Each dictionary entry will contain the following pairs (see Security/SecItem.h): + key: kSecAttrServer value: CFStringRef (the website) + key: kSecAttrAccount value: CFStringRef (the account) + key: kSecSharedPassword value: CFStringRef (the password) + + If the found item specifies a non-standard port number (i.e. other than 443 for https), the following key may also be present: + key: kSecAttrPort value: CFNumberRef (the port number) + + Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available. + */ +void SecRequestSharedWebCredential(CFStringRef __nullable fqdn, CFStringRef __nullable account, + void (^completionHandler)(CFArrayRef __nullable credentials, CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); + +/*! + @function SecCreateSharedWebCredentialPassword + @abstract Returns a randomly generated password. + @return CFStringRef password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present. +*/ +__nullable +CFStringRef SecCreateSharedWebCredentialPassword(void) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos); + + +#endif /* __BLOCKS__ */ + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECSHAREDCREDENTIAL_H_ */ + diff --git a/keychain/ot/CuttlefishXPCWrapper.h b/keychain/ot/CuttlefishXPCWrapper.h new file mode 100644 index 00000000..7d746def --- /dev/null +++ b/keychain/ot/CuttlefishXPCWrapper.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef CuttlefishXPCWrapper_h +#define CuttlefishXPCWrapper_h + +#import +#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +// Wrapper around calling cuttlefish XPC calls that performs retries for generic +// XPC errors that warrant retrying. All operations are synchronous. + +@interface CuttlefishXPCWrapper : NSObject +@property (readonly) id cuttlefishXPCConnection; + +- (instancetype) initWithCuttlefishXPCConnection: (id)cuttlefishXPCConnection; + +@end + +NS_ASSUME_NONNULL_END + +#endif // CuttlefishXPCWrapper_h diff --git a/keychain/ot/CuttlefishXPCWrapper.m b/keychain/ot/CuttlefishXPCWrapper.m new file mode 100644 index 00000000..c531fb82 --- /dev/null +++ b/keychain/ot/CuttlefishXPCWrapper.m @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "keychain/ot/CuttlefishXPCWrapper.h" + +@implementation CuttlefishXPCWrapper +- (instancetype) initWithCuttlefishXPCConnection: (id)cuttlefishXPCConnection +{ + if ((self = [super init])) { + _cuttlefishXPCConnection = cuttlefishXPCConnection; + } + return self; +} + ++ (bool)retryable:(NSError *_Nonnull)error +{ + return error.domain == NSCocoaErrorDomain && error.code == NSXPCConnectionInterrupted; +} + +enum {NUM_RETRIES = 5}; + +- (void)pingWithReply:(void (^)(void))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + } + ++i; + }] pingWithReply:reply]; + } while (retry); +} + +- (void)dumpWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSDictionary * _Nullable, NSError * _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] dumpWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)departByDistrustingSelfWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSError * _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] departByDistrustingSelfWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)distrustPeerIDsWithContainer:(NSString *)container + context:(NSString *)context + peerIDs:(NSSet*)peerIDs + reply:(void (^)(NSError * _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] distrustPeerIDsWithContainer:container context:context peerIDs:peerIDs reply:reply]; + } while (retry); +} + +- (void)trustStatusWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(TrustedPeersHelperEgoPeerStatus *status, + NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] trustStatusWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)resetWithContainer:(NSString *)container + context:(NSString *)context + resetReason:(CuttlefishResetReason)reason + reply:(void (^)(NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] resetWithContainer:container context:context resetReason:reason reply:reply]; + } while (retry); +} + +- (void)localResetWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] localResetWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)setAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + allowedMachineIDs:(NSSet *)allowedMachineIDs + reply:(void (^)(BOOL listDifferences, NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(NO, error); + } + ++i; + }] setAllowedMachineIDsWithContainer:container context:context allowedMachineIDs:allowedMachineIDs reply:reply]; + } while (retry); +} + +- (void)addAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + machineIDs:(NSArray *)machineIDs + reply:(void (^)(NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] addAllowedMachineIDsWithContainer:container + context:context + machineIDs:machineIDs + reply:reply]; + } while (retry); +} + +- (void)removeAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + machineIDs:(NSArray *)machineIDs + reply:(void (^)(NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] removeAllowedMachineIDsWithContainer:container context:context machineIDs:machineIDs reply:reply]; + } while (retry); +} + +- (void)fetchEgoEpochWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(unsigned long long epoch, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(0, error); + } + ++i; + }] fetchEgoEpochWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)prepareWithContainer:(NSString *)container + context:(NSString *)context + epoch:(unsigned long long)epoch + machineID:(NSString *)machineID + bottleSalt:(NSString *)bottleSalt + bottleID:(NSString *)bottleID + modelID:(NSString *)modelID + deviceName:(nullable NSString*)deviceName + serialNumber:(NSString *)serialNumber + osVersion:(NSString *)osVersion + policyVersion:(nullable NSNumber *)policyVersion + policySecrets:(nullable NSDictionary *)policySecrets + signingPrivKeyPersistentRef:(nullable NSData *)spkPr + encPrivKeyPersistentRef:(nullable NSData*)epkPr + reply:(void (^)(NSString * _Nullable peerID, + NSData * _Nullable permanentInfo, + NSData * _Nullable permanentInfoSig, + NSData * _Nullable stableInfo, + NSData * _Nullable stableInfoSig, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, nil, nil, nil, error); + } + ++i; + }] prepareWithContainer:container context:context epoch:epoch machineID:machineID bottleSalt:bottleSalt bottleID:bottleID modelID:modelID deviceName:deviceName serialNumber:serialNumber osVersion:osVersion policyVersion:policyVersion policySecrets:policySecrets signingPrivKeyPersistentRef:spkPr encPrivKeyPersistentRef:epkPr reply:reply]; + } while (retry); +} + +- (void)establishWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)viewKeySets + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(nullable NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] establishWithContainer:container context:context ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)vouchWithContainer:(NSString *)container + context:(NSString *)context + peerID:(NSString *)peerID + permanentInfo:(NSData *)permanentInfo + permanentInfoSig:(NSData *)permanentInfoSig + stableInfo:(NSData *)stableInfo + stableInfoSig:(NSData *)stableInfoSig + ckksKeys:(NSArray *)viewKeySets + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] vouchWithContainer:container context:context peerID:peerID permanentInfo:permanentInfo permanentInfoSig:permanentInfoSig stableInfo:stableInfo stableInfoSig:stableInfoSig ckksKeys:viewKeySets reply:reply]; + } while (retry); +} + + +- (void)preflightVouchWithBottleWithContainer:(nonnull NSString *)container + context:(nonnull NSString *)context + bottleID:(nonnull NSString *)bottleID + reply:(nonnull void (^)(NSString * _Nullable, NSError * _Nullable))reply { + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] preflightVouchWithBottleWithContainer:container + context:context + bottleID:bottleID + reply:reply]; + } while (retry); +} + +- (void)vouchWithBottleWithContainer:(NSString *)container + context:(NSString *)context + bottleID:(NSString*)bottleID + entropy:(NSData*)entropy + bottleSalt:(NSString*)bottleSalt + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] vouchWithBottleWithContainer:container context:context bottleID:bottleID entropy:entropy bottleSalt:bottleSalt tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)vouchWithRecoveryKeyWithContainer:(NSString *)container + context:(NSString *)context + recoveryKey:(NSString*)recoveryKey + salt:(NSString*)salt + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] vouchWithRecoveryKeyWithContainer:container context:context recoveryKey:recoveryKey salt:salt tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)joinWithContainer:(NSString *)container + context:(NSString *)context + voucherData:(NSData *)voucherData + voucherSig:(NSData *)voucherSig + ckksKeys:(NSArray *)viewKeySets + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] joinWithContainer:container context:context voucherData:voucherData voucherSig:voucherSig ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)preflightPreapprovedJoinWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(BOOL launchOkay, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(NO, error); + } + ++i; + }] preflightPreapprovedJoinWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)attemptPreapprovedJoinWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)ckksKeys + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] attemptPreapprovedJoinWithContainer:container context:context ckksKeys:ckksKeys tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)updateWithContainer:(NSString *)container + context:(NSString *)context + deviceName:(nullable NSString *)deviceName + serialNumber:(nullable NSString *)serialNumber + osVersion:(nullable NSString *)osVersion + policyVersion:(nullable NSNumber *)policyVersion + policySecrets:(nullable NSDictionary *)policySecrets + reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState, NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] updateWithContainer:container context:context deviceName:deviceName serialNumber:serialNumber osVersion:osVersion policyVersion:policyVersion policySecrets:policySecrets reply:reply]; + } while (retry); +} + +- (void)setPreapprovedKeysWithContainer:(NSString *)container + context:(NSString *)context + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] setPreapprovedKeysWithContainer:container context:context preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)updateTLKsWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)ckksKeys + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] updateTLKsWithContainer:container context:context ckksKeys:ckksKeys tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)fetchViableBottlesWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSArray* _Nullable sortedBottleIDs, NSArray* _Nullable sortedPartialBottleIDs, NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] fetchViableBottlesWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchEscrowContentsWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSData* _Nullable entropy, + NSString* _Nullable bottleID, + NSData* _Nullable signingPublicKey, + NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, nil, error); + } + ++i; + }] fetchEscrowContentsWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchPolicyDocumentsWithContainer:(NSString*)container + context:(NSString*)context + keys:(NSDictionary*)keys + reply:(void (^)(NSDictionary*>* _Nullable entries, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] fetchPolicyDocumentsWithContainer:container context:context keys:keys reply:reply]; + } while (retry); +} + +- (void)fetchPolicyWithContainer:(NSString*)container + context:(NSString*)context + reply:(void (^)(TPPolicy * _Nullable policy, + NSError * _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] fetchPolicyWithContainer:container context:context reply:reply]; + } while (retry); +} + + +- (void)validatePeersWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSDictionary * _Nullable, NSError * _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] validatePeersWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchTrustStateWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(TrustedPeersHelperPeerState* _Nullable selfPeerState, + NSArray* _Nullable trustedPeers, + NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, nil, error); + } + ++i; + }] fetchTrustStateWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)setRecoveryKeyWithContainer:(NSString *)container + context:(NSString *)context + recoveryKey:(NSString *)recoveryKey + salt:(NSString *)salt + ckksKeys:(NSArray *)ckksKeys + reply:(void (^)(NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] setRecoveryKeyWithContainer:container context:context recoveryKey:recoveryKey salt:salt ckksKeys:ckksKeys reply:reply]; + } while (retry); +} + +- (void)reportHealthWithContainer:(NSString *)container + context:(NSString *)context + stateMachineState:(NSString *)state + trustState:(NSString *)trustState + reply:(void (^)(NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] reportHealthWithContainer:container context:context stateMachineState:state trustState:trustState reply:reply]; + } while (retry); +} + +- (void)pushHealthInquiryWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSError* _Nullable error))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(error); + } + ++i; + }] pushHealthInquiryWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)getViewsWithContainer:(NSString *)container + context:(NSString *)context + inViews:(NSArray*)inViews + reply:(void (^)(NSArray* _Nullable, NSError* _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] getViewsWithContainer:container context:context inViews:inViews reply:reply]; + } while (retry); +} + +- (void)requestHealthCheckWithContainer:(NSString *)container + context:(NSString *)context + requiresEscrowCheck:(BOOL)requiresEscrowCheck + reply:(void (^)(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError* _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(NO, NO, NO, error); + } + ++i; + }] requestHealthCheckWithContainer:container context:context requiresEscrowCheck:requiresEscrowCheck reply:reply]; + } while (retry); +} +@end diff --git a/keychain/ot/OTBottledPeer.h b/keychain/ot/OTBottledPeer.h deleted file mode 100644 index 3d84714c..00000000 --- a/keychain/ot/OTBottledPeer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import -#import - -#import "OTEscrowKeys.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTBottledPeer : NSObject - -@property (nonatomic, readonly) NSString* peerID; -@property (nonatomic, readonly) NSString* spID; -@property (nonatomic, readonly) SFECKeyPair* peerSigningKey; -@property (nonatomic, readonly) SFECKeyPair* peerEncryptionKey; -@property (nonatomic, readonly) NSData* data; - -// Given a peer's details including private key material, and -// the keys generated from the escrow secret, encrypt the peer private keys, -// make a bottled peer object and serialize it into data. -- (nullable instancetype) initWithPeerID:(NSString * _Nullable)peerID - spID:(NSString * _Nullable)spID - peerSigningKey:(SFECKeyPair *)peerSigningKey - peerEncryptionKey:(SFECKeyPair *)peerEncryptionKey - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -// Deserialize a bottle and decrypt the contents (peer keys) -// using the keys generated from the escrow secret. -- (nullable instancetype) initWithData:(NSData *)data - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END - -#endif diff --git a/keychain/ot/OTBottledPeer.m b/keychain/ot/OTBottledPeer.m deleted file mode 100644 index 69e07cf9..00000000 --- a/keychain/ot/OTBottledPeer.m +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import "OTBottledPeer.h" - -#if OCTAGON -#import -#import -#import -#import -#import - -#import - -#import -#import -#import - -#import - -#import - -#if 0 -#import "OTBottle.h" -#import "OTBottleContents.h" -#endif - -#import "OTDefines.h" -#import "OTPrivateKey.h" -#import "OTPrivateKey+SF.h" -#import "OTAuthenticatedCiphertext.h" -#import "OTAuthenticatedCiphertext+SF.h" - -@interface OTBottledPeer () - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) SFECKeyPair* peerEncryptionKey; -@property (nonatomic, strong) NSData* data; - -@end - -@implementation OTBottledPeer - -+ (SFAuthenticatedEncryptionOperation *) encryptionOperation -{ - SFAESKeySpecifier *keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; - return [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:keySpecifier]; -} - -// Given a peer's details including private key material, and -// the keys generated from the escrow secret, encrypt the peer private keys, -// make a bottled peer object and serialize it into data. -- (nullable instancetype) initWithPeerID:(NSString * _Nullable)peerID - spID:(NSString * _Nullable)spID - peerSigningKey:(SFECKeyPair *)peerSigningKey - peerEncryptionKey:(SFECKeyPair *)peerEncryptionKey - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - self = [super init]; - if (self) { -#if 0 - // Serialize the peer private keys into "contents" - OTBottleContents *contentsObj = [[OTBottleContents alloc] init]; - contentsObj.peerSigningPrivKey = [OTPrivateKey fromECKeyPair:peerSigningKey]; - contentsObj.peerEncryptionPrivKey = [OTPrivateKey fromECKeyPair:peerEncryptionKey]; - NSData *clearContentsData = contentsObj.data; - - // Encrypt the contents - SFAuthenticatedEncryptionOperation *op = [OTBottledPeer encryptionOperation]; - SFAuthenticatedCiphertext* cipher = [op encrypt:clearContentsData withKey:escrowKeys.symmetricKey error:error]; - if (!cipher) { - return nil; - } - - // Serialize the whole thing - OTBottle *obj = [[OTBottle alloc] init]; - obj.peerID = peerID; - obj.spID = spID; - obj.escrowedSigningSPKI = [escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]; - obj.escrowedEncryptionSPKI = [escrowKeys.encryptionKey.publicKey encodeSubjectPublicKeyInfo]; - obj.peerSigningSPKI = [peerSigningKey.publicKey encodeSubjectPublicKeyInfo]; - obj.peerEncryptionSPKI = [peerEncryptionKey.publicKey encodeSubjectPublicKeyInfo]; - obj.contents = [OTAuthenticatedCiphertext fromSFAuthenticatedCiphertext:cipher]; - - _peerID = [peerID copy]; - _spID = [spID copy]; - _peerSigningKey = peerSigningKey; - _peerEncryptionKey = peerEncryptionKey; - _data = obj.data; -#endif - } - return self; -} - -// Deserialize a bottle and decrypt the contents (peer keys) -// using the keys generated from the escrow secret. -- (nullable instancetype) initWithData:(NSData *)data - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - self = [super init]; - if (self) { -#if 0 - NSError* localError =nil; - // Deserialize the whole thing - OTBottle *obj = [[OTBottle alloc] initWithData:data]; - if (!obj) { - secerror("octagon: failed to deserialize data into OTBottle"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorDeserializationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}]; - } - return nil; - - - // Decrypt contents - SFAuthenticatedEncryptionOperation *op = [OTBottledPeer encryptionOperation]; - SFAuthenticatedCiphertext* ciphertext = [obj.contents asSFAuthenticatedCiphertext]; - NSData* clearContentsData = [op decrypt:ciphertext withKey:escrowKeys.symmetricKey error:&localError]; - if (!clearContentsData || clearContentsData.length == 0) { - secerror("octagon: could not decrypt bottle contents: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - - // Deserialize contents into private peer keys - OTBottleContents *contentsObj = [[OTBottleContents alloc] initWithData:clearContentsData]; - if (!contentsObj) { - secerror("octagon: could not deserialize bottle contents"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorDeserializationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle contents"}]; - } - return nil; - } - - _peerID = obj.peerID; - _spID = obj.spID; - if (self.keyType != OTPrivateKey_KeyType_EC_NIST_CURVES) { - return nil; - } - return [[SFECKeyPair alloc] initWithSecKey:[EscrowKeys createSecKey:self.keyData]]; - - _peerSigningKey = [contentsObj.peerSigningPrivKey asECKeyPair]; - _peerEncryptionKey = [contentsObj.peerEncryptionPrivKey asECKeyPair]; - if (!_peerSigningKey || !_peerEncryptionKey) { - secerror("octagon: could not get private EC keys from bottle contents"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to instantiate octagon peer keys"}]; - } - return nil; - } - _data = [data copy]; - - SFECPublicKey *peerSigningPubKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:obj.peerSigningSPKI]; - SFECPublicKey *peerEncryptionPubKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:obj.peerEncryptionSPKI]; - - // Check the private keys match the public keys - if (![_peerSigningKey.publicKey isEqual:peerSigningPubKey]) { - secerror("octagon: public and private peer signing keys do not match"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"public and private peer signing keys do not match"}]; - } - return nil; - } - if (![_peerEncryptionKey.publicKey isEqual:peerEncryptionPubKey]) { - secerror("octagon: public and private peer encryption keys do not match"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"public and private peer encryption keys do not match"}]; - } - return nil; - } -#endif - } - return self; -} - -@end - -#endif - - diff --git a/keychain/ot/OTBottledPeerRecord.h b/keychain/ot/OTBottledPeerRecord.h deleted file mode 100644 index 18390f91..00000000 --- a/keychain/ot/OTBottledPeerRecord.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import - -@interface OTBottledPeerRecord : NSObject - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) NSData* bottle; -@property (nonatomic, strong) NSString* escrowRecordID; -@property (nonatomic, strong) NSData* escrowedSigningSPKI; -@property (nonatomic, strong) NSData* peerSigningSPKI; -@property (nonatomic, strong) NSData* signatureUsingEscrowKey; -@property (nonatomic, strong) NSData* signatureUsingPeerKey; -@property (nonatomic, strong) NSData* encodedRecord; -@property (nonatomic, readonly) NSString* recordName; -@property (nonatomic, strong) NSString* launched; - -+ (NSString*) constructRecordID:(NSString*)escrowRecordID escrowSigningSPKI:(NSData*)escrowSigningSPKI; - -@end -#endif diff --git a/keychain/ot/OTBottledPeerRecord.m b/keychain/ot/OTBottledPeerRecord.m deleted file mode 100644 index 5dd5f270..00000000 --- a/keychain/ot/OTBottledPeerRecord.m +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import "OTBottledPeerRecord.h" -#import -#import -#import - -static NSString* OTCKRecordName = @"bp-"; - -@implementation OTBottledPeerRecord - --(NSString*) recordName -{ - return [OTBottledPeerRecord constructRecordID:self.escrowRecordID escrowSigningSPKI:self.escrowedSigningSPKI]; -} - -+ (NSString*) constructRecordID:(NSString*)escrowRecordID escrowSigningSPKI:(NSData*)escrowSigningSPKI -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [escrowSigningSPKI length], [escrowSigningSPKI bytes], [result mutableBytes]); - - NSString* hash = [result base64EncodedStringWithOptions:0]; - - return [NSString stringWithFormat:@"%@-spid:%@-%@", OTCKRecordName, escrowRecordID, hash]; -} - -@end -#endif diff --git a/keychain/ot/OTBottledPeerSigned.h b/keychain/ot/OTBottledPeerSigned.h deleted file mode 100644 index c21599e2..00000000 --- a/keychain/ot/OTBottledPeerSigned.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import -#import "OTBottledPeer.h" -#import "OTBottledPeerRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTBottledPeerSigned : NSObject -@property (nonatomic, readonly) OTBottledPeer* bp; -@property (nonatomic, readonly) NSData* signatureUsingEscrowKey; -@property (nonatomic, readonly) NSData* signatureUsingPeerKey; -@property (nonatomic, readonly) NSData* escrowSigningSPKI; - -- (instancetype) init NS_UNAVAILABLE; - -// Create signatures -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - escrowedSigningKey:(SFECKeyPair *)escrowedSigningKey - peerSigningKey:(SFECKeyPair *)peerSigningKey - error:(NSError**)error; - -// Verify signatures, or return nil -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - signatureUsingEscrow:(NSData*)signatureUsingEscrow - signatureUsingPeerKey:(NSData*)signatureUsingPeerKey - escrowedSigningPubKey:(SFECPublicKey *)escrowedSigningPubKey - error:(NSError**)error; - -// Convenience wrapper, verifies signatures -- (nullable instancetype) initWithBottledPeerRecord:(OTBottledPeerRecord *)record - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -- (OTBottledPeerRecord *)asRecord:(NSString*)escrowRecordID; -+ (BOOL) verifyBottleSignature:(NSData*)data signature:(NSData*)signature key:(_SFECPublicKey*) pubKey error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END - -#endif diff --git a/keychain/ot/OTBottledPeerSigned.m b/keychain/ot/OTBottledPeerSigned.m deleted file mode 100644 index eeef3d06..00000000 --- a/keychain/ot/OTBottledPeerSigned.m +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import -#import "OTBottledPeer.h" -#import "OTBottledPeerSigned.h" -#import "OTIdentity.h" - -#import -#import -#import -#import -#import - -#import -#import -#import - -#include - -@interface OTBottledPeerSigned () -@property (nonatomic, strong) OTBottledPeer* bp; -@property (nonatomic, strong) NSData* signatureUsingEscrowKey; -@property (nonatomic, strong) NSData* signatureUsingPeerKey; -@property (nonatomic, strong) NSData* escrowSigningPublicKey; -@end - -@implementation OTBottledPeerSigned - -// Create signatures -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - escrowedSigningKey:(SFECKeyPair *)escrowedSigningKey - peerSigningKey:(SFECKeyPair *)peerSigningKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _bp = bp; - _escrowSigningSPKI = [escrowedSigningKey.publicKey encodeSubjectPublicKeyInfo]; - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - _signatureUsingEscrowKey = [xso sign:bp.data withKey:escrowedSigningKey error:error].signature; - if (!_signatureUsingEscrowKey) { - return nil; - } - _signatureUsingPeerKey = [xso sign:bp.data withKey:peerSigningKey error:error].signature; - if (!_signatureUsingPeerKey) { - return nil; - } - } - return self; -} - --(NSString*) escrowSigningPublicKeyHash -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [self.escrowSigningPublicKey length], [self.escrowSigningPublicKey bytes], [result mutableBytes]); - - return [result base64EncodedStringWithOptions:0]; -} - -// Verify signatures, or return nil -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - signatureUsingEscrow:(NSData*)signatureUsingEscrow - signatureUsingPeerKey:(NSData*)signatureUsingPeerKey - escrowedSigningPubKey:(SFECPublicKey *)escrowedSigningPubKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _bp = bp; - _escrowSigningSPKI = [escrowedSigningPubKey encodeSubjectPublicKeyInfo]; - _signatureUsingPeerKey = signatureUsingPeerKey; - _signatureUsingEscrowKey = signatureUsingEscrow; - _escrowSigningPublicKey = [escrowedSigningPubKey keyData]; - - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - - SFSignedData *escrowSigned = [[SFSignedData alloc] initWithData:bp.data signature:signatureUsingEscrow]; - if (![xso verify:escrowSigned withKey:escrowedSigningPubKey error:error]) { - return nil; - } - SFSignedData *peerSigned = [[SFSignedData alloc] initWithData:bp.data signature:signatureUsingPeerKey]; - if (![xso verify:peerSigned withKey:bp.peerSigningKey.publicKey error:error]) { - return nil; - } - //stuff restored keys in the keychain - [OTIdentity storeOctagonIdentityIntoKeychain:self.bp.peerSigningKey restoredEncryptionKey:self.bp.peerEncryptionKey escrowSigningPubKeyHash:self.escrowSigningPublicKeyHash restoredPeerID:self.bp.spID error:error]; - } - return self; -} - -+ (SFEC_X962SigningOperation*) signingOperation -{ - SFECKeySpecifier *keySpecifier = [[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]; - id digestOperation = [[SFSHA384DigestOperation alloc] init]; - return [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:keySpecifier digestOperation:digestOperation]; -} - -+ (BOOL) verifyBottleSignature:(NSData*)data signature:(NSData*)signature key:(_SFECPublicKey*) pubKey error:(NSError**)error -{ - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - - SFSignedData *peerSigned = [[SFSignedData alloc] initWithData:data signature:signature]; - - return ([xso verify:peerSigned withKey:pubKey error:error] != nil); - -} - -- (nullable instancetype) initWithBottledPeerRecord:(OTBottledPeerRecord *)record - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithData:record.bottle - escrowKeys:escrowKeys - error:error]; - if (!bp) { - return nil; - } - return [self initWithBottledPeer:bp - signatureUsingEscrow:record.signatureUsingEscrowKey - signatureUsingPeerKey:record.signatureUsingPeerKey - escrowedSigningPubKey:escrowKeys.signingKey.publicKey - error:error]; -} - -- (OTBottledPeerRecord *)asRecord:(NSString*)escrowRecordID -{ - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.spID = self.bp.spID; - rec.escrowRecordID = [escrowRecordID copy]; - rec.peerSigningSPKI = [self.bp.peerSigningKey.publicKey encodeSubjectPublicKeyInfo]; - rec.escrowedSigningSPKI = self.escrowSigningSPKI; - rec.bottle = self.bp.data; - rec.signatureUsingPeerKey = self.signatureUsingPeerKey; - rec.signatureUsingEscrowKey = self.signatureUsingEscrowKey; - rec.launched = @"NO"; - return rec; -} - -@end -#endif - diff --git a/keychain/ot/OTBottledPeerState.h b/keychain/ot/OTBottledPeerState.h deleted file mode 100644 index eb0ec436..00000000 --- a/keychain/ot/OTBottledPeerState.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#ifndef OTBottledPeerState_h -#define OTBottledPeerState_h - -#import - -NS_ASSUME_NONNULL_BEGIN - -/* Bottled Peer States */ -@protocol SecOTBottledPeerState -@end -typedef NSString OTBottledPeerState; - -// Octagon Trust currently logged out -extern OTBottledPeerState* const SecOTBottledPeerStateLoggedOut; - -// Octagon Trust currently signed in -extern OTBottledPeerState* const SecOTBottledPeerStateSignedIn; - -// Octagon Trust: check bottle states -extern OTBottledPeerState* const SecOTBottledPeerStateInventoryCheck; - -// Octagon Trust: update bottles for current peerid with current octagon keys -extern OTBottledPeerState* const SecOTBottledPeerStateUpdateBottles; - -// Octagon Trust: bottles exist for the current octagon key set and have been writte to cloudkit -extern OTBottledPeerState* const SecOTBottledPeerStateCleanBottles; - -// Octagon Trust: bottles for current peerid have been updated and persited locally, but not commited to cloudkit -extern OTBottledPeerState* const SecOTBottledPeerStateDirtyBottles; - -NS_ASSUME_NONNULL_END - -#endif /* OTBottledPeerState_h */ -#endif diff --git a/keychain/ot/OTBottledPeerState.m b/keychain/ot/OTBottledPeerState.m deleted file mode 100644 index 3c697b2e..00000000 --- a/keychain/ot/OTBottledPeerState.m +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import "keychain/ot/OTBottledPeerState.h" - -OTBottledPeerState* const SecOTBottledPeerStateLoggedOut = (OTBottledPeerState*) @"loggedout"; -OTBottledPeerState* const SecOTBottledPeerStateSignedIn = (OTBottledPeerState*) @"signedin"; -OTBottledPeerState* const SecOTBottledPeerStateInventoryCheck = (OTBottledPeerState*) @"inventorycheck"; -OTBottledPeerState* const SecOTBottledPeerStateUpdateBottles = (OTBottledPeerState*) @"updatebottles"; -OTBottledPeerState* const SecOTBottledPeerStateCleanBottles = (OTBottledPeerState*) @"cleanbottles"; -OTBottledPeerState* const SecOTBottledPeerStateDirtyBottles = (OTBottledPeerState*) @"dirtybottles"; - -#endif diff --git a/keychain/ot/OTCheckHealthOperation.m b/keychain/ot/OTCheckHealthOperation.m index b1edee94..b76ce462 100644 --- a/keychain/ot/OTCheckHealthOperation.m +++ b/keychain/ot/OTCheckHealthOperation.m @@ -25,6 +25,7 @@ #import "keychain/ot/OTCheckHealthOperation.h" #import "keychain/ot/OTOperationDependencies.h" +#import "keychain/ot/OTStates.h" #import "keychain/ot/ObjCImprovements.h" #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import @@ -146,31 +147,40 @@ } WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-health: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - return; - - }] requestHealthCheckWithContainer:self.deps.containerName - context:self.deps.contextID - requiresEscrowCheck: [self checkIfPasscodeIsSetForDevice] - reply:^(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError *error) { - STRONGIFY(self); - if(error) { - secerror("octagon-health: error: %@", error); - self.error = error; - } else { - secnotice("octagon-health", "cuttlefish came back with these suggestions\n: post repair? %d\n, post escrow? %d\n, reset octagon? %d", postRepairCFU, postEscrowCFU, resetOctagon); - self.postEscrowCFU = postEscrowCFU; - self.postRepairCFU = postRepairCFU; - self.resetOctagon = resetOctagon; - - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishOp]; - }]; + [self.deps.cuttlefishXPCWrapper requestHealthCheckWithContainer:self.deps.containerName + context:self.deps.contextID + requiresEscrowCheck: [self checkIfPasscodeIsSetForDevice] + reply:^(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError *error) { + STRONGIFY(self); + if(error) { + secerror("octagon-health: error: %@", error); + self.error = error; + + [self runBeforeGroupFinished:self.finishOp]; + return; + } else { + secnotice("octagon-health", "cuttlefish came back with these suggestions\n: post repair? %d\n, post escrow? %d\n, reset octagon? %d", postRepairCFU, postEscrowCFU, resetOctagon); + [self handleRepairSuggestions:postRepairCFU + postEscrowCFU:postEscrowCFU + resetOctagon:resetOctagon]; + } + }]; +} + +- (void)handleRepairSuggestions:(BOOL)postRepairCFU postEscrowCFU:(BOOL)postEscrowCFU resetOctagon:(BOOL)resetOctagon +{ + self.postEscrowCFU = postEscrowCFU; + self.postRepairCFU = postRepairCFU; + self.resetOctagon = resetOctagon; + + if (resetOctagon) { + secnotice("octagon-health", "Resetting Octagon as per Cuttlefish request"); + self.nextState = OctagonStateHealthCheckReset; + } else { + self.nextState = self.intendedState; + } + + [self runBeforeGroupFinished:self.finishOp]; } @end diff --git a/keychain/ot/OTClientStateMachine.m b/keychain/ot/OTClientStateMachine.m index 8570fa0d..32f8f044 100644 --- a/keychain/ot/OTClientStateMachine.m +++ b/keychain/ot/OTClientStateMachine.m @@ -41,7 +41,6 @@ #import "keychain/ot/ObjCImprovements.h" #import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTPrepareOperation.h" #import "keychain/ot/OTSOSAdapter.h" @@ -304,9 +303,11 @@ NSDictionary* OctagonClientStateMap(void) { reply:(void (^)(uint64_t epoch, NSError * _Nullable error))reply { - OTEpochOperation* pendingOp = [[OTEpochOperation alloc] initForCuttlefishContext:cuttlefishContext - intendedState:OctagonStateAcceptorAwaitingIdentity - errorState:OctagonStateAcceptorDone]; + OTEpochOperation* pendingOp = [[OTEpochOperation alloc] init:self.containerName + contextID:self.contextID + intendedState:OctagonStateAcceptorAwaitingIdentity + errorState:OctagonStateAcceptorDone + cuttlefishXPCWrapper:cuttlefishContext.cuttlefishXPCWrapper]; OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"rpcEpoch" sourceStates:[NSSet setWithArray:@[OctagonStateAcceptorBeginClientJoin]] diff --git a/keychain/ot/OTClientVoucherOperation.m b/keychain/ot/OTClientVoucherOperation.m index 0f3d4039..6257c0d2 100644 --- a/keychain/ot/OTClientVoucherOperation.m +++ b/keychain/ot/OTClientVoucherOperation.m @@ -96,34 +96,29 @@ secnotice("octagon", "vouching with %d keysets", (int)viewKeySets.count); - [[self.operationDependencies.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] vouchWithContainer:self.deviceInfo.containerName - context:self.deviceInfo.contextID - peerID:self.peerID - permanentInfo:self.permanentInfo - permanentInfoSig:self.permanentInfoSig - stableInfo:self.stableInfo - stableInfoSig:self.stableInfoSig - ckksKeys:viewKeySets - reply:^(NSData * _Nullable voucher, - NSData * _Nullable voucherSig, - NSError * _Nullable error) - { - if(error){ - secerror("octagon: Error preparing voucher: %@", error); - self.error = error; - }else{ - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.operationDependencies.cuttlefishXPCWrapper vouchWithContainer:self.deviceInfo.containerName + context:self.deviceInfo.contextID + peerID:self.peerID + permanentInfo:self.permanentInfo + permanentInfoSig:self.permanentInfoSig + stableInfo:self.stableInfo + stableInfoSig:self.stableInfoSig + ckksKeys:viewKeySets + reply:^(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error) + { + STRONGIFY(self); + if(error){ + secerror("octagon: Error preparing voucher: %@", error); + self.error = error; + }else{ + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTClique.h b/keychain/ot/OTClique.h index 4e8100cc..77217221 100644 --- a/keychain/ot/OTClique.h +++ b/keychain/ot/OTClique.h @@ -42,6 +42,7 @@ typedef NS_ENUM(NSInteger, CliqueStatus) { #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -62,7 +63,6 @@ extern NSString* kSecEntitlementPrivateOctagonEscrow; @property (nonatomic, copy) NSString* altDSID; @property (nonatomic, strong, nullable) SFSignInAnalytics* analytics; - // Use this to inject your own OTControl object. It must be configured as synchronous. @property (nullable, strong) OTControl* otControl; // Use this to inject your own SecureBackup object. It must conform to the OctagonEscrowRecoverer protocol. @@ -86,11 +86,6 @@ extern NSString* kSecEntitlementPrivateOctagonEscrow; @property (nonatomic, assign) BOOL useCachedAccountStatus; @end -typedef NSString* OTCliqueCFUType NS_STRING_ENUM; -extern OTCliqueCFUType OTCliqueCFTypeRepair; -extern OTCliqueCFUType OTCliqueCFTypePasscode; -extern OTCliqueCFUType OTCliqueCFTypeUpgrade; - typedef NSString* OTCliqueCDPContextType NS_STRING_ENUM; extern OTCliqueCDPContextType OTCliqueCDPContextTypeNone; extern OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn; @@ -130,7 +125,20 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; * @return clique, returns a new clique instance * @param error, error gets filled if something goes horribly wrong */ -+ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error; ++ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error __deprecated_msg("use newFriendsWithContextData:resetReason:error: instead"); + +/* * +* @abstract Establish a new clique, reset protected data +* Reset the clique +* Delete backups +* Delete all CKKS data +* +* @param ctx, context containing parameters to setup OTClique +* @param resetReason, a reason that drives cdp to perform a reset +* @return clique, returns a new clique instance +* @param error, error gets filled if something goes horribly wrong +*/ ++ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error; /* * @abstract Perform a SecureBackup escrow/keychain recovery and attempt to use the information therein to join this account. @@ -236,7 +244,7 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error; -- (NSArray*)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error; +- (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error; - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews; @@ -248,7 +256,7 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; password:(NSData*)userPassword error:(NSError *__autoreleasing*)error; -- (NSArray*)copyPeerPeerInfo:(NSError *__autoreleasing*)error; +- (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error; - (BOOL)peersHaveViewsEnabled:(NSArray*)viewNames error:(NSError *__autoreleasing*)error; diff --git a/keychain/ot/OTClique.m b/keychain/ot/OTClique.m index 918077d4..8a6c33b3 100644 --- a/keychain/ot/OTClique.m +++ b/keychain/ot/OTClique.m @@ -61,10 +61,6 @@ SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain); #pragma clang diagnostic pop #endif -OTCliqueCFUType OTCliqueCFTypeRepair = @"typeRepair"; -OTCliqueCFUType OTCliqueCFTypePasscode = @"typePasscode"; -OTCliqueCFUType OTCliqueCFTypeUpgrade = @"typeUpgrade"; - OTCliqueCDPContextType OTCliqueCDPContextTypeNone = @"cdpContextTypeNone"; OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn = @"cdpContextTypeSignIn"; OTCliqueCDPContextType OTCliqueCDPContextTypeRepair = @"cdpContextTypeRepair"; @@ -172,7 +168,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) + (BOOL)platformSupportsSOS { - return OctagonPlatformSupportsSOS(); + return (OctagonPlatformSupportsSOS() && OctagonIsSOSFeatureEnabled()); } // defaults write com.apple.security.octagon enable -bool YES @@ -237,7 +233,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique", "cliqueMemberIdentifier(octagon) received %@", retPeerID); } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef error = NULL; SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(&error); retPeerID = (NSString*)CFBridgingRelease(CFRetainSafe(SOSPeerInfoGetPeerID(me))); @@ -286,7 +282,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) return success; } -- (BOOL)resetAndEstablish:(NSError**)error +- (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error { secnotice("clique-resetandestablish", "resetAndEstablish started"); @@ -298,7 +294,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) __block BOOL success = NO; __block NSError* localError = nil; - [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID reply:^(NSError * _Nullable operationError) { + [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID resetReason:resetReason reply:^(NSError * _Nullable operationError) { if(operationError) { secnotice("clique-resetandestablish", "resetAndEstablish returned an error: %@", operationError); @@ -318,16 +314,21 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) #endif // OCTAGON + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error +{ + return [OTClique newFriendsWithContextData:data resetReason:CuttlefishResetReasonUserInitiatedReset error:error]; +} + ++ (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error { #if OCTAGON secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid); bool result = false; - + OTClique* clique = [[OTClique alloc] initWithContextData:data error:error]; if(OctagonIsEnabled()) { NSError* localError = nil; - [clique resetAndEstablish:&localError]; + [clique resetAndEstablish:resetReason error:&localError]; if(localError) { secnotice("clique-newfriends", "account reset failed: %@", localError); @@ -340,7 +341,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef resetError = NULL; NSData* analyticsData = nil; if(data.analytics) { @@ -394,7 +395,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(recoverError) { secnotice("clique-recovery", "sbd escrow recovery failed: %@", recoverError); - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */ secnotice("clique-recovery", "Can't restore legacy backup with no keybag. Resetting SOS to offering"); CFErrorRef blowItAwayError = NULL; @@ -482,7 +483,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(shouldResetOctagon) { secnotice("clique-recovery", "bottle %@ is not valid, resetting octagon", bottleID); NSError* resetError = nil; - [clique resetAndEstablish:&resetError]; + [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError]; if(resetError) { secnotice("clique-recovery", "failed to reset octagon: %@", resetError); } else{ @@ -576,7 +577,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef circleStatusError = NULL; sosStatus = kSOSCCError; if(configuration.useCachedAccountStatus){ @@ -701,7 +702,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) }]; } - if(OctagonPlatformSupportsSOS() && sosIdentifiers.count > 0) { + if([OTClique platformSupportsSOS] && sosIdentifiers.count >0) { CFErrorRef removeFriendError = NULL; NSData* analyticsData = nil; @@ -764,7 +765,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) result = !localError; } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { NSData* analyticsData = nil; if(self.ctx.analytics) { @@ -831,7 +832,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique", "Received %lu Octagon peers", (unsigned long)localPeers.count); } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef peerErrorRef = NULL; NSMutableDictionary* peerMapping = [NSMutableDictionary dictionary]; NSArray* arrayOfPeerRefs = CFBridgingRelease(SOSCCCopyPeerPeerInfo(&peerErrorRef)); @@ -862,36 +863,56 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error { secnotice("clique-recovery", "joinAfterRestore for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef restoreError = NULL; + if([OTClique platformSupportsSOS]) { + CFErrorRef restoreError = NULL; - bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError); - if (error) { - *error = (NSError*)CFBridgingRelease(restoreError); + bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError); + if (error) { + *error = (NSError*)CFBridgingRelease(restoreError); + } else { + CFBridgingRelease(restoreError); + } + secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided"); + return res; } else { - CFBridgingRelease(restoreError); + secnotice("clique-recovery", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"join after restore unimplemented"}]; + } + return NO; } - secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided"); - return res; } - (BOOL)safariPasswordSyncingEnabled:(NSError **)error { secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef viewErrorRef = NULL; + if([OTClique platformSupportsSOS]) { + CFErrorRef viewErrorRef = NULL; - SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef); + SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef); - BOOL viewMember = result == kSOSCCViewMember; - if (error) { - *error = (NSError*)CFBridgingRelease(viewErrorRef); - } else { - CFBridgingRelease(viewErrorRef); - } + BOOL viewMember = result == kSOSCCViewMember; + if (error) { + *error = (NSError*)CFBridgingRelease(viewErrorRef); + } else { + CFBridgingRelease(viewErrorRef); + } - secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO"); + secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO"); - return viewMember; + return viewMember; + } else { + secnotice("clique-safari", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"safari password syncing enabled unimplemented"}]; + } + return NO; + } } - (BOOL)isLastFriend:(NSError **)error @@ -903,63 +924,89 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "waitForInitialSync for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef initialSyncErrorRef = NULL; - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCWaitForInitialSyncWithAnalytics((__bridge CFDataRef)analyticsData, &initialSyncErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef initialSyncErrorRef = NULL; + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCWaitForInitialSyncWithAnalytics((__bridge CFDataRef)analyticsData, &initialSyncErrorRef); + }else{ + result = SOSCCWaitForInitialSync(&initialSyncErrorRef); + } }else{ result = SOSCCWaitForInitialSync(&initialSyncErrorRef); } - }else{ - result = SOSCCWaitForInitialSync(&initialSyncErrorRef); - } - - BOOL initialSyncResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(initialSyncErrorRef); + + BOOL initialSyncResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(initialSyncErrorRef); + } else { + CFBridgingRelease(initialSyncErrorRef); + } + secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided"); + return initialSyncResult; } else { - CFBridgingRelease(initialSyncErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"wait for initial sync unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided"); - return initialSyncResult; } -- (NSArray*)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error +- (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "copyViewUnawarePeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL; - CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef); - NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil); - if (error) { - *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL; + CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef); + + NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil); + if (error) { + *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + } else { + CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + } + return peerList; } else { - CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NULL"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"copy view unaware peer info unimplemented"}]; + } + return nil; } - return peerList; } - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews { secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCViewSetWithAnalytics((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews, (__bridge CFDataRef)analyticsData); + if([OTClique platformSupportsSOS]) { + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCViewSetWithAnalytics((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews, (__bridge CFDataRef)analyticsData); + }else{ + result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); + } }else{ result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); } - }else{ - result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); - } - BOOL viewSetResult = (result == true); - return viewSetResult; + BOOL viewSetResult = (result == true); + return viewSetResult; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + return NO; + } } - (BOOL)setUserCredentialsAndDSID:(NSString*)userLabel @@ -967,38 +1014,48 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "setUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef setCredentialsErrorRef = NULL; - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCSetUserCredentialsAndDSIDWithAnalytics((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - (__bridge CFDataRef)analyticsData, - &setCredentialsErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef setCredentialsErrorRef = NULL; + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCSetUserCredentialsAndDSIDWithAnalytics((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + (__bridge CFDataRef)analyticsData, + &setCredentialsErrorRef); + }else{ + result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + &setCredentialsErrorRef); + } }else{ result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, (__bridge CFDataRef)userPassword, (__bridge CFStringRef)self.ctx.dsid, &setCredentialsErrorRef); } - }else{ - result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - &setCredentialsErrorRef); - } - BOOL setCredentialsResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef); + BOOL setCredentialsResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef); + } else { + CFBridgingRelease(setCredentialsErrorRef); + } + secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef); + return setCredentialsResult; } else { - CFBridgingRelease(setCredentialsErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"set user credentials unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef); - return setCredentialsResult; } - (BOOL)tryUserCredentialsAndDSID:(NSString*)userLabel @@ -1006,60 +1063,91 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "tryUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef tryCredentialsErrorRef = NULL; - bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - &tryCredentialsErrorRef); - BOOL tryCredentialsResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef tryCredentialsErrorRef = NULL; + bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + &tryCredentialsErrorRef); + + BOOL tryCredentialsResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef); + } else { + CFBridgingRelease(tryCredentialsErrorRef); + } + secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef); + return tryCredentialsResult; } else { - CFBridgingRelease(tryCredentialsErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"try user credentials unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef); - return tryCredentialsResult; - } -- (NSArray*)copyPeerPeerInfo:(NSError *__autoreleasing*)error +- (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "copyPeerPeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef copyPeerErrorRef = NULL; - CFArrayRef result = SOSCCCopyPeerPeerInfo(©PeerErrorRef); - NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil); + if([OTClique platformSupportsSOS]) { + CFErrorRef copyPeerErrorRef = NULL; + CFArrayRef result = SOSCCCopyPeerPeerInfo(©PeerErrorRef); - if (error) { - *error = (NSError*)CFBridgingRelease(copyPeerErrorRef); - } else { - CFBridgingRelease(copyPeerErrorRef); - } - secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList); + NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil); - return peerList; + if (error) { + *error = (NSError*)CFBridgingRelease(copyPeerErrorRef); + } else { + CFBridgingRelease(copyPeerErrorRef); + } + secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList); + return peerList; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"copy peer peer info unimplemented"}]; + } + return nil; + } } - (BOOL)peersHaveViewsEnabled:(NSArray*)viewNames error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "peersHaveViewsEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef viewsEnabledErrorRef = NULL; - BOOL viewsEnabledResult = NO; - CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef); - if(result){ - viewsEnabledResult = CFBooleanGetValue(result); - } - if (error) { - *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef viewsEnabledErrorRef = NULL; + BOOL viewsEnabledResult = NO; + + CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef); + if(result){ + viewsEnabledResult = CFBooleanGetValue(result); + } + if (error) { + *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef); + } else { + CFBridgingRelease(viewsEnabledErrorRef); + } + secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO"); + + return viewsEnabledResult; } else { - CFBridgingRelease(viewsEnabledErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"peers have views enabled unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO"); - - return viewsEnabledResult; } - (BOOL)requestToJoinCircle:(NSError *__autoreleasing*)error @@ -1072,7 +1160,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(OctagonIsEnabled()) { NSError* localError = nil; - [self resetAndEstablish:&localError]; + [self resetAndEstablish:CuttlefishResetReasonLegacyJoinCircle error:&localError]; if(localError) { secnotice("clique-legacy", "account reset failed: %@", localError); @@ -1092,7 +1180,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } #endif // OCTAGON - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { NSData* analyticsData = nil; if(self.ctx.analytics){ NSError* encodingError = nil; @@ -1119,11 +1207,17 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)accountUserKeyAvailable { secnotice("clique-legacy", "accountUserKeyAvailable for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL); - if (canAuthenticate == NO) { - secnotice("clique-legacy", "Security requires credentials..."); + + if([OTClique platformSupportsSOS]) { + BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL); + if (canAuthenticate == NO) { + secnotice("clique-legacy", "Security requires credentials..."); + } + return canAuthenticate; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + return NO; } - return canAuthenticate; } // MARK: SBD interfaces @@ -1266,7 +1360,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) reply(nil, retError); return; } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef registerError = nil; if (!SecRKRegisterBackupPublicKey(rk, ®isterError)) { secerror("octagon-setrecoverykey, SecRKRegisterBackupPublicKey() failed: %@", registerError); diff --git a/keychain/ot/OTCloudStore.h b/keychain/ot/OTCloudStore.h deleted file mode 100644 index 4b6ecb29..00000000 --- a/keychain/ot/OTCloudStore.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef OTCloudStore_h -#define OTCloudStore_h - -#if OCTAGON -#import "keychain/ot/OTLocalStore.h" - -#import -#import - -#import "keychain/ckks/CKKSZone.h" -#import "keychain/ckks/CloudKitDependencies.h" -#import "keychain/ckks/CKKSCloudKitClassDependencies.h" -#import "keychain/ckks/CKKSCondition.h" -#import "keychain/ckks/CKKSZoneChangeFetcher.h" -#import "keychain/ckks/CKKSNotifier.h" -#import "keychain/ckks/CKKSSQLDatabaseObject.h" -#import "keychain/ckks/CKKSRecordHolder.h" -#import "keychain/ckks/CKKSZoneModifier.h" -#import "OTBottledPeerRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTCloudStore : CKKSZone - -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) NSString* containerName; -@property (nonatomic, readonly) CKRecordID* recordID; -@property (nonatomic, readonly) CKKSResultOperation* viewSetupOperation; -@property CKKSCondition* loggedIn; -@property CKKSCondition* loggedOut; - - -- (instancetype) initWithContainer:(CKContainer*) container - zoneName:(NSString*)zoneName - accountTracker:(nullable CKKSAccountStateTracker*)accountTracker - reachabilityTracker:(nullable CKKSReachabilityTracker*)reachabilityTracker - localStore:(OTLocalStore*)localStore - contextID:(NSString*)contextID - dsid:(NSString*)dsid - zoneModifier:(CKKSZoneModifier*)zoneModifier - cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies - operationQueue:(nullable NSOperationQueue *)operationQueue; - - -- (BOOL) uploadBottledPeerRecord:(OTBottledPeerRecord *)bprecord - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error; -- (BOOL) downloadBottledPeerRecord:(NSError**)error; -- (BOOL) removeBottledPeerRecordID:(CKRecordID*)recordID error:(NSError**)error; -- (nullable NSArray*) retrieveListOfEligibleEscrowRecordIDs:(NSError**)error; - -- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification; -- (void)handleCKLogin; -- (BOOL) performReset:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END -#endif -#endif /* OTCloudStore_h */ diff --git a/keychain/ot/OTCloudStore.m b/keychain/ot/OTCloudStore.m deleted file mode 100644 index 241b732a..00000000 --- a/keychain/ot/OTCloudStore.m +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import -#import -#import -#import - -#import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTCloudStore.h" -#import "keychain/ot/OTCloudStoreState.h" -#import "keychain/ckks/CKKSZoneStateEntry.h" -#import "keychain/ckks/CKKS.h" -#import "keychain/ot/OTDefines.h" -#import "keychain/ckks/CKKSReachabilityTracker.h" -#import - -#import "keychain/ckks/CKKSZoneModifier.h" - - -NS_ASSUME_NONNULL_BEGIN - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordBottle = @"bottle"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordEncodedRecord = @"encodedRecord"; - -/* Octagon Table Names */ -static NSString* const contextTable = @"context"; -static NSString* const peerTable = @"peer"; -static NSString* const bottledPeerTable = @"bp"; - -/* Octagon Trust Schemas */ -static NSString* const octagonZoneName = @"OctagonTrustZone"; - -/* Octagon Cloud Kit defines */ -static NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* OTCKRecordName = @"bp-"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTCloudStore () -@property (nonatomic, strong) NSString* dsid; -@property (nonatomic, strong) NSString* containerName; -@property (nonatomic, strong) CKModifyRecordsOperation* modifyRecordsOperation; -@property (nonatomic, strong) CKDatabaseOperation* fetchRecordZoneChangesOperation; -@property (nonatomic, strong) NSOperationQueue *operationQueue; -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) CKKSResultOperation* viewSetupOperation; -@property (nonatomic, strong) NSError* error; -@end - -@class OctagonAPSReceiver; - -@interface OTCloudStore() - -@property CKDatabaseOperation* zoneCreationOperation; -@property CKDatabaseOperation* zoneDeletionOperation; -@property CKDatabaseOperation* zoneSubscriptionOperation; - -@property NSOperation* accountLoggedInDependency; - -@property NSHashTable* accountOperations; -@end - -@implementation OTCloudStore - -- (instancetype) initWithContainer:(CKContainer*) container - zoneName:(NSString*)zoneName - accountTracker:(nullable CKKSAccountStateTracker*)accountTracker - reachabilityTracker:(nullable CKKSReachabilityTracker*)reachabilityTracker - localStore:(OTLocalStore*)localStore - contextID:(NSString*)contextID - dsid:(NSString*)dsid - zoneModifier:(CKKSZoneModifier*)zoneModifier - cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies - operationQueue:(nullable NSOperationQueue *)operationQueue -{ - - self = [super initWithContainer:container - zoneName:zoneName - accountTracker:accountTracker - reachabilityTracker:reachabilityTracker - zoneModifier:zoneModifier - cloudKitClassDependencies:cloudKitClassDependencies]; - - if(self){ - if (!operationQueue) { - operationQueue = [[NSOperationQueue alloc] init]; - } - _contextID = [contextID copy]; - _localStore = localStore; - _containerName = OTCKContainerName; - _dsid = [dsid copy]; - _operationQueue = operationQueue; - self.queue = dispatch_queue_create([[NSString stringWithFormat:@"OctagonTrustQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL); - [self beginCloudKitOperation]; - } - return self; - -} - --(CKKSResultOperation*) otFetchAndProcessUpdates -{ - CKKSResultOperation* fetchOp = [CKKSResultOperation named:@"fetch-and-process-updates-watcher" withBlock:^{}]; - - __weak __typeof(self) weakSelf = self; - - [self dispatchSync: ^bool{ - - OTCloudStoreState* state = [OTCloudStoreState state: self.zoneName]; - - CKFetchRecordZoneChangesConfiguration* options = [[CKFetchRecordZoneChangesConfiguration alloc] init]; - options.previousServerChangeToken = state.changeToken; - - self.fetchRecordZoneChangesOperation = [[[self.cloudKitClassDependencies.fetchRecordZoneChangesOperationClass class] alloc] initWithRecordZoneIDs:@[self.zoneID] configurationsByRecordZoneID:@{self.zoneID : options}]; - - self.fetchRecordZoneChangesOperation.recordChangedBlock = ^(CKRecord *record) { - secinfo("octagon", "CloudKit notification: record changed(%@): %@", [record recordType], record); - __strong __typeof(weakSelf) strongSelf = weakSelf; - - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - fetchOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - - return; - } - if ([record.recordType isEqualToString:OTCKRecordBottledPeerType]) { - NSError* localError = nil; - - //write to localStore - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.bottle = record[OTCKRecordBottle]; - rec.spID = record[OTCKRecordSPID]; - rec.escrowRecordID = record[OTCKRecordEscrowRecordID]; - rec.escrowedSigningSPKI = record[OTCKRecordEscrowSigningSPKI]; - rec.peerSigningSPKI = record[OTCKRecordPeerSigningSPKI]; - rec.signatureUsingEscrowKey = record[OTCKRecordSignatureFromEscrow]; - rec.signatureUsingPeerKey = record[OTCKRecordSignatureFromPeerKey]; - rec.encodedRecord = [strongSelf recordToData:record]; - rec.launched = @"YES"; - BOOL result = [strongSelf.localStore insertBottledPeerRecord:rec escrowRecordID:record[OTCKRecordEscrowRecordID] error:&localError]; - if(!result || localError){ - secerror("Could not write bottled peer record:%@ to database: %@", record.recordID.recordName, localError); - fetchOp.error = localError; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - - } - secnotice("octagon", "fetched changes: %@", record); - } - }; - - self.fetchRecordZoneChangesOperation.recordWithIDWasDeletedBlock = ^(CKRecordID *RecordID, NSString *recordType) { - secinfo("octagon", "CloudKit notification: deleted record(%@): %@", recordType, RecordID); - }; - - self.fetchRecordZoneChangesOperation.recordZoneChangeTokensUpdatedBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - NSError* error = nil; - OTCloudStoreState* state = [OTCloudStoreState state: strongSelf.zoneName]; - secdebug("octagon", "Received a new server change token: %@ %@", serverChangeToken, clientChangeTokenData); - state.changeToken = serverChangeToken; - - if(error) { - secerror("octagon: Couldn't save new server change token: %@", error); - fetchOp.error = error; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - }; - - // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. - NSBlockOperation* recordZoneChangesCompletedOperation = [[NSBlockOperation alloc] init]; - self.fetchRecordZoneChangesOperation.recordZoneFetchCompletionBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, BOOL moreComing, NSError * recordZoneError) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - return; - } - if(recordZoneError) { - secerror("octagon: FetchRecordZoneChanges(%@) error: %@", strongSelf.zoneName, recordZoneError); - fetchOp.error = recordZoneError; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - - // TODO: fetch state here - if(serverChangeToken) { - NSError* error = nil; - secdebug("octagon", "Zone change fetch complete: received a new server change token: %@ %@", serverChangeToken, clientChangeTokenData); - state.changeToken = serverChangeToken; - if(error) { - secerror("octagon: Couldn't save new server change token: %@", error); - fetchOp.error = error; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - } - secdebug("octagon", "Record zone fetch complete: changeToken=%@ error=%@", serverChangeToken, recordZoneError); - - [strongSelf.operationQueue addOperation: recordZoneChangesCompletedOperation]; - [strongSelf.operationQueue addOperation: fetchOp]; - - }; - self.fetchRecordZoneChangesOperation.fetchRecordZoneChangesCompletionBlock = ^(NSError * _Nullable operationError) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - fetchOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - return; - } - secnotice("octagon", "Record zone changes fetch complete: error=%@", operationError); - }; - return true; - }]; - [self.database addOperation: self.fetchRecordZoneChangesOperation]; - - return fetchOp; -} - - -- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification -{ - secnotice("octagon", "received notify zone change. notification: %@", notification); - - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to fetch changes error:%@", op.error); - } - else{ - secnotice("octagon", "downloaded bottled peer records"); - } -} - --(BOOL) downloadBottledPeerRecord:(NSError**)error -{ - secnotice("octagon", "downloadBottledPeerRecord"); - BOOL result = NO; - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to fetch changes error:%@", op.error); - if(error){ - *error = op.error; - } - } - else{ - result = YES; - secnotice("octagon", "downloaded bottled peer records"); - } - return result; -} - -- (nullable NSArray*) retrieveListOfEligibleEscrowRecordIDs:(NSError**)error -{ - NSError* localError = nil; - - NSMutableArray* recordIDs = [NSMutableArray array]; - - //fetch any recent changes first before gathering escrow record ids - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit fetch"); - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secnotice("octagon", "failed to fetch changes error:%@", op.error); - } - - secnotice("octagon", "checking local store for bottles"); - - //check localstore for bottles - NSArray* localStoreBottledPeerRecords = [self.localStore readAllLocalBottledPeerRecords:&localError]; - if(!localStoreBottledPeerRecords) - { - secerror("octagon: local store contains no bottled peer entries: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - for(OTBottledPeerRecord* entry in localStoreBottledPeerRecords){ - NSString* escrowID = entry.escrowRecordID; - if(escrowID && ![recordIDs containsObject:escrowID]){ - [recordIDs addObject:escrowID]; - } - } - - return recordIDs; -} - --(CKRecord*) dataToRecord:(NSData*)encodedRecord -{ - NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedRecord error:nil]; - CKRecord* record = [[CKRecord alloc] initWithCoder:coder]; - [coder finishDecoding]; - return record; -} - --(NSData*) recordToData:(CKRecord*)record -{ - NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES]; - [record encodeWithCoder:archiver]; - [archiver finishEncoding]; - - return archiver.encodedData; -} - --( CKRecord* _Nullable ) CKRecordFromMirror:(CKRecordID*)recordID bpRecord:(OTBottledPeerRecord*)bprecord escrowRecordID:(NSString*)escrowRecordID error:(NSError**)error -{ - CKRecord* record = nil; - - OTBottledPeerRecord* recordFromDB = [self.localStore readLocalBottledPeerRecordWithRecordID:recordID.recordName error:error]; - if(recordFromDB && recordFromDB.encodedRecord != nil){ - record = [self dataToRecord:recordFromDB.encodedRecord]; - } - else{ - record = [[CKRecord alloc] initWithRecordType:OTCKRecordBottledPeerType recordID:recordID]; - } - - if(record == nil){ - secerror("octagon: failed to create cloud kit record"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"failed to create cloud kit record"}]; - } - return nil; - } - record[OTCKRecordPeerID] = bprecord.peerID; - record[OTCKRecordSPID] = bprecord.spID; - record[OTCKRecordEscrowSigningSPKI] = bprecord.escrowedSigningSPKI; - record[OTCKRecordPeerSigningSPKI] = bprecord.peerSigningSPKI; - record[OTCKRecordEscrowRecordID] = escrowRecordID; - record[OTCKRecordBottle] = bprecord.bottle; - record[OTCKRecordSignatureFromEscrow] = bprecord.signatureUsingEscrowKey; - record[OTCKRecordSignatureFromPeerKey] = bprecord.signatureUsingPeerKey; - - return record; -} - --(CKKSResultOperation*) modifyRecords:(NSArray*) recordsToSave deleteRecordIDs:(NSArray*) recordIDsToDelete -{ - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* modifyOp = [CKKSResultOperation named:@"modify-records-watcher" withBlock:^{}]; - - [self dispatchSync: ^bool{ - self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:recordIDsToDelete]; - - self.modifyRecordsOperation.atomic = YES; - self.modifyRecordsOperation.longLived = NO; // The keys are only in memory; mark this explicitly not long-lived - - // Currently done during buddy. User is waiting. - self.modifyRecordsOperation.configuration.automaticallyRetryNetworkFailures = NO; - self.modifyRecordsOperation.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary; - self.modifyRecordsOperation.configuration.isCloudKitSupportOperation = YES; - - self.modifyRecordsOperation.savePolicy = CKRecordSaveIfServerRecordUnchanged; - - self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { - // These should all fail or succeed as one. Do the hard work in the records completion block. - if(!error) { - secnotice("octagon", "Successfully completed upload for %@", record.recordID.recordName); - - } else { - secerror("octagon: error on row: %@ %@", record.recordID.recordName, error); - modifyOp.error = error; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - [weakSelf.operationQueue addOperation:modifyOp]; - } - }; - self.modifyRecordsOperation.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *error) { - secnotice("octagon", "Completed trust update"); - __strong __typeof(weakSelf) strongSelf = weakSelf; - - if(error){ - modifyOp.error = error; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - secerror("octagon: received error from cloudkit: %@", error); - if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorPartialFailure)) { - NSMutableDictionary* failedRecords = error.userInfo[CKPartialErrorsByItemIDKey]; - ckksnotice("octagon", strongSelf, "failed records %@", failedRecords); - } - return; - } - if(!strongSelf) { - secerror("octagon: received callback for released object"); - modifyOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - [strongSelf.operationQueue addOperation:modifyOp]; - return; - } - - if(savedRecords && [savedRecords count] > 0){ - for(CKRecord* record in savedRecords){ - NSError* localError = nil; - secnotice("octagon", "saving recordID: %@ changeToken:%@", record.recordID.recordName, record.recordChangeTag); - - //write to localStore - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.bottle = record[OTCKRecordBottle]; - rec.spID = record[OTCKRecordSPID]; - rec.escrowRecordID = record[OTCKRecordEscrowRecordID]; - rec.signatureUsingEscrowKey = record[OTCKRecordSignatureFromEscrow]; - rec.signatureUsingPeerKey = record[OTCKRecordSignatureFromPeerKey]; - rec.encodedRecord = [strongSelf recordToData:record]; - rec.launched = @"YES"; - rec.escrowedSigningSPKI = record[OTCKRecordEscrowSigningSPKI]; - rec.peerSigningSPKI = record[OTCKRecordPeerSigningSPKI]; - - BOOL result = [strongSelf.localStore insertBottledPeerRecord:rec escrowRecordID:record[OTCKRecordEscrowRecordID] error:&localError]; - - if(!result || localError){ - secerror("Could not write bottled peer record:%@ to database: %@", record.recordID.recordName, localError); - } - - if(localError){ - secerror("octagon: could not save to database: %@", localError); - modifyOp.error = localError; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - } - } - } - else if(deletedRecordIDs && [deletedRecordIDs count] >0){ - for(CKRecordID* recordID in deletedRecordIDs){ - secnotice("octagon", "removed recordID: %@", recordID); - NSError* localError = nil; - BOOL result = [strongSelf.localStore deleteBottledPeer:recordID.recordName error:&localError]; - if(!result){ - secerror("octagon: could not remove record id: %@, error:%@", recordID, localError); - modifyOp.error = localError; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - } - } - } - [strongSelf.operationQueue addOperation:modifyOp]; - }; - return true; - }]; - - [self.database addOperation: self.modifyRecordsOperation]; - return modifyOp; -} - -- (BOOL) uploadBottledPeerRecord:(OTBottledPeerRecord *)bprecord - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error -{ - secnotice("octagon", "sending bottled peer to cloudkit"); - BOOL result = YES; - - CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:bprecord.recordName zoneID:self.zoneID]; - CKRecord *record = [self CKRecordFromMirror:recordID bpRecord:bprecord escrowRecordID:escrowRecordID error:error]; - - if(!record){ - return NO; - } - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-modify-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit ModifyRecords"); - [op addSuccessDependency: [self modifyRecords:@[ record ] deleteRecordIDs:@[]]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to commit record changes error:%@", op.error); - if(error){ - *error = op.error; - } - return NO; - } - secnotice("octagon", "successfully uploaded record: %@", bprecord.recordName); - return result; -} - --(BOOL) removeBottledPeerRecordID:(CKRecordID*)recordID error:(NSError**)error -{ - secnotice("octagon", "removing bottled peer from cloudkit"); - BOOL result = YES; - - NSMutableArray* recordIDsToRemove = [[NSMutableArray alloc] init]; - [recordIDsToRemove addObject:recordID]; - - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-modify-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit ModifyRecords"); - [op addSuccessDependency: [self modifyRecords:[NSMutableArray array] deleteRecordIDs:recordIDsToRemove]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: ailed to commit record changes error:%@", op.error); - if(error){ - *error = op.error; - } - return NO; - } - - return result; -} - -- (void)_onqueueHandleCKLogin { - if(!SecCKKSIsEnabled()) { - ckksnotice("ckks", self, "Skipping CloudKit initialization due to disabled CKKS"); - return; - } - - dispatch_assert_queue(self.queue); - - __weak __typeof(self) weakSelf = self; - - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - [self handleCKLogin:ckse.ckzonecreated zoneSubscribed:ckse.ckzonesubscribed]; - - self.viewSetupOperation = [CKKSResultOperation operationWithBlock: ^{ - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - ckkserror("ckks", strongSelf, "received callback for released object"); - return; - } - - __block bool quit = false; - - [strongSelf dispatchSync: ^bool { - ckksnotice("octagon", strongSelf, "Zone setup progress: %@ %d %@ %d %@", - [CKKSAccountStateTracker stringFromAccountStatus:strongSelf.accountStatus], - strongSelf.zoneCreated, strongSelf.zoneCreatedError, strongSelf.zoneSubscribed, strongSelf.zoneSubscribedError); - - NSError* error = nil; - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: strongSelf.zoneName]; - ckse.ckzonecreated = strongSelf.zoneCreated; - ckse.ckzonesubscribed = strongSelf.zoneSubscribed; - - // Although, if the zone subscribed error says there's no zone, mark down that there's no zone - if(strongSelf.zoneSubscribedError && - [strongSelf.zoneSubscribedError.domain isEqualToString:CKErrorDomain] && strongSelf.zoneSubscribedError.code == CKErrorPartialFailure) { - NSError* subscriptionError = strongSelf.zoneSubscribedError.userInfo[CKPartialErrorsByItemIDKey][strongSelf.zoneID]; - if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) { - - ckkserror("octagon", strongSelf, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", strongSelf.zoneSubscribedError); - ckse.ckzonecreated = false; - } - } - - [ckse saveToDatabase: &error]; - if(error) { - ckkserror("octagon", strongSelf, "couldn't save zone creation status for %@: %@", strongSelf.zoneName, error); - } - - if(!strongSelf.zoneCreated || !strongSelf.zoneSubscribed || strongSelf.accountStatus != CKAccountStatusAvailable) { - // Something has gone very wrong. Error out and maybe retry. - quit = true; - - // Note that CKKSZone has probably called [handleLogout]; which means we have a key hierarchy reset queued up. Error here anyway. - NSError* realReason = strongSelf.zoneCreatedError ? strongSelf.zoneCreatedError : strongSelf.zoneSubscribedError; - strongSelf.viewSetupOperation.error = realReason; - - - return true; - } - - return true; - }]; - - if(quit) { - ckkserror("octagon", strongSelf, "Quitting setup."); - return; - } - }]; - self.viewSetupOperation.name = @"zone-setup"; - - [self.viewSetupOperation addNullableDependency: self.zoneSetupOperation]; - [self scheduleAccountStatusOperation: self.viewSetupOperation]; -} - -- (void)handleCKLogin -{ - ckksinfo("octagon", self, "received a notification of CK login"); - - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* login = [CKKSResultOperation named:@"octagon-login" withBlock:^{ - __strong __typeof(self) strongSelf = weakSelf; - - [strongSelf dispatchSync:^bool{ - strongSelf.accountStatus = CKKSAccountStatusAvailable; - [strongSelf _onqueueHandleCKLogin]; - return true; - }]; - }]; - - [self scheduleAccountStatusOperation:login]; -} - -- (bool)_onqueueResetLocalData: (NSError * __autoreleasing *) error { - dispatch_assert_queue(self.queue); - - NSError* localerror = nil; - bool setError = false; - - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - ckse.ckzonecreated = false; - ckse.ckzonesubscribed = false; - ckse.changeToken = NULL; - [ckse saveToDatabase: &localerror]; - if(localerror) { - ckkserror("ckks", self, "couldn't reset zone status for %@: %@", self.zoneName, localerror); - if(error && !setError) { - *error = localerror; setError = true; - } - } - - BOOL result = [_localStore removeAllBottledPeerRecords:&localerror]; - if(!result){ - *error = localerror; - secerror("octagon: failed to move all bottled peer entries for context: %@ error: %@", self.contextID, localerror); - } - return (localerror == nil && !setError); -} - --(CKKSResultOperation*) resetOctagonTrustZone:(NSError**)error -{ - // On a reset, we should cancel all existing operations - [self cancelAllOperations]; - CKKSResultOperation* reset = [super deleteCloudKitZoneOperation:nil]; - [self scheduleOperationWithoutDependencies:reset]; - - __weak __typeof(self) weakSelf = self; - CKKSGroupOperation* resetFollowUp = [[CKKSGroupOperation alloc] init]; - resetFollowUp.name = @"cloudkit-reset-follow-up-group"; - - [resetFollowUp runBeforeGroupFinished: [CKKSResultOperation named:@"cloudkit-reset-follow-up" withBlock: ^{ - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - ckkserror("octagon", strongSelf, "received callback for released object"); - return; - } - - if(!reset.error) { - ckksnotice("octagon", strongSelf, "Successfully deleted zone %@", strongSelf.zoneName); - __block NSError* error = nil; - - [strongSelf dispatchSync: ^bool{ - [strongSelf _onqueueResetLocalData: &error]; - return true; - }]; - } else { - // Shouldn't ever happen, since reset is a successDependency - ckkserror("ckks", strongSelf, "Couldn't reset zone %@: %@", strongSelf.zoneName, reset.error); - } - }]]; - - [resetFollowUp addSuccessDependency:reset]; - [self scheduleOperationWithoutDependencies:resetFollowUp]; - - return reset; -} - --(BOOL) performReset:(NSError**)error -{ - BOOL result = NO; - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-reset-zones-waiter" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit reset for Octagon Trust"); - [op addSuccessDependency:[self resetOctagonTrustZone:error]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(!op.error) { - secnotice("octagon", "Completed rpcResetCloudKit"); - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* login = [CKKSResultOperation named:@"octagon-login" withBlock:^{ - __strong __typeof(self) strongSelf = weakSelf; - - [strongSelf dispatchSync:^bool{ - strongSelf.accountStatus = CKKSAccountStatusAvailable; - [strongSelf handleCKLogin:false zoneSubscribed:false]; - return true; - }]; - }]; - - [self.operationQueue addOperation:login]; - result = YES; - } else { - secnotice("octagon", "Completed rpcResetCloudKit with error: %@", op.error); - if(error){ - *error = op.error; - } - } - - return result; -} - -@end - -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTCloudStoreState.h b/keychain/ot/OTCloudStoreState.h deleted file mode 100644 index 915a3200..00000000 --- a/keychain/ot/OTCloudStoreState.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef OTCloudStoreState_h -#define OTCloudStoreState_h - -#if OCTAGON -#import "keychain/ckks/CKKSSQLDatabaseObject.h" - -@interface OTCloudStoreState : CKKSSQLDatabaseObject - -@property NSString* ckzone; -@property bool ckzonecreated; -@property bool ckzonesubscribed; -@property (getter=getChangeToken, setter=setChangeToken:) CKServerChangeToken* changeToken; -@property NSData* encodedChangeToken; -@property NSDate* lastFetchTime; - -+ (instancetype)state:(NSString*)ckzone; - -+ (instancetype)fromDatabase:(NSString*)ckzone error:(NSError* __autoreleasing*)error; -+ (instancetype)tryFromDatabase:(NSString*)ckzone error:(NSError* __autoreleasing*)error; - -- (instancetype)initWithCKZone:(NSString*)ckzone - zoneCreated:(bool)ckzonecreated - zoneSubscribed:(bool)ckzonesubscribed - changeToken:(NSData*)changetoken - lastFetch:(NSDate*)lastFetch; - -- (CKServerChangeToken*)getChangeToken; -- (void)setChangeToken:(CKServerChangeToken*)token; - -- (BOOL)isEqual:(id)object; -@end - -#endif -#endif /* OTCloudStoreState_h */ diff --git a/keychain/ot/OTCloudStoreState.m b/keychain/ot/OTCloudStoreState.m deleted file mode 100644 index 63b3ab74..00000000 --- a/keychain/ot/OTCloudStoreState.m +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include - -#import -#import - -#import "CKKSKeychainView.h" - -#include -#include -#include - -#if OCTAGON - -#import -#import "OTCloudStoreState.h" - -@implementation OTCloudStoreState - -- (instancetype)initWithCKZone:(NSString*)ckzone - zoneCreated:(bool)ckzonecreated - zoneSubscribed:(bool)ckzonesubscribed - changeToken:(NSData*)changetoken - lastFetch:(NSDate*)lastFetch -{ - if(self = [super init]) { - _ckzone = [ckzone copy]; - _ckzonecreated = ckzonecreated; - _ckzonesubscribed = ckzonesubscribed; - _encodedChangeToken = [changetoken copy]; - _lastFetchTime = [lastFetch copy]; - } - return self; -} - -- (BOOL)isEqual: (id) object { - if(![object isKindOfClass:[OTCloudStoreState class]]) { - return NO; - } - - OTCloudStoreState* obj = (OTCloudStoreState*) object; - - return ([self.ckzone isEqualToString: obj.ckzone] && - self.ckzonecreated == obj.ckzonecreated && - self.ckzonesubscribed == obj.ckzonesubscribed && - ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) && - ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) && - true) ? YES : NO; -} - -+ (instancetype) state: (NSString*) ckzone { - NSError* error = nil; - OTCloudStoreState* ret = [OTCloudStoreState tryFromDatabase:ckzone error:&error]; - - if(error) { - secerror("octagon: error fetching CKState(%@): %@", ckzone, error); - } - - if(!ret) { - ret = [[OTCloudStoreState alloc] initWithCKZone:ckzone - zoneCreated:false - zoneSubscribed:false - changeToken:nil - lastFetch:nil]; - } - return ret; -} - -- (CKServerChangeToken*) getChangeToken { - if(self.encodedChangeToken) { - NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.encodedChangeToken error:nil]; - return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey]; - } else { - return nil; - } -} - -- (void)setChangeToken: (CKServerChangeToken*) token { - self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil] : nil; -} - -#pragma mark - Database Operations - -+ (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { - return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; -} - -+ (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { - return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; -} - -#pragma mark - CKKSSQLDatabaseObject methods - -+ (NSString*) sqlTable { - return @"ckstate"; -} - -+ (NSArray*) sqlColumns { - return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup"]; -} - -- (NSDictionary*) whereClauseToFindSelf { - return @{@"ckzone": self.ckzone}; -} - -- (NSDictionary*) sqlValues { - NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; - - return @{@"ckzone": self.ckzone, - @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated], - @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed], - @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]), - @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil), - }; -} - -+ (instancetype)fromDatabaseRow:(NSDictionary*)row { - return [[OTCloudStoreState alloc] initWithCKZone:row[@"ckzone"].asString - zoneCreated:row[@"ckzonecreated"].asBOOL - zoneSubscribed:row[@"ckzonesubscribed"].asBOOL - changeToken:row[@"changetoken"].asBase64DecodedData - lastFetch:row[@"lastfetch"].asISO8601Date - ]; -} - -@end - -#endif //OTCloudStoreState - diff --git a/keychain/ot/OTConstants.h b/keychain/ot/OTConstants.h index 3518f397..1b7ba2d2 100644 --- a/keychain/ot/OTConstants.h +++ b/keychain/ot/OTConstants.h @@ -61,6 +61,19 @@ void OctagonRecoveryKeySetIsEnabled(BOOL value); BOOL OctagonAuthoritativeTrustIsEnabled(void); void OctagonAuthoritativeTrustSetIsEnabled(BOOL value); +BOOL OctagonIsSOSFeatureEnabled(void); +void OctagonSetSOSFeatureEnabled(BOOL value); + +typedef NS_ENUM(NSInteger, CuttlefishResetReason) { + CuttlefishResetReasonUnknown = 0, + CuttlefishResetReasonUserInitiatedReset = 1, + CuttlefishResetReasonHealthCheck = 2, + CuttlefishResetReasonNoBottleDuringEscrowRecovery = 3, + CuttlefishResetReasonLegacyJoinCircle = 4, + CuttlefishResetReasonRecoveryKey = 5, + CuttlefishResetReasonTestGenerated = 6, +}; + #endif // __OBJC__ #endif /* OTConstants_h */ diff --git a/keychain/ot/OTConstants.m b/keychain/ot/OTConstants.m index 4368cc5c..9fbf29a3 100644 --- a/keychain/ot/OTConstants.m +++ b/keychain/ot/OTConstants.m @@ -55,6 +55,9 @@ static bool OctagonRecoveryKeyEnabledOverride = false; static bool OctagonAuthoritativeTrustEnabledOverrideSet = false; static bool OctagonAuthoritativeTrustEnabledOverride = false; +static bool OctagonSOSFeatureIsEnabledOverrideSet = false; +static bool OctagonSOSFeatureIsEnabledOverride = false; + bool OctagonIsEnabled(void) { if(OctagonEnabledOverrideSet) { @@ -183,3 +186,26 @@ void OctagonAuthoritativeTrustSetIsEnabled(BOOL value) OctagonAuthoritativeTrustEnabledOverrideSet = true; OctagonAuthoritativeTrustEnabledOverride = value; } + +BOOL OctagonIsSOSFeatureEnabled(void) +{ + if(OctagonSOSFeatureIsEnabledOverrideSet) { + secnotice("octagon", "SOS Feature is %@ (overridden)", OctagonSOSFeatureIsEnabledOverride ? @"enabled" : @"disabled"); + return OctagonSOSFeatureIsEnabledOverrideSet; + } + + static bool sosEnabled = true; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sosEnabled = os_feature_enabled(Security, EnableSecureObjectSync); + secnotice("octagon", "SOS Feature is %@ (via feature flags)", sosEnabled ? @"enabled" : @"disabled"); + }); + + return sosEnabled; +} + +void OctagonSetSOSFeatureEnabled(BOOL value) +{ + OctagonSOSFeatureIsEnabledOverrideSet = true; + OctagonSOSFeatureIsEnabledOverride = value; +} diff --git a/keychain/ot/OTContext.h b/keychain/ot/OTContext.h deleted file mode 100644 index 3f75b375..00000000 --- a/keychain/ot/OTContext.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import -#import "OTLocalStore.h" -#import "OTCloudStore.h" -#import "OTEscrowKeys.h" -#import "OTIdentity.h" -#import "OTBottledPeer.h" -#import "OTBottledPeerSigned.h" -#import "OTRamping.h" -#import "OTDefines.h" -#import "OTPreflightInfo.h" -#import "keychain/ckks/CKKSLockStateTracker.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol OTContextIdentityProvider -- (nullable OTIdentity *) currentIdentity:(NSError**) error; -@end - - -@interface OTContext : NSObject - -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) OTCloudStore* cloudStore; - -@property (nonatomic, readonly) CKKSLockStateTracker* lockStateTracker; -@property (nonatomic, readonly) CKKSAccountStateTracker* accountTracker; -@property (nonatomic, readonly) CKKSReachabilityTracker *reachabilityTracker; - -- (nullable instancetype) initWithContextID:(NSString*)contextID - dsid:(NSString*)dsid - localStore:(OTLocalStore*)localStore - cloudStore:(nullable OTCloudStore*)cloudStore - identityProvider:(id )identityProvider - error:(NSError**)error; - -- (nullable OTBottledPeerSigned *) restoreFromEscrowRecordID:(NSString*)escrowRecordID - secret:(NSData*)secret - error:(NSError**)error; - -- (NSData* _Nullable) makeMeSomeEntropy:(int)requiredLength; -- (nullable OTPreflightInfo*) preflightBottledPeer:(NSString*)contextID - entropy:(NSData*)entropy - error:(NSError**)error; -- (BOOL)scrubBottledPeer:(NSString*)contextID - bottleID:(NSString*)bottleID - error:(NSError**)error; - --(BOOL)updateAllBottlesForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)newSigningKey - newEncryptionKey:(SFECKeyPair*)newEncryptionKey - error:(NSError**)error; - --(OctagonBottleCheckState)doesThisDeviceHaveABottle:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTContext.m b/keychain/ot/OTContext.m deleted file mode 100644 index ee9a3ed0..00000000 --- a/keychain/ot/OTContext.m +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import "OTContext.h" -#import - -#import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTDefines.h" - -#include -#include - -#import "keychain/ckks/CKKS.h" -#import "keychain/ckks/CKKSViewManager.h" -#import "keychain/ckks/CKKSAnalytics.h" - -#import - -NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* const kOTRampZoneName = @"metadata_zone"; - -@interface OTContext (lockstateTracker) -@end - -@interface OTContext () - -@property (nonatomic, strong) NSString* contextID; -@property (nonatomic, strong) NSString* contextName; -@property (nonatomic, strong) NSString* dsid; - -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) OTCloudStore* cloudStore; -@property (nonatomic, strong) NSData* changeToken; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSDate* egoPeerCreationDate; -@property (nonatomic, strong) dispatch_queue_t queue; -@property (nonatomic, weak) id identityProvider; - -@property (nonatomic, strong) CKKSAccountStateTracker* accountTracker; -@property (nonatomic, strong) CKKSLockStateTracker* lockStateTracker; -@property (nonatomic, strong) CKKSReachabilityTracker *reachabilityTracker; - -@end - -@implementation OTContext - --(CKContainer*)makeCKContainer:(NSString*)containerName { - CKContainer* container = [CKContainer containerWithIdentifier:containerName]; - container = [[CKContainer alloc] initWithContainerID: container.containerID]; - return container; -} - --(BOOL) isPrequeliteEnabled -{ - BOOL result = YES; - if([PQLConnection class] == nil) { - secerror("OT: prequelite appears to not be linked. Can't create OT objects."); - result = NO; - } - return result; -} - -- (nullable instancetype) initWithContextID:(NSString*)contextID - dsid:(NSString*)dsid - localStore:(OTLocalStore*)localStore - cloudStore:(nullable OTCloudStore*)cloudStore - identityProvider:(id )identityProvider - error:(NSError**)error -{ - if(![self isPrequeliteEnabled]){ - // We're running in the base build environment, which lacks a bunch of libraries. - // We don't support doing anything in this environment. Bye. - return nil; - } - - self = [super init]; - if (self) { - NSError* localError = nil; - _contextID = contextID; - _dsid = dsid; - _identityProvider = identityProvider; - _localStore = localStore; - - NSString* contextAndDSID = [NSString stringWithFormat:@"%@-%@", contextID, dsid]; - - CKContainer* container = [self makeCKContainer:OTCKContainerName]; - - _accountTracker = [CKKSViewManager manager].accountTracker; - _lockStateTracker = [CKKSViewManager manager].lockStateTracker; - _reachabilityTracker = [CKKSViewManager manager].reachabilityTracker; - - if(!cloudStore) { - _cloudStore = [[OTCloudStore alloc]initWithContainer:container - zoneName:OTCKZoneName - accountTracker:_accountTracker - reachabilityTracker:_reachabilityTracker - localStore:_localStore - contextID:contextID - dsid:dsid - zoneModifier:[CKKSViewManager manager].zoneModifier - cloudKitClassDependencies:[CKKSCloudKitClassDependencies forLiveCloudKit] - operationQueue:nil]; - } else{ - _cloudStore = cloudStore; - } - - OTContextRecord* localContextRecord = [_localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&localError]; - - if(localContextRecord == nil || localContextRecord.contextID == nil){ - localError = nil; - BOOL result = [_localStore initializeContextTable:contextID dsid:dsid error:&localError]; - if(!result || localError != nil){ - secerror("octagon: reading from database failed with error: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - localContextRecord = [_localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&localError]; - if(localContextRecord == nil || localError !=nil){ - secerror("octagon: reading from database failed with error: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - } - - _contextID = localContextRecord.contextID; - _contextName = localContextRecord.contextName; - _changeToken = localContextRecord.changeToken; - _egoPeerID = localContextRecord.egoPeerID; - _egoPeerCreationDate = localContextRecord.egoPeerCreationDate; - - _queue = dispatch_queue_create("com.apple.security.otcontext", DISPATCH_QUEUE_SERIAL); - } - return self; -} - -- (nullable OTBottledPeerSigned *) createBottledPeerRecordForIdentity:(OTIdentity *)identity - secret:(NSData*)secret - error:(NSError**)error -{ - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTEscrowKeys *escrowKeys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:self.dsid error:&localError]; - if (!escrowKeys || localError != nil) { - secerror("octagon: unable to derive escrow keys: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithPeerID:identity.peerID - spID:identity.spID - peerSigningKey:identity.peerSigningKey - peerEncryptionKey:identity.peerEncryptionKey - escrowKeys:escrowKeys - error:&localError]; - if (!bp || localError !=nil) { - secerror("octagon: unable to create a bottled peer: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - return [[OTBottledPeerSigned alloc] initWithBottledPeer:bp - escrowedSigningKey:escrowKeys.signingKey - peerSigningKey:identity.peerSigningKey - error:error]; -} - -- (NSData* _Nullable) makeMeSomeEntropy:(int)requiredLength -{ - NSMutableData* salt = [NSMutableData dataWithLength:requiredLength]; - if (salt == nil){ - return nil; - } - if (SecRandomCopyBytes(kSecRandomDefault, [salt length], [salt mutableBytes]) != 0){ - return nil; - } - return salt; -} - -- (nullable OTPreflightInfo*) preflightBottledPeer:(NSString*)contextID - entropy:(NSData*)entropy - error:(NSError**)error -{ - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTIdentity *identity = [self.identityProvider currentIdentity:&localError]; - if (!identity || localError != nil) { - secerror("octagon: unable to get current identity:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeerSigned* bps = [self createBottledPeerRecordForIdentity:identity - secret:entropy - error:&localError]; - if (!bps || localError != nil) { - secerror("octagon: failed to create bottled peer record: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - secnotice("octagon", "created bottled peer:%@", bps); - - OTBottledPeerRecord *bprec = [bps asRecord:identity.spID]; - - if (!identity.spID) { - secerror("octagon: cannot enroll without a spID"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorNoIdentity userInfo:@{NSLocalizedDescriptionKey: @"OTIdentity does not have an SOS peer id"}]; - } - return nil; - } - - OTPreflightInfo* info = [[OTPreflightInfo alloc]init]; - info.escrowedSigningSPKI = bprec.escrowedSigningSPKI; - - if(!info.escrowedSigningSPKI){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEscrowSigningSPKI userInfo:@{NSLocalizedDescriptionKey: @"Escrowed spinging SPKI is nil"}]; - } - secerror("octagon: Escrowed spinging SPKI is nil"); - return nil; - } - - info.bottleID = bprec.recordName; - if(!info.bottleID){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"BottleID is nil"}]; - } - secerror("octagon: BottleID is nil"); - return nil; - } - - //store record in localStore - BOOL result = [self.localStore insertBottledPeerRecord:bprec escrowRecordID:identity.spID error:&localError]; - if(!result || localError){ - secerror("octagon: could not persist the bottle record: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - return info; -} - -- (BOOL)scrubBottledPeer:(NSString*)contextID - bottleID:(NSString*)bottleID - error:(NSError**)error -{ - secnotice("octagon", "scrubBottledPeer"); - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return YES; - } - - BOOL result = [self.localStore deleteBottledPeer:bottleID error:&localError]; - if(!result || localError != nil){ - secerror("octagon: could not remove record for bottleID %@, error:%@", bottleID, localError); - if (error) { - *error = localError; - } - } - return result; -} - -- (OTBottledPeerSigned *) restoreFromEscrowRecordID:(NSString*)escrowRecordID - secret:(NSData*)secret - error:(NSError**)error -{ - NSError *localError = nil; - - if(self.lockStateTracker.isLocked){ - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTEscrowKeys *escrowKeys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:self.dsid error:&localError]; - if (!escrowKeys || localError != nil) { - secerror("unable to derive escrow keys: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - BOOL result = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(!result || localError){ - secerror("octagon: could not download bottled peer record:%@", localError); - if(error){ - *error = localError; - } - } - NSString* recordName = [OTBottledPeerRecord constructRecordID:escrowRecordID - escrowSigningSPKI:[escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]]; - OTBottledPeerRecord* rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&localError]; - - if (!rec) { - secerror("octagon: could not read bottled peer record:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:escrowKeys - error:&localError]; - if (!bps) { - secerror("octagon: could not unpack bottled peer:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - return bps; -} - --(BOOL)updateBottleForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)signingKey - newEncryptionKey:(SFECKeyPair*)encryptionKey - escrowKeySet:(OTEscrowKeys*)keySet - error:(NSError**)error -{ - NSError* localError = nil; - - //let's rebottle our bottles! - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithPeerID:nil - spID:peerID - peerSigningKey:signingKey - peerEncryptionKey:encryptionKey - escrowKeys:keySet - error:&localError]; - if (!bp || localError !=nil) { - secerror("octagon: unable to create a bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - OTBottledPeerSigned* bpSigned = [[OTBottledPeerSigned alloc] initWithBottledPeer:bp - escrowedSigningKey:keySet.signingKey - peerSigningKey:signingKey - error:&localError]; - if(!bpSigned || localError){ - secerror("octagon: unable to create a signed bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - - OTBottledPeerRecord *newRecord = [bpSigned asRecord:peerID]; - - BOOL uploaded = [self.cloudStore uploadBottledPeerRecord:newRecord escrowRecordID:peerID error:&localError]; - if(!uploaded || localError){ - secerror("octagon: unable to upload bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - - return YES; -} - --(BOOL)updateAllBottlesForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)newSigningKey - newEncryptionKey:(SFECKeyPair*)newEncryptionKey - error:(NSError**)error -{ - BOOL result = NO; - BOOL atLeastOneHasBeenUpdated = NO; - - NSError* localError = nil; - - SFECKeyPair *escrowSigningKey = nil; - SFECKeyPair *escrowEncryptionKey = nil; - SFAESKey *escrowSymmetricKey = nil; - - result = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(!result || localError){ - secnotice("octagon", "could not download bottles from cloudkit: %@", localError); - } - - secnotice("octagon", "checking local store for downloaded bottles"); - - NSArray* bottles = [self.localStore readLocalBottledPeerRecordsWithMatchingPeerID:peerID error:&localError]; - if(!bottles || localError){ - secnotice("octagon", "peer %@ enrolled 0 bottles", peerID); - if (error) { - *error = localError; - } - return result; - } - - //iterate through all the bottles and attempt to update all the bottles - for(OTBottledPeerRecord* bottle in bottles){ - - NSString* escrowSigningPubKeyHash = [OTEscrowKeys hashEscrowedSigningPublicKey:bottle.escrowedSigningSPKI]; - - BOOL foundKeys = [OTEscrowKeys findEscrowKeysForLabel:escrowSigningPubKeyHash - foundSigningKey:&escrowSigningKey - foundEncryptionKey:&escrowEncryptionKey - foundSymmetricKey:&escrowSymmetricKey - error:&localError]; - if(!foundKeys){ - secnotice("octagon", "found 0 persisted escrow keys for label: %@", escrowSigningPubKeyHash); - continue; - } - - OTEscrowKeys *retrievedKeySet = [[OTEscrowKeys alloc]initWithSigningKey:escrowSigningKey encryptionKey:escrowEncryptionKey symmetricKey:escrowSymmetricKey]; - - if(!retrievedKeySet){ - secnotice("octagon", "failed to create escrow keys"); - continue; - } - - BOOL updated = [self updateBottleForPeerID:peerID newSigningKey:newSigningKey newEncryptionKey:newEncryptionKey escrowKeySet:retrievedKeySet error:&localError]; - - if(!updated || localError){ - secnotice("octagon", "could not updated bottle for peerid: %@ for escrowed signing public key hash: %@", peerID, escrowSigningPubKeyHash); - }else{ - atLeastOneHasBeenUpdated = YES; - } - } - - if(!atLeastOneHasBeenUpdated){ - secerror("octagon: no bottles were updated for : %@", peerID); - result = NO; - - localError = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleUpdate userInfo:@{NSLocalizedDescriptionKey: @"bottle update failed, 0 bottles updated."}]; - if(error){ - *error = localError; - } - }else{ - result = YES; - secnotice("octagon", "bottles were updated for : %@", peerID); - } - return result; -} - --(BOOL)bottleExistsLocallyForIdentity:(OTIdentity*)identity - error:(NSError**)error -{ - NSError* localError = nil; - //read all the local bp records - NSArray* bottles = [self.localStore readLocalBottledPeerRecordsWithMatchingPeerID:identity.spID error:&localError]; - if(!bottles || [bottles count] == 0 || localError != nil){ - secerror("octagon: there are no eligible bottle peer records: %@", localError); - if(error){ - *error = localError; - } - return NO; - } - - BOOL hasBottle = NO; - //if check all the records if the peer signing public key matches the bottled one! - for(OTBottledPeerRecord* bottle in bottles){ - NSData* bottledSigningSPKIData = [[SFECPublicKey keyWithSubjectPublicKeyInfo:bottle.peerSigningSPKI] keyData]; - NSData* currentIdentitySPKIData = [identity.peerSigningKey.publicKey keyData]; - - //spIDs are the same AND check bottle signature - if([currentIdentitySPKIData isEqualToData:bottledSigningSPKIData] && - [OTBottledPeerSigned verifyBottleSignature:bottle.bottle - signature:bottle.signatureUsingPeerKey - key:identity.peerSigningKey.publicKey - error:error]){ - hasBottle = YES; - } - } - - - - return hasBottle; -} - --(BOOL)queryCloudKitForBottle:(OTIdentity*)identity - error:(NSError**)error -{ - NSError* localError = nil; - BOOL hasBottle = NO; - //attempt to pull down all the records, but continue checking local store even if this fails. - BOOL fetched = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(fetched == NO || localError != nil){ //couldn't download bottles - secerror("octagon: 0 bottled peers downloaded: %@", localError); - if(error){ - *error = localError; - } - return NO; - }else{ //downloaded bottles, let's check local store - hasBottle = [self bottleExistsLocallyForIdentity:identity error:&localError]; - } - - if(error){ - *error = localError; - } - return hasBottle; -} - --(OctagonBottleCheckState) doesThisDeviceHaveABottle:(NSError**)error -{ - secnotice("octagon", "checking if device has enrolled a bottle"); - - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device locked, not checking for bottle"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return UNCLEAR; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - - if(self.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"iCloud account is logged out"}]; - } - secnotice("octagon", "not logged into an account"); - return UNCLEAR; - } - - NSError* localError = nil; - OctagonBottleCheckState bottleStatus = NOBOTTLE; - - //get our current identity - OTIdentity* identity = [self.identityProvider currentIdentity:&localError]; - - //if we get the locked error, return true so we don't prompt the user - if(localError && [_lockStateTracker isLockedError:localError]){ - secnotice("octagon", "attempting to perform bottle check while locked: %@", localError); - return UNCLEAR; - } - - if(!identity && localError != nil){ - secerror("octagon: do not have an identity: %@", localError); - if(error){ - *error = localError; - } - return NOBOTTLE; - } - - //check locally first - BOOL bottleExistsLocally = [self bottleExistsLocallyForIdentity:identity error:&localError]; - - //no bottle and we have no network - if(!bottleExistsLocally && !self.reachabilityTracker.currentReachability){ - secnotice("octagon", "no network, can't query"); - localError = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - if(error){ - *error = localError; - } - return UNCLEAR; - } - else if(!bottleExistsLocally){ - if([self queryCloudKitForBottle:identity error:&localError]){ - bottleStatus = BOTTLE; - } - }else if(bottleExistsLocally){ - bottleStatus = BOTTLE; - } - - if(bottleStatus == NOBOTTLE){ - localError = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoBottlePeerRecords - userInfo:@{NSLocalizedDescriptionKey: @"Peer does not have any bottled records"}]; - secerror("octagon: this device does not have any bottled peers: %@", localError); - if(error){ - *error = localError; - } - } - - return bottleStatus; -} - -@end -#endif diff --git a/keychain/ot/OTContextRecord.h b/keychain/ot/OTContextRecord.h deleted file mode 100644 index 48a5f5dc..00000000 --- a/keychain/ot/OTContextRecord.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef OTContextRecord_h -#define OTContextRecord_h - -#if OCTAGON - -#import - -NS_ASSUME_NONNULL_BEGIN - - -@interface OTContextRecord : NSObject - -@property (nonatomic, strong) NSString* contextID; -@property (nonatomic, strong) NSString* dsid; -@property (nonatomic, strong) NSString* contextName; -@property (nonatomic) BOOL zoneCreated; -@property (nonatomic) BOOL subscribedToChanges; -@property (nonatomic, strong) NSData* changeToken; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSDate* egoPeerCreationDate; -@property (nonatomic, strong) NSData* recoverySigningSPKI; -@property (nonatomic, strong) NSData* recoveryEncryptionSPKI; - - --(BOOL)isEqual:(OTContextRecord* _Nullable)record; - -@end - -NS_ASSUME_NONNULL_END - -#endif /* OCTAGON */ -#endif /* OTContextRecord_h */ diff --git a/keychain/ot/OTContextRecord.m b/keychain/ot/OTContextRecord.m deleted file mode 100644 index 09e9e371..00000000 --- a/keychain/ot/OTContextRecord.m +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON -#import "OTContextRecord.h" - -@implementation OTContextRecord - --(BOOL)isEqual:(OTContextRecord*)record -{ - return [self.contextID isEqualToString:record.contextID] && - [self.contextName isEqualToString:record.contextName] && - [self.dsid isEqualToString:record.dsid] && - [self.egoPeerID isEqualToString:record.egoPeerID] && - [self.recoverySigningSPKI isEqual:record.recoverySigningSPKI] && - [self.recoveryEncryptionSPKI isEqual:record.recoveryEncryptionSPKI]; -} -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/OTControl.h b/keychain/ot/OTControl.h index 1adc056c..6e8b48de 100644 --- a/keychain/ot/OTControl.h +++ b/keychain/ot/OTControl.h @@ -58,11 +58,16 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithConnection:(NSXPCConnection*)connection sync:(bool)sync; - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID - reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error))reply; -- (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply; -- (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply; -- (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply; -- (void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply; + reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error))reply + API_DEPRECATED("Use OTClique API", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); - (void)signIn:(NSString*)dsid container:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply; - (void)signOut:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply; @@ -72,7 +77,8 @@ NS_ASSUME_NONNULL_BEGIN ForEncryptionKey:(SFECKeyPair* _Nonnull)encryptionKey ForPeerID:(NSString*)peerID reply:(void (^)(BOOL result, - NSError* _Nullable error))reply; + NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); - (void)rpcEpochWithConfiguration:(OTJoiningConfiguration*)config reply:(void (^)(uint64_t epoch, @@ -155,12 +161,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply; - (void)establish:(NSString* _Nullable)container - context:(NSString*)context - altDSID:(NSString*)altDSID - reply:(void (^)(NSError* _Nullable error))reply; + context:(NSString*)context + altDSID:(NSString*)altDSID + reply:(void (^)(NSError* _Nullable error))reply; - (void)leaveClique:(NSString* _Nullable)container context:(NSString*)context diff --git a/keychain/ot/OTControl.m b/keychain/ot/OTControl.m index adc3df22..ce1d0965 100644 --- a/keychain/ot/OTControl.m +++ b/keychain/ot/OTControl.m @@ -333,11 +333,12 @@ - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply { [[self getConnection: ^(NSError* error) { reply(error); - }] resetAndEstablish:container context:context altDSID:altDSID reply:reply]; + }] resetAndEstablish:container context:context altDSID:altDSID resetReason:resetReason reply:reply]; } - (void)establish:(NSString* _Nullable)container diff --git a/keychain/ot/OTControlProtocol.h b/keychain/ot/OTControlProtocol.h index 458c9595..6af4bbef 100644 --- a/keychain/ot/OTControlProtocol.h +++ b/keychain/ot/OTControlProtocol.h @@ -27,7 +27,7 @@ #define SECURITY_OT_OTCONTROLPROTOCOL_H 1 #import - +#import @class SFECKeyPair; NS_ASSUME_NONNULL_BEGIN @@ -132,6 +132,7 @@ typedef void (^OTNextJoinCompleteBlock)(BOOL finished, NSData* _Nullable message - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply; - (void)establish:(NSString * _Nullable)container diff --git a/keychain/ot/OTControlProtocol.m b/keychain/ot/OTControlProtocol.m index 003f186a..f98ae502 100644 --- a/keychain/ot/OTControlProtocol.m +++ b/keychain/ot/OTControlProtocol.m @@ -66,6 +66,7 @@ NSXPCInterface* OTSetupControlProtocol(NSXPCInterface* interface) { [interface setClasses:errorClasses forSelector:@selector(postCDPFollowupResult:type:error:containerName:contextName:reply:) argumentIndex:2 ofReply:NO]; [interface setClasses:errorClasses forSelector:@selector(postCDPFollowupResult:type:error:containerName:contextName:reply:) argumentIndex:0 ofReply:YES]; [interface setClasses:errorClasses forSelector:@selector(tapToRadar:description:radar:reply:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errorClasses forSelector:@selector(resetAndEstablish:context:altDSID:resetReason:reply:) argumentIndex:0 ofReply:YES]; #if __OBJC2__ diff --git a/keychain/ot/OTCuttlefishContext.h b/keychain/ot/OTCuttlefishContext.h index db45bada..4665950c 100644 --- a/keychain/ot/OTCuttlefishContext.h +++ b/keychain/ot/OTCuttlefishContext.h @@ -48,6 +48,7 @@ #import #import "keychain/ot/OTJoiningConfiguration.h" #import "keychain/ot/OTOperationDependencies.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" #import @@ -62,9 +63,10 @@ NS_ASSUME_NONNULL_BEGIN OTAuthKitAdapterNotifier, OctagonStateMachineEngine, CKKSCloudKitAccountStateListener, - CKKSPeerUpdateListener> + CKKSPeerUpdateListener, + OTDeviceInformationNameUpdateListener> -@property (readonly) id cuttlefishXPCConnection; +@property (readonly) CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property (readonly) OTFollowup *followupHandler; @property (readonly) NSString *containerName; @@ -78,6 +80,7 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) BOOL postedEscrowRepairCFU; @property (readonly) BOOL postedRecoveryKeyCFU; @property (nullable, nonatomic) CKKSNearFutureScheduler* apsRateLimiter; +@property (nullable, nonatomic) CKKSNearFutureScheduler* sosConsistencyRateLimiter; @property (readonly, nullable) CKKSViewManager* viewManager; @@ -104,6 +107,8 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)accountNoLongerAvailable:(NSError**)error; - (BOOL)idmsTrustLevelChanged:(NSError**)error; +- (void)deviceNameUpdated; + - (void)startOctagonStateMachine; - (void)handlePairingRestart:(OTJoiningConfiguration*)config; @@ -120,7 +125,7 @@ NS_ASSUME_NONNULL_BEGIN preapprovedKeys:(NSArray* _Nullable)preapprovedKeys reply:(void (^)(NSError * _Nullable error))reply; -- (void)rpcResetAndEstablish:(nonnull void (^)(NSError * _Nullable))reply; +- (void)rpcResetAndEstablish:(CuttlefishResetReason)resetReason reply:(nonnull void (^)(NSError * _Nullable))reply; - (void)localReset:(nonnull void (^)(NSError * _Nullable))reply; @@ -139,7 +144,7 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys reply:(void (^)(NSError * _Nullable error))reply; - (void)rpcRemoveFriendsInClique:(NSArray*)peerIDs - reply:(void (^)(NSError*))reply; + reply:(void (^)(NSError * _Nullable))reply; - (void)notifyContainerChange:(APSIncomingMessage* _Nullable)notification; - (void)notifyContainerChangeWithUserInfo:(NSDictionary*)userInfo; @@ -171,10 +176,13 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys - (void)attemptSOSUpgrade:(void (^)(NSError* _Nullable error))reply; -- (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply; +- (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply NS_SWIFT_NAME(waitForOctagonUpgrade(reply:)); - (void)clearPendingCFUFlags; +- (BOOL)waitForReady:(int64_t)timeOffset; + + // For testing. - (void)setPostedBool:(BOOL)posted; - (OTAccountMetadataClassC_AccountState)currentMemoizedAccountState; diff --git a/keychain/ot/OTCuttlefishContext.m b/keychain/ot/OTCuttlefishContext.m index b8fd2275..3ebe0853 100644 --- a/keychain/ot/OTCuttlefishContext.m +++ b/keychain/ot/OTCuttlefishContext.m @@ -50,7 +50,6 @@ #import "keychain/ot/OTStates.h" #import "keychain/ot/OTFollowup.h" #import "keychain/ot/OTAuthKitAdapter.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTConstants.h" #import "keychain/ot/OTOperationDependencies.h" #import "keychain/ot/OTClique.h" @@ -113,6 +112,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; NSData* _entropy; NSArray* _preapprovedKeys; NSString* _recoveryKey; + CuttlefishResetReason _resetReason; BOOL _skipRateLimitingCheck; } @@ -195,7 +195,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [_sosAdapter registerForPeerChangeUpdates:self]; _authKitAdapter = authKitAdapter; _deviceAdapter = deviceInformationAdapter; - _cuttlefishXPCConnection = cuttlefish; + [_deviceAdapter registerForDeviceNameUpdates:self]; + + _cuttlefishXPCWrapper = [[CuttlefishXPCWrapper alloc] initWithCuttlefishXPCConnection:cuttlefish]; _lockStateTracker = lockStateTracker; _accountStateTracker = accountStateTracker; @@ -222,7 +224,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (void)dealloc { // TODO: how to invalidate this? - //[self.cuttlefishXPCConnection invalidate]; + //[self.cuttlefishXPCWrapper invalidate]; } - (void)notifyTrustChanged:(OTAccountMetadataClassC_TrustState)trustState { @@ -264,82 +266,77 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (void)machinesAdded:(NSArray*)machineIDs altDSID:(NSString*)altDSID { WEAKIFY(self); - dispatch_sync(self.queue, ^{ - NSError* metadataError = nil; - OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore _onqueueLoadOrCreateAccountMetadata:&metadataError]; + NSError* metadataError = nil; + OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError]; - if(!accountMetadata || metadataError) { - secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); - [self requestTrustedDeviceListRefresh]; - return; - } + if(!accountMetadata || metadataError) { + // TODO: collect a sysdiagnose here if the error is not "device is in class D" + secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); + [self requestTrustedDeviceListRefresh]; + return; + } - if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { - secnotice("octagon-authkit", "Machines-added push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); - return; - } + if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { + secnotice("octagon-authkit", "Machines-added push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); + return; + } - secnotice("octagon-authkit", "adding machines for altDSID(%@): %@", altDSID, machineIDs); - - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon-authkit: Can't talk with TrustedPeersHelper: %@", error); - }] addAllowedMachineIDsWithContainer:self.containerName - context:self.contextID - machineIDs:machineIDs - reply:^(NSError* error) { - if (error) { - secerror("octagon-authkit: addAllow errored: %@", error); - STRONGIFY(self); - [self requestTrustedDeviceListRefresh]; - } else { - secnotice("octagon-authkit", "addAllow succeeded"); + secnotice("octagon-authkit", "adding machines for altDSID(%@): %@", altDSID, machineIDs); - OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification - conditions:OctagonPendingConditionsDeviceUnlocked]; - [self.stateMachine handlePendingFlag:pendingFlag]; - } - }]; - }); + [self.cuttlefishXPCWrapper addAllowedMachineIDsWithContainer:self.containerName + context:self.contextID + machineIDs:machineIDs + reply:^(NSError* error) { + STRONGIFY(self); + if (error) { + secerror("octagon-authkit: addAllow errored: %@", error); + [self requestTrustedDeviceListRefresh]; + } else { + secnotice("octagon-authkit", "addAllow succeeded"); + + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; + } + }]; } - (void)machinesRemoved:(NSArray*)machineIDs altDSID:(NSString*)altDSID { WEAKIFY(self); - dispatch_sync(self.queue, ^{ - NSError* metadataError = nil; - OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore _onqueueLoadOrCreateAccountMetadata:&metadataError]; - if(!accountMetadata || metadataError) { - secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); - [self requestTrustedDeviceListRefresh]; - return; - } + NSError* metadataError = nil; + OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError]; - if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { - secnotice("octagon-authkit", "Machines-removed push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); - return; - } + if(!accountMetadata || metadataError) { + // TODO: collect a sysdiagnose here if the error is not "device is in class D" + secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); + [self requestTrustedDeviceListRefresh]; + return; + } - secnotice("octagon-authkit", "removing machines for altDSID(%@): %@", altDSID, machineIDs); - - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon-authkit: Can't talk with TrustedPeersHelper: %@", error); - }] removeAllowedMachineIDsWithContainer:self.containerName - context:self.contextID - machineIDs:machineIDs - reply:^(NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon-authkit: removeAllow errored: %@", error); - } else { - secnotice("octagon-authkit", "removeAllow succeeded"); - } + if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { + secnotice("octagon-authkit", "Machines-removed push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); + return; + } - // We don't necessarily trust remove pushes; they could be delayed past when an add has occurred. - // Request that the full list be rechecked. - [self requestTrustedDeviceListRefresh]; - }]; - }); + secnotice("octagon-authkit", "removing machines for altDSID(%@): %@", altDSID, machineIDs); + + [self.cuttlefishXPCWrapper removeAllowedMachineIDsWithContainer:self.containerName + context:self.contextID + machineIDs:machineIDs + reply:^(NSError* _Nullable error) { + STRONGIFY(self); + if (error) { + secerror("octagon-authkit: removeAllow errored: %@", error); + } else { + secnotice("octagon-authkit", "removeAllow succeeded"); + } + + // We don't necessarily trust remove pushes; they could be delayed past when an add has occurred. + // Request that the full list be rechecked. + [self requestTrustedDeviceListRefresh]; + }]; } - (void)incompleteNotificationOfMachineIDListChange @@ -431,16 +428,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (BOOL)idmsTrustLevelChanged:(NSError**)error { - // Cool! If we believe there's no sufficient iCloud account, let's try checking again - CKKSResultOperation* checkHSA2 = [OctagonStateTransitionOperation named:[NSString stringWithFormat:@"%@", @"check-hsa2-status"] - entering:OctagonStateDetermineiCloudAccountState]; - - OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"check-hsa2-state" - sourceStates:[NSSet setWithArray: @[OctagonStateWaitForHSA2]] - serialQueue:self.queue - timeout:OctagonStateTransitionDefaultTimeout - transitionOp:checkHSA2]; - [self.stateMachine handleExternalRequest:request]; + [self.stateMachine handleFlag:OctagonFlagIDMSLevelChanged]; return YES; } @@ -512,7 +500,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; contextID:self.contextID intendedState:OctagonStateBecomeUntrusted errorState:OctagonStateError - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; NSMutableSet* sourceStates = [NSMutableSet setWithArray: OctagonStateMap().allKeys]; [self.stateMachine doSimpleStateMachineRPC:@"local-reset" op:pendingOp sourceStates:sourceStates reply:reply]; @@ -558,8 +546,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; reply:reply]; } -- (void)rpcResetAndEstablish:(nonnull void (^)(NSError * _Nullable))reply +- (void)rpcResetAndEstablish:(CuttlefishResetReason)resetReason reply:(nonnull void (^)(NSError * _Nullable))reply { + _resetReason = resetReason; + // The reset flow can split into an error-handling path halfway through; this is okay OctagonStateTransitionPath* path = [OctagonStateTransitionPath pathFromDictionary: @{ OctagonStateResetBecomeUntrusted: @{ @@ -587,7 +577,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } - (void)rpcRemoveFriendsInClique:(NSArray*)peerIDs - reply:(void (^)(NSError*))reply + reply:(void (^)(NSError * _Nullable))reply { OTRemovePeersOperation* op = [[OTRemovePeersOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady @@ -626,9 +616,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; sosAdapter:self.sosAdapter octagonAdapter:self.octagonAdapter authKitAdapter:self.authKitAdapter + deviceInfoAdapter:self.deviceAdapter viewManager:self.viewManager lockStateTracker:self.lockStateTracker - cuttlefishXPC:self.cuttlefishXPCConnection + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper escrowRequestClass:self.escrowRequestClass]; } @@ -682,6 +673,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } if([currentState isEqualToString:OctagonStateWaitForHSA2]) { + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + return [OctagonStateTransitionOperation named:@"hsa2-check" + entering:OctagonStateDetermineiCloudAccountState]; + } + secnotice("octagon", "Waiting for an HSA2 account"); return nil; } @@ -731,6 +728,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; if ([currentState isEqualToString:OctagonStatePostRepairCFU]) { return [self postRepairCFUAndBecomeUntrusted]; } + + if ([currentState isEqualToString:OctagonStateHealthCheckReset]) { + // A small violation of state machines... + _resetReason = CuttlefishResetReasonHealthCheck; + return [OctagonStateTransitionOperation named:@"begin-reset" + entering:OctagonStateResetBecomeUntrusted]; + } #pragma mark --- Watch Pairing States @@ -790,6 +794,11 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"untrusted-update" entering:OctagonStateUntrustedUpdated]; } + + // We're untrusted; no need for the IDMS level flag anymore + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + } } if([currentState isEqualToString:OctagonStateUntrustedUpdated]) { @@ -864,11 +873,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; contextID:self.contextID intendedState:OctagonStateNoAccount errorState:OctagonStateNoAccount - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; } if([currentState isEqualToString:OctagonStateEnsureConsistency]) { - secnotice("octagon", "Ensuring consistency of things that might've changed"); if(self.sosAdapter.sosEnabled) { return [[OTEnsureOctagonKeyConsistency alloc] initWithDependencies:self.operationDependencies @@ -967,7 +975,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; OTUpdateTrustedDeviceListOperation* op = [[OTUpdateTrustedDeviceListOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateInitiatorJoin listUpdatesState:OctagonStateInitiatorJoin - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted retryFlag:nil]; return op; @@ -975,7 +983,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; OTJoinWithVoucherOperation* op = [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady ckksConflictState:OctagonStateInitiatorJoinCKKSReset - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted voucherData:_vouchData voucherSig:_vouchSig preapprovedKeys:_preapprovedKeys]; @@ -990,7 +998,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady ckksConflictState:OctagonStateBecomeUntrusted - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted voucherData:_vouchData voucherSig:_vouchSig preapprovedKeys:_preapprovedKeys]; @@ -1001,9 +1009,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } else if([currentState isEqualToString:OctagonStateResetAndEstablish]) { return [[OTResetOperation alloc] init:self.containerName contextID:self.contextID + reason:_resetReason intendedState:OctagonStateResetAnyMissingTLKCKKSViews errorState:OctagonStateError - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; } else if([currentState isEqualToString:OctagonStateResetAnyMissingTLKCKKSViews]) { return [[OTResetCKKSZonesLackingTLKsOperation alloc] initWithDependencies:self.operationDependencies @@ -1070,17 +1079,25 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; sosNotPresentState:OctagonStateReady errorState:OctagonStateReady]; - } else if([currentState isEqualToString: OctagonStateAssistCKKSTLKUpload]) { + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUpload]) { return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateReady + ckksConflictState:OctagonStateAssistCKKSTLKUploadCKKSReset errorState:OctagonStateReady]; - } else if([currentState isEqualToString:OctagonStateReady]) { - if([flags _onqueueContains:OctagonFlagPerformHealthCheck]) { - [flags _onqueueRemoveFlag:OctagonFlagPerformHealthCheck]; - return [self cuttlefishTrustEvaluation]; - } + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUploadCKKSReset]) { + return [[OTLocalCKKSResetOperation alloc] initWithDependencies:self.operationDependencies + intendedState:OctagonStateAssistCKKSTLKUploadAfterCKKSReset + errorState:OctagonStateBecomeReady]; + + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUploadAfterCKKSReset]) { + // If CKKS fails again, just go to 'ready' + return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies + intendedState:OctagonStateReady + ckksConflictState:OctagonStateReady + errorState:OctagonStateReady]; + } else if([currentState isEqualToString:OctagonStateReady]) { if([flags _onqueueContains:OctagonFlagCKKSRequestsTLKUpload]) { [flags _onqueueRemoveFlag:OctagonFlagCKKSRequestsTLKUpload]; return [OctagonStateTransitionOperation named:@"ckks-assist" @@ -1117,6 +1134,29 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } } + if([flags _onqueueContains:OctagonFlagAttemptSOSConsistency]) { + [flags _onqueueRemoveFlag:OctagonFlagAttemptSOSConsistency]; + if(self.sosAdapter.sosEnabled) { + secnotice("octagon", "Attempting SOS consistency checks"); + return [OctagonStateTransitionOperation named:@"attempt-sos-update-preapproval" + entering:OctagonStateEnsureConsistency]; + } else { + secnotice("octagon", "Someone would like us to check SOS consistency, but this platform doesn't support SOS."); + } + } + + if([flags _onqueueContains:OctagonFlagAccountIsAvailable]) { + // We're in ready--we already know the account is available + secnotice("octagon", "Removing 'account is available' flag"); + [flags _onqueueRemoveFlag:OctagonFlagAccountIsAvailable]; + } + + // We're ready; no need for the IDMS level flag anymore + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + secnotice("octagon", "Removing 'IDMS level changed' flag"); + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + } + secnotice("octagon", "Entering state ready"); [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:OctagonAnalyticsLastKeystateReady]; [self.launchSequence launch]; @@ -1128,10 +1168,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; retryFlag:OctagonFlagCuttlefishNotification]; } else if ([currentState isEqualToString:OctagonStateError]) { - if([flags _onqueueContains:OctagonFlagPerformHealthCheck]) { - [flags _onqueueRemoveFlag:OctagonFlagPerformHealthCheck]; - return [self cuttlefishTrustEvaluation]; - } } return nil; @@ -1281,19 +1317,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; secnotice("octagon-health", "Not posting confirm passcode CFU, already pending a prerecord upload"); } } - if (op.resetOctagon) { - secnotice("octagon-health", "Resetting Octagon as per Cuttlefish request"); - // uh oh let's reset octagon.. - - [self rpcResetAndEstablish:^(NSError *error) { - if(error){ - secerror("octagon-health: failed to reset octagon: %@", error); - op.error = error; - } else { - secnotice("octagon-health", "successfully reset octagon"); - } - }]; - } }]; [callback addDependency:op]; [self.operationQueue addOperation: callback]; @@ -1673,9 +1696,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; NSString *trustState = OTAccountMetadataClassC_TrustStateAsString(self.currentMemoizedTrustState); OctagonState* currentState = [self.stateMachine waitForState:OctagonStateReady wait:3*NSEC_PER_SEC]; - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper, report is lost: %@", error); - }] reportHealthWithContainer:self.containerName context:self.contextID stateMachineState:currentState trustState:trustState reply:^(NSError * _Nullable error) { + [self.cuttlefishXPCWrapper reportHealthWithContainer:self.containerName context:self.contextID stateMachineState:currentState trustState:trustState reply:^(NSError * _Nullable error) { if (error) { secerror("octagon: health report is lost: %@", error); } @@ -1780,6 +1801,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.apsRateLimiter trigger]; } +- (BOOL)waitForReady:(int64_t)timeOffset +{ + OctagonState* currentState = [self.stateMachine waitForState:OctagonStateReady wait:timeOffset]; + return [currentState isEqualToString:OctagonStateReady]; + +} + - (OTAccountMetadataClassC_TrustState)currentMemoizedTrustState { NSError* localError = nil; @@ -1826,6 +1854,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.stateMachine handleFlag:OctagonFlagFetchAuthKitMachineIDList]; } +#pragma mark --- Device Info update handling + +- (void)deviceNameUpdated { + secnotice("octagon-devicename", "device name updated: %@", self.contextID); + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; +} + #pragma mark --- SOS update handling @@ -1844,13 +1881,28 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; secnotice("octagon-sos", "This platform doesn't support SOS. This is probably a bug?"); } - //OTUpdatePreapprovalsOperation* op = [[OTUpdatePreapprovalsOperation alloc] initWithDependencies:self.operationDependencies]; + if (self.sosConsistencyRateLimiter == nil) { + secnotice("octagon", "creating SOS consistency rate limiter"); + dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 200 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); + dispatch_time_t maximumDelay = (SecCKKSReduceRateLimiting() ? 10 * NSEC_PER_SEC : 30 * NSEC_PER_SEC); + + WEAKIFY(self); + + void (^block)(void) = ^{ + STRONGIFY(self); + [self.stateMachine handleFlag:OctagonFlagAttemptSOSConsistency]; + }; + + self.sosConsistencyRateLimiter = [[CKKSNearFutureScheduler alloc] initWithName:@"sos-consistency-ratelimiter" + initialDelay:initialDelay + expontialBackoff:2 + maximumDelay:maximumDelay + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionPendingZoneChangeFetchScheduling + block:block]; + } - [self.stateMachine doSimpleStateMachineRPC:@"update-sos-preapprovals" - op:[OctagonStateTransitionOperation named:@"sos-peers-changed" - entering:OctagonStateUpdateSOSPreapprovals] - sourceStates:[NSSet setWithObject:OctagonStateReady] - reply:^(NSError* error) {}]; + [self.sosConsistencyRateLimiter trigger]; } #pragma mark --- External Interfaces @@ -1975,17 +2027,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.stateMachine doWatchedStateMachineRPC:@"rpc-join-with-bottle" sourceStates:OctagonInAccountStates() path:path - reply:^(NSError *joinError) { - if(joinError) { - if([joinError isCuttlefishError: CuttlefishErrorResultGraphNotFullyReachable]){ - secnotice("octagon", "setting flag for cuttlefish health check"); - [self.stateMachine handleFlag:OctagonFlagPerformHealthCheck]; - } - reply(joinError); - } else { - reply(nil); - } - }]; + reply:reply]; } -(void)joinWithRecoveryKey:(NSString*)recoveryKey @@ -2164,21 +2206,20 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } result[@"CoreFollowUp"] = [self.followupHandler sysdiagnoseStatus]; + result[@"lastOctagonPush"] = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastOctagonPush]; + - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to dump state for status RPC: %@", error); - reply(nil, error); - }] dumpWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { - secnotice("octagon", "Finished dump for status RPC"); - if(dumpError) { - result[@"contextDumpError"] = dumpError; - } else { - result[@"contextDump"] = dump; - } - reply(result, nil); - }]; + [self.cuttlefishXPCWrapper dumpWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { + secnotice("octagon", "Finished dump for status RPC"); + if(dumpError) { + result[@"contextDumpError"] = dumpError; + } else { + result[@"contextDump"] = dump; + } + reply(result, nil); + }]; } - (void)rpcFetchEgoPeerID:(void (^)(NSString* peerID, NSError* error))reply @@ -2204,45 +2245,42 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to fetch peers: %@", error); - reply(nil, error); - }] dumpWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { - // Pull out our peers - if(dumpError) { - secnotice("octagon", "Unable to dump info: %@", dumpError); - reply(nil, dumpError); - return; - } - - NSDictionary* selfInfo = dump[@"self"]; - NSArray* peers = dump[@"peers"]; - NSArray* trustedPeerIDs = selfInfo[@"dynamicInfo"][@"included"]; - - NSMutableDictionary* peerMap = [NSMutableDictionary dictionary]; - - for(NSString* peerID in trustedPeerIDs) { - NSDictionary* peerMatchingID = nil; - - for(NSDictionary* peer in peers) { - if([peer[@"peerID"] isEqualToString:peerID]) { - peerMatchingID = peer; - break; - } - } + [self.cuttlefishXPCWrapper dumpWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { + // Pull out our peers + if(dumpError) { + secnotice("octagon", "Unable to dump info: %@", dumpError); + reply(nil, dumpError); + return; + } - if(!peerMatchingID) { - secerror("octagon: have a trusted peer ID without peer information: %@", peerID); - continue; - } + NSDictionary* selfInfo = dump[@"self"]; + NSArray* peers = dump[@"peers"]; + NSArray* trustedPeerIDs = selfInfo[@"dynamicInfo"][@"included"]; + + NSMutableDictionary* peerMap = [NSMutableDictionary dictionary]; + + for(NSString* peerID in trustedPeerIDs) { + NSDictionary* peerMatchingID = nil; + + for(NSDictionary* peer in peers) { + if([peer[@"peerID"] isEqualToString:peerID]) { + peerMatchingID = peer; + break; + } + } + + if(!peerMatchingID) { + secerror("octagon: have a trusted peer ID without peer information: %@", peerID); + continue; + } - peerMap[peerID] = peerMatchingID[@"stableInfo"][@"device_name"]; - } + peerMap[peerID] = peerMatchingID[@"stableInfo"][@"device_name"]; + } - reply(peerMap, nil); - }]; + reply(peerMap, nil); + }]; } - (void)rpcSetRecoveryKey:(NSString*)recoveryKey reply:(void (^)(NSError * _Nullable error))reply @@ -2319,26 +2357,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys return; } - NSXPCConnection* c = [self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *xpcError) { - localError = xpcError; - secnotice("octagon", "rpcTrustStatus: Failed to get XPC connection: %@", xpcError); - }]; - - if(localError){ - reply(CliqueStatusError, nil, nil, NO, localError); - return; - } __block NSString* peerID = nil; __block NSDictionary* peerModelCounts = nil; __block BOOL excluded = NO; __block CliqueStatus trustStatus = CliqueStatusError; - [c trustStatusWithContainer:self.containerName context:self.contextID reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus, - NSError *xpcError) { + [self.cuttlefishXPCWrapper trustStatusWithContainer:self.containerName context:self.contextID reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus, + NSError *xpcError) { TPPeerStatus status = egoStatus.egoStatus; peerID = egoStatus.egoPeerID; excluded = egoStatus.isExcluded; - peerModelCounts = egoStatus.peerCountsByModelID; + peerModelCounts = egoStatus.viablePeerCountsByModelID; localError = xpcError; if(xpcError) { @@ -2394,21 +2423,18 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - reply(nil, nil, error); - }] fetchViableBottlesWithContainer:self.containerName - context:self.contextID - reply:^(NSArray* _Nullable sortedEscrowRecordIDs, NSArray* _Nullable sortedPartialEscrowRecordIDs, NSError * _Nullable error) { - if(error){ - secerror("octagon: error fetching all viable bottles: %@", error); - reply(nil, nil, error); - }else{ - secnotice("octagon", "fetched viable bottles: %@", sortedEscrowRecordIDs); - secnotice("octagon", "fetched partially viable bottles: %@", sortedPartialEscrowRecordIDs); - reply(sortedEscrowRecordIDs, sortedPartialEscrowRecordIDs, error); - } - }]; + [self.cuttlefishXPCWrapper fetchViableBottlesWithContainer:self.containerName + context:self.contextID + reply:^(NSArray* _Nullable sortedEscrowRecordIDs, NSArray* _Nullable sortedPartialEscrowRecordIDs, NSError * _Nullable error) { + if(error){ + secerror("octagon: error fetching all viable bottles: %@", error); + reply(nil, nil, error); + }else{ + secnotice("octagon", "fetched viable bottles: %@", sortedEscrowRecordIDs); + secnotice("octagon", "fetched partially viable bottles: %@", sortedPartialEscrowRecordIDs); + reply(sortedEscrowRecordIDs, sortedPartialEscrowRecordIDs, error); + } + }]; } - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy, @@ -2417,20 +2443,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys NSError* _Nullable error))reply { // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - reply(nil, nil, nil, error); - }] fetchEscrowContentsWithContainer:self.containerName - context:self.contextID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - if(error){ - secerror("octagon: error fetching escrow contents: %@", error); - reply(nil, nil, nil, error); - }else{ - secnotice("octagon", "fetched escrow contents for bottle: %@", bottleID); - reply(entropy, bottleID, signingPublicKey, error); - } - }]; + [self.cuttlefishXPCWrapper fetchEscrowContentsWithContainer:self.containerName + context:self.contextID + reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { + if(error){ + secerror("octagon: error fetching escrow contents: %@", error); + reply(nil, nil, nil, error); + }else{ + secnotice("octagon", "fetched escrow contents for bottle: %@", bottleID); + reply(entropy, bottleID, signingPublicKey, error); + } + }]; } - (void)rpcValidatePeers:(void (^)(NSDictionary* _Nullable result, NSError* _Nullable error))reply @@ -2447,20 +2470,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys return; } - [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to validatePeers RPC: %@", error); - reply(nil, error); - }] validatePeersWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable validateData, NSError * _Nullable dumpError) { - secnotice("octagon", "Finished validatePeers for status RPC"); - if(dumpError) { - result[@"error"] = dumpError; - } else { - result[@"validate"] = validateData; - } - reply(result, nil); - }]; + [self.cuttlefishXPCWrapper validatePeersWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable validateData, NSError * _Nullable dumpError) { + secnotice("octagon", "Finished validatePeers for status RPC"); + if(dumpError) { + result[@"error"] = dumpError; + } else { + result[@"validate"] = validateData; + } + reply(result, nil); + }]; } @@ -2583,6 +2603,9 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys OctagonStateReady: [OctagonStateTransitionPathStep success], OctagonStateWaitForUnlock: [OctagonStateTransitionPathStep success], }, + // Cuttlefish can suggest we reset the world. Consider reaching here a success, + // instead of tracking the whole reset. + OctagonStateHealthCheckReset: [OctagonStateTransitionPathStep success], }, }, }, diff --git a/keychain/ot/OTDefines.h b/keychain/ot/OTDefines.h index 1313fda0..216d2614 100644 --- a/keychain/ot/OTDefines.h +++ b/keychain/ot/OTDefines.h @@ -37,73 +37,86 @@ extern NSString* const CuttlefishTrustZone; extern NSString* const CuttlefishErrorDomain; extern NSString* const TrustedPeersHelperErrorDomain; +extern NSString* const CuttlefishErrorRetryAfterKey; + /* Octagon Errors */ typedef enum { - OTErrorNoColumn = 1, - OTErrorKeyGeneration = 2, - OTErrorEmptySecret = 3, - OTErrorEmptyDSID = 4, + //OTErrorNoColumn = 1, + //OTErrorKeyGeneration = 2, + //OTErrorEmptySecret = 3, + //OTErrorEmptyDSID = 4, OTErrorNoIdentity = 5, - OTErrorRestoreFailed = 6, - OTErrorRestoredPeerEncryptionKeyFailure = 7, - OTErrorRestoredPeerSigningKeyFailure = 8, - OTErrorEntropyCreationFailure = 9, + //OTErrorRestoreFailed = 6, + //OTErrorRestoredPeerEncryptionKeyFailure = 7, + //OTErrorRestoredPeerSigningKeyFailure = 8, + //OTErrorEntropyCreationFailure = 9, OTErrorDeserializationFailure = 10, - OTErrorDecryptFailure = 11, - OTErrorPrivateKeyFailure = 12, - OTErrorEscrowSigningSPKI = 13, - OTErrorBottleID = 14, - OTErrorOTLocalStore = 15, - OTErrorOTCloudStore = 16, - OTErrorEmptyEscrowRecordID = 17, - OTErrorNoBottlePeerRecords = 18, - OTErrorCoreFollowUp = 19, + //OTErrorDecryptFailure = 11, + //OTErrorPrivateKeyFailure = 12, + //OTErrorEscrowSigningSPKI = 13, + //OTErrorBottleID = 14, + //OTErrorOTLocalStore = 15, + //OTErrorOTCloudStore = 16, + //OTErrorEmptyEscrowRecordID = 17, + //OTErrorNoBottlePeerRecords = 18, + //OTErrorCoreFollowUp = 19, OTErrorFeatureNotEnabled = 20, OTErrorCKCallback = 21, - OTErrorRampInit = 22, + //OTErrorRampInit = 22, OTErrorCKTimeOut = 23, OTErrorNoNetwork = 24, OTErrorNotSignedIn = 25, OTErrorRecordNotFound = 26, - OTErrorNoEscrowKeys = 27, - OTErrorBottleUpdate = 28, + //OTErrorNoEscrowKeys = 27, + //OTErrorBottleUpdate = 28, OTErrorNotSupported = 29, OTErrorUnexpectedStateTransition = 30, OTErrorNoSuchContext = 31, - OTErrorTimeout = 32, - OTErrorMasterKey = 33, - OTErrorNotTrusted = 34, + //OTErrorTimeout = 32, + //OTErrorMasterKey = 33, + //OTErrorNotTrusted = 34, OTErrorLimitedPeer = 35, - OTErrorNoOctagonKeysInSOS = 36, - OTErrorNeedsAuthentication = 37, + //OTErrorNoOctagonKeysInSOS = 36, + //OTErrorNeedsAuthentication = 37, OTErrorOctagonAdapter = 38, OTErrorSOSAdapter = 39, - OctagonErrorNoAccount = 40, + //OctagonErrorNoAccount = 40, + OTErrorRecoveryKeyMalformed = 41, } OctagonErrorCode; #define OTMasterSecretLength 72 -typedef enum { - OctagonSigningKey = 1, - OctagonEncryptionKey = 2 -} OctagonKeyType; - -typedef enum { - UNCLEAR = 0, - BOTTLE = 1, - NOBOTTLE = 2 -} OctagonBottleCheckState; - typedef NS_ENUM(NSInteger, TrustedPeersHelperErrorCode) { TrustedPeersHelperErrorNoPreparedIdentity = 1, TrustedPeersHelperErrorNoPeersPreapprovePreparedIdentity = 14, TrustedPeersHelperErrorCodeNotEnrolled = 34, }; +// See cuttlefish/CuttlefishService/Sources/CuttlefishService/CuttlefishError.swift typedef NS_ENUM(NSInteger, CuttlefishErrorCode) { + CuttlefishErrorEstablishFailed = 1001, + CuttlefishErrorJoinFailed = 1002, + CuttlefishErrorUpdateTrustFailed = 1004, + CuttlefishErrorInvalidChangeToken = 1005, + CuttlefishErrorMalformedRecord = 1006, CuttlefishErrorResultGraphNotFullyReachable = 1007, + CuttlefishErrorResultGraphHasNoPotentiallyTrustedPeers = 1008, + CuttlefishErrorResultGraphHasSplitKnowledge = 1009, + CuttlefishErrorResultGraphHasPeerWithNoSelf = 1010, + CuttlefishErrorInvalidEscrowProxyOperation = 1011, + CuttlefishErrorRecordWrongType = 1012, + CuttlefishErrorMissingMandatoryField = 1013, + CuttlefishErrorMalformedViewKeyHierarchy = 1014, + CuttlefishErrorUnknownView = 1015, + CuttlefishErrorEstablishPeerFailed = 1016, + CuttlefishErrorEstablishBottleFailed = 1017, + CuttlefishErrorChangeTokenExpired = 1018, CuttlefishErrorTransactionalFailure = 1019, + CuttlefishErrorSetRecoveryKeyFailed = 1020, + CuttlefishErrorRetryableServerFailure = 1021, + CuttlefishErrorPreflightGraphValidationError = 1022, CuttlefishErrorKeyHierarchyAlreadyExists = 1033, + CuttlefishErrorDuplicatePeerIdUnderConsideration = 1034, }; NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTDefines.m b/keychain/ot/OTDefines.m index 76302f65..0aa95a36 100644 --- a/keychain/ot/OTDefines.m +++ b/keychain/ot/OTDefines.m @@ -33,3 +33,5 @@ NSString* OTCKContainerName = @"com.apple.security.keychain"; NSString* const CuttlefishTrustZone = @"CuttlefishTrustZone"; NSString* const CuttlefishErrorDomain = @"CuttlefishError"; NSString* const TrustedPeersHelperErrorDomain = @"com.apple.security.trustedpeers.container"; + +NSString* const CuttlefishErrorRetryAfterKey = @"retryafter"; diff --git a/keychain/ot/OTDeviceInformationAdapter.h b/keychain/ot/OTDeviceInformationAdapter.h index f2c26f54..43279916 100644 --- a/keychain/ot/OTDeviceInformationAdapter.h +++ b/keychain/ot/OTDeviceInformationAdapter.h @@ -3,6 +3,10 @@ NS_ASSUME_NONNULL_BEGIN +@protocol OTDeviceInformationNameUpdateListener +- (void)deviceNameUpdated; +@end + @protocol OTDeviceInformationAdapter /* Returns a string like "iPhone3,5" */ @@ -17,6 +21,9 @@ NS_ASSUME_NONNULL_BEGIN /* Returns the serial number as a string. */ - (NSString*)serialNumber; +/* register for deviceName updates */ +- (void)registerForDeviceNameUpdates:(id)listener; + @end @interface OTDeviceInformationActualAdapter : NSObject diff --git a/keychain/ot/OTDeviceInformationAdapter.m b/keychain/ot/OTDeviceInformationAdapter.m index 4fa6e072..acd71ebe 100644 --- a/keychain/ot/OTDeviceInformationAdapter.m +++ b/keychain/ot/OTDeviceInformationAdapter.m @@ -1,4 +1,6 @@ -#import "OTDeviceInformationAdapter.h" +#import "keychain/ot/OTDeviceInformationAdapter.h" +#import "keychain/ot/OTConstants.h" +#import "keychain/ckks/CKKSListenerCollection.h" #import "keychain/ckks/CKKS.h" #include @@ -12,8 +14,22 @@ #include #endif +static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *context); + +@interface OTDeviceInformationActualAdapter () +@property CKKSListenerCollection>* deviceNameUpdateListeners; +@property (assign) SCDynamicStoreRef store; +@end + @implementation OTDeviceInformationActualAdapter +- (void)dealloc { + if (self.store) { + CFRelease(self.store); + self.store = NULL; + } +} + - (NSString*)modelID { static NSString *hwModel = nil; @@ -57,6 +73,18 @@ } } +- (void)registerForDeviceNameUpdates:(id)listener +{ + // Octagon only uses the device name on internal releases. + // Therefore, if this is not an internal release, don't bother registering clients--they don't need the update. + if (SecIsInternalRelease()) { + @synchronized (self) { + [self setupDeviceNameListener]; + [self.deviceNameUpdateListeners registerListener:listener]; + } + } +} + - (NSString*)osVersion { return SecCKKSHostOSVersion(); @@ -97,5 +125,38 @@ #endif + +- (void)setupDeviceNameListener { + if (self.deviceNameUpdateListeners == nil) { + self.deviceNameUpdateListeners = [[CKKSListenerCollection alloc] initWithName:@"OTDeviceInformationActualAdapter"]; + + CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL); + if (computerKey == NULL) { + return; + } + NSArray *keys = @[ (__bridge NSString *)computerKey]; + CFRelease(computerKey); + + SCDynamicStoreContext context = { .info = (void *)(__bridge CFTypeRef)self }; + self.store = SCDynamicStoreCreate(NULL, CFSTR("OTDeviceInformationActualAdapter"), updateDeviceNameChanges, &context); + if (self.store == NULL) { + return; + } + + SCDynamicStoreSetNotificationKeys(self.store, (__bridge CFArrayRef)keys, NULL); + SCDynamicStoreSetDispatchQueue(self.store, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + } +} + @end +static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *info) +{ + secnotice("octagon", "Notified that the device name has changed"); + OTDeviceInformationActualAdapter *adapter = (__bridge id)info; + + [adapter.deviceNameUpdateListeners iterateListeners:^void(id object){ + [object deviceNameUpdated]; + }]; +} + diff --git a/keychain/ot/OTEnsureOctagonKeyConsistency.m b/keychain/ot/OTEnsureOctagonKeyConsistency.m index 985ee0a8..bb86a39c 100644 --- a/keychain/ot/OTEnsureOctagonKeyConsistency.m +++ b/keychain/ot/OTEnsureOctagonKeyConsistency.m @@ -39,7 +39,7 @@ #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ot/ObjCImprovements.h" -#import +#import "keychain/securityd/SOSCloudCircleServer.h" @interface OTEnsureOctagonKeyConsistency () @property OTOperationDependencies* deps; @@ -64,7 +64,7 @@ - (void)groupStart { - secnotice("octagon-sos", "Beginning ensuring Octagon keys are the same between "); + secnotice("octagon-sos", "Beginning ensuring Octagon keys are set properly in SOS"); self.finishOp = [[NSOperation alloc] init]; [self dependOnBeforeGroupFinished:self.finishOp]; @@ -99,7 +99,7 @@ NSError* fetchSelfPeersError = nil; CKKSSelves *selfPeers = [octagonAdapter fetchSelfPeers:&fetchSelfPeersError]; - if(fetchSelfPeersError) { + if((!selfPeers) || fetchSelfPeersError) { secnotice("octagon", "failed to retrieve self peers: %@", fetchSelfPeersError); self.error = fetchSelfPeersError; [self runBeforeGroupFinished:self.finishOp]; diff --git a/keychain/ot/OTEpochOperation.h b/keychain/ot/OTEpochOperation.h index 8180f4d2..b474f6af 100644 --- a/keychain/ot/OTEpochOperation.h +++ b/keychain/ot/OTEpochOperation.h @@ -27,19 +27,19 @@ #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" @class OTCuttlefishContext; NS_ASSUME_NONNULL_BEGIN @interface OTEpochOperation : CKKSGroupOperation -@property OctagonState* nextState; -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initForCuttlefishContext:(OTCuttlefishContext*)context - intendedState:(OctagonState*)intendedState - errorState:(OctagonState*)errorState; -@property (weak) OTCuttlefishContext* cuttlefishContext; +- (instancetype)init:(NSString*)containerName + contextID:(NSString*)contextID + intendedState:(OctagonState*)intendedState + errorState:(OctagonState*)errorState +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; @property (nonatomic) uint64_t epoch; diff --git a/keychain/ot/OTEpochOperation.m b/keychain/ot/OTEpochOperation.m index 6d74b5bf..de28fd39 100644 --- a/keychain/ot/OTEpochOperation.m +++ b/keychain/ot/OTEpochOperation.m @@ -31,17 +31,29 @@ #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ot/ObjCImprovements.h" +@interface OTEpochOperation () +@property NSString* containerName; +@property NSString* contextID; +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; +@end + @implementation OTEpochOperation @synthesize intendedState = _intendedState; +@synthesize nextState = _nextState; -- (instancetype)initForCuttlefishContext:(OTCuttlefishContext*)context - intendedState:(OctagonState*)intendedState - errorState:(OctagonState*)errorState +- (instancetype)init:(NSString*)containerName + contextID:(NSString*)contextID + intendedState:(OctagonState*)intendedState + errorState:(OctagonState*)errorState +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; _nextState = errorState; - self.cuttlefishContext = context; + + _containerName = containerName; + _contextID = contextID; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; } return self; } @@ -53,30 +65,20 @@ NSOperation* finishOp = [[NSOperation alloc] init]; [self dependOnBeforeGroupFinished:finishOp]; - OTCuttlefishContext* strongCuttlefishContext = self.cuttlefishContext; - WEAKIFY(self); - - [[strongCuttlefishContext.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:finishOp]; - - }] fetchEgoEpochWithContainer:strongCuttlefishContext.containerName - context:strongCuttlefishContext.contextID - reply:^(uint64_t epoch, NSError* _Nullable error) { - STRONGIFY(self); - if(error) { - secerror("octagon: Error getting epoch: %@", error); - self.error = error; - } else { - self.epoch = epoch; - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:finishOp]; - - }]; + [self.cuttlefishXPCWrapper fetchEgoEpochWithContainer:self.containerName + context:self.contextID + reply:^(uint64_t epoch, NSError* _Nullable error) { + STRONGIFY(self); + if(error) { + secerror("octagon: Error getting epoch: %@", error); + self.error = error; + } else { + self.epoch = epoch; + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:finishOp]; + }]; } @end diff --git a/keychain/ot/OTEscrowKeys.h b/keychain/ot/OTEscrowKeys.h deleted file mode 100644 index bf6b8802..00000000 --- a/keychain/ot/OTEscrowKeys.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef OTEscrow_h -#define OTEscrow_h -#if OCTAGON - -#import -#import -NS_ASSUME_NONNULL_BEGIN - -typedef enum { - kOTEscrowKeySigning = 1, - kOTEscrowKeyEncryption = 2, - kOTEscrowKeySymmetric = 3, -} escrowKeyType; - -@interface OTEscrowKeys : NSObject - -@property (nonatomic, readonly) SFECKeyPair* encryptionKey; -@property (nonatomic, readonly) SFECKeyPair* signingKey; -@property (nonatomic, readonly) SFAESKey* symmetricKey; - -@property (nonatomic, readonly) NSData* secret; -@property (nonatomic, readonly) NSString* dsid; - --(instancetype) init NS_UNAVAILABLE; - -- (nullable instancetype) initWithSecret:(NSData*)secret - dsid:(NSString*)dsid - error:(NSError* __autoreleasing *)error; - -- (nullable instancetype) initWithSigningKey:(SFECKeyPair*)signingKey - encryptionKey:(SFECKeyPair*)encryptionKey - symmetricKey:(SFAESKey*)symmetricKey; - -+ (SecKeyRef) createSecKey:(NSData*)keyData; -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error; -+ (BOOL)findEscrowKeysForLabel:(NSString*)label - foundSigningKey:(SFECKeyPair*_Nonnull*_Nullable)signingKey - foundEncryptionKey:(SFECKeyPair*_Nonnull*_Nullable)encryptionKey - foundSymmetricKey:(SFAESKey*_Nonnull*_Nullable)symmetricKey - error:(NSError**)error; -+ (NSString*) hashEscrowedSigningPublicKey:(NSData*)keyData; - -+ (NSData* _Nullable) generateEscrowKey:(escrowKeyType)keyType - masterSecret:(NSData*)masterSecret - dsid:(NSString *)dsid - error:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END -#endif -#endif /* OTEscrow_h */ diff --git a/keychain/ot/OTEscrowKeys.m b/keychain/ot/OTEscrowKeys.m deleted file mode 100644 index 75e2ebf3..00000000 --- a/keychain/ot/OTEscrowKeys.m +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import "OTEscrowKeys.h" - -#import -#include -#include -#import -#import -#import - -#import -#import -#import -#import -#import - -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTConstants.h" -#import -#import -#import - -#import -#import -#import - -static uint8_t escrowedSigningPrivKey[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'i', 'g', 'n', 'i', 'n', 'g', ' ', 'P', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y'}; -static uint8_t escrowedEncryptionPrivKey[] = { 'E', 's', 'c', 'r', 'o', 'w', ' ','E', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', ' ', 'P', 'r', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y' }; -static uint8_t escrowedSymmetric[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'y', 'm', 'm', 'e', 't', 'r', 'i','c',' ', 'K', 'e', 'y' }; - -#define OT_ESCROW_SIGNING_HKDF_SIZE 56 -#define OT_ESCROW_ENCRYPTION_HKDF_SIZE 56 -#define OT_ESCROW_SYMMETRIC_HKDF_SIZE 32 - -@interface OTEscrowKeys () -@property (nonatomic, strong) SFECKeyPair* encryptionKey; -@property (nonatomic, strong) SFECKeyPair* signingKey; -@property (nonatomic, strong) SFAESKey* symmetricKey; -@property (nonatomic, strong) NSData* secret; -@property (nonatomic, strong) NSString* dsid; -@end - -@implementation OTEscrowKeys - -- (nullable instancetype) initWithSecret:(NSData*)secret - dsid:(NSString*)dsid - error:(NSError* __autoreleasing *)error -{ - self = [super init]; - if (self) { - NSError* localError = nil; - - if([secret length] == 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptySecret userInfo:@{NSLocalizedDescriptionKey: @"entropy/secret is nil"}]; - } - return nil; - } - _secret = [secret copy]; - - if([dsid length] == 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyDSID userInfo:@{NSLocalizedDescriptionKey: @"dsid is nil"}]; - } - return nil; - } - _dsid = [dsid copy]; - - NSData *data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _signingKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]]; - if(!_signingKey){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC signing key"}]; - } - return nil; - } - data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _encryptionKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]]; - if(!_encryptionKey){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC encryption key"}]; - } - return nil; - } - data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _symmetricKey = [[SFAESKey alloc] initWithData:data specifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:&localError]; - if (!_symmetricKey) { - if(error){ - *error = localError; - } - return nil; - } - NSString* escrowSigningPubKeyHash = [OTEscrowKeys hashEscrowedSigningPublicKey:[[_signingKey publicKey] encodeSubjectPublicKeyInfo]]; - BOOL result = [OTEscrowKeys storeEscrowedSigningKeyPair:[_signingKey keyData] label:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - result = [OTEscrowKeys storeEscrowedEncryptionKeyPair:[_encryptionKey keyData] label:escrowSigningPubKeyHash error:error]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - result = [OTEscrowKeys storeEscrowedSymmetricKey:[_symmetricKey keyData] label:escrowSigningPubKeyHash error:error]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - } - return self; -} - -- (nullable instancetype) initWithSigningKey:(SFECKeyPair*)signingKey - encryptionKey:(SFECKeyPair*)encryptionKey - symmetricKey:(SFAESKey*)symmetricKey -{ - self = [super init]; - if(self){ - _signingKey = signingKey; - _encryptionKey = encryptionKey; - _symmetricKey = symmetricKey; - } - return self; -} - -+ (NSData* _Nullable) generateEscrowKey:(escrowKeyType)keyType - masterSecret:(NSData*)masterSecret - dsid:(NSString *)dsid - error:(NSError**)error -{ - NSUInteger keyLength = 0; - const void *info = nil; - size_t infoLength = 0; - NSMutableData* derivedKey = NULL; - - switch(keyType) - { - case kOTEscrowKeySymmetric: - keyLength = OT_ESCROW_SYMMETRIC_HKDF_SIZE; - info = escrowedSymmetric; - infoLength = sizeof(escrowedSymmetric); - break; - case kOTEscrowKeyEncryption: - keyLength = OT_ESCROW_ENCRYPTION_HKDF_SIZE; - info = escrowedEncryptionPrivKey; - infoLength = sizeof(escrowedEncryptionPrivKey); - break; - case kOTEscrowKeySigning: - keyLength = OT_ESCROW_SIGNING_HKDF_SIZE; - info = escrowedSigningPrivKey; - infoLength = sizeof(escrowedSigningPrivKey); - break; - default: - break; - } - - ccec_const_cp_t cp = ccec_cp_384(); - int status = 0; - - ccec_full_ctx_decl_cp(cp, fullKey); - - derivedKey = [NSMutableData dataWithLength:keyLength]; - status = cchkdf(ccsha384_di(), - [masterSecret length], [masterSecret bytes], - strlen([dsid UTF8String]),[dsid UTF8String], - infoLength, info, - keyLength, [derivedKey mutableBytes]); - - - if (status != 0) { - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:nil]; - } - secerror("octagon: could not generate seed for signing keys"); - return nil; - } - if(keyType == kOTEscrowKeySymmetric){ - return derivedKey; - } - else if(keyType == kOTEscrowKeyEncryption || keyType == kOTEscrowKeySigning){ - - status = ccec_generate_key_deterministic(cp, - [derivedKey length], [derivedKey mutableBytes], - ccDRBGGetRngState(), - CCEC_GENKEY_DETERMINISTIC_FIPS, - fullKey); - if(status != 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:nil]; - } - secerror("octagon: could not generate signing keys"); - return nil; - } - - size_t space = ccec_x963_export_size(true, ccec_ctx_pub(fullKey)); - NSMutableData* key = [[NSMutableData alloc]initWithLength:space]; - ccec_x963_export(true, [key mutableBytes], fullKey); - derivedKey = key; - } - return derivedKey; -} - -+ (SecKeyRef) createSecKey:(NSData*)keyData -{ - NSDictionary *keyAttributes = @{ - (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, - (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, - }; - - SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)keyData, (__bridge CFDictionaryRef)keyAttributes, NULL); - return key; -} - -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error -{ - BOOL result = NO; - - CFTypeRef results = NULL; - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results); - - NSError* localerror = nil; - - if(status == errSecDuplicateItem || status == errSecSuccess) { - result = YES; - } else { - localerror = [NSError errorWithDomain:@"securityd" - code:status - userInfo:nil]; - } - if(status != errSecSuccess) { - CFReleaseNull(results); - - if(error) { - *error = localerror; - } - } - - return result; -} - -+(NSString*) hashEscrowedSigningPublicKey:(NSData*)keyData -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [keyData length], [keyData bytes], [result mutableBytes]); - - NSString* hash = [result base64EncodedStringWithOptions:0]; - return hash; -} - -+ (BOOL)storeEscrowedEncryptionKeyPair:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrLabel : label, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Encryption Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (BOOL)storeEscrowedSigningKeyPair:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Signing Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecAttrLabel : label, - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (BOOL)storeEscrowedSymmetricKey:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Symmetric Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecAttrLabel : label, - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (NSArray*)retrieveEscrowKeysFromKeychain:(NSString* _Nonnull)label error:(NSError**)error -{ - NSError* localError = nil; - NSArray* keySet = nil; - - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecAttrLabel: label, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnData : @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - }; - - CFTypeRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - - if(status != errSecSuccess || result == nil) { - secnotice("octagon", "no set of escrow keys for escrowed signing public key hash: %@", label); - localError = [NSError errorWithDomain:@"securityd" code:status userInfo:@{NSLocalizedDescriptionKey: @"no escrow key set for label"}]; - if(error){ - *error = localError; - } - } - - if(result && isArray(result)){ - secnotice("octagon", "found set of escrow keys for escrowed signing public key hash: %@", label); - keySet = (__bridge_transfer NSArray*)result; - } - - return keySet; -} - -+ (BOOL)findEscrowKeysForLabel:(NSString*)label foundSigningKey:(SFECKeyPair**)signingKey foundEncryptionKey:(SFECKeyPair**)encryptionKey foundSymmetricKey:(SFAESKey**)symmetricKey error:(NSError**)error -{ - BOOL result = NO; - NSError* localError = nil; - - NSArray* keySet = [OTEscrowKeys retrieveEscrowKeysFromKeychain:label error:&localError]; - - for(NSDictionary* item in keySet){ - - NSString* keyType = [[NSString alloc] initWithData:item[(id)kSecAttrApplicationLabel] encoding:NSUTF8StringEncoding]; - - if([keyType containsString:@"Symmetric"]){ - *symmetricKey = [[SFAESKey alloc] initWithData:item[(id)kSecValueData] specifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:&localError]; - }else if([keyType containsString:@"Encryption"]){ - SecKeyRef encryptionSecKey = [OTEscrowKeys createSecKey:item[(id)kSecValueData]]; - *encryptionKey = [[SFECKeyPair alloc] initWithSecKey:encryptionSecKey]; - CFReleaseNull(encryptionSecKey); - }else if([keyType containsString:@"Signing"]){ - SecKeyRef signingSecKey = [OTEscrowKeys createSecKey:item[(id)kSecValueData]]; - *signingKey = [[SFECKeyPair alloc] initWithSecKey:signingSecKey]; - CFReleaseNull(signingSecKey); - }else{ - secnotice("octagon", "unknown keychain item"); - } - } - if(*signingKey != nil && *encryptionKey != nil && *symmetricKey != nil){ - secnotice("octagon", "found escrow keys"); - result = YES; - }else{ - secerror("octagon: no matching escrow keys"); - } - - return result; -} - -@end -#endif diff --git a/keychain/ot/OTEstablishOperation.m b/keychain/ot/OTEstablishOperation.m index e9719e3d..cfb4a621 100644 --- a/keychain/ot/OTEstablishOperation.m +++ b/keychain/ot/OTEstablishOperation.m @@ -117,58 +117,51 @@ } secnotice("octagon-ckks", "Beginning establish with keys: %@", viewKeySets); - [[self.operationDependencies.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventEstablishIdentity withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] establishWithContainer:self.operationDependencies.containerName - context:self.operationDependencies.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:publicSigningSPKIs - reply:^(NSString * _Nullable peerID, NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventEstablishIdentity hardFailure:true result:error]; - if(error) { - secerror("octagon: Error calling establish: %@", error); + [self.operationDependencies.cuttlefishXPCWrapper establishWithContainer:self.operationDependencies.containerName + context:self.operationDependencies.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:publicSigningSPKIs + reply:^(NSString * _Nullable peerID, NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + + [[CKKSAnalytics logger] logResultForEvent:OctagonEventEstablishIdentity hardFailure:true result:error]; + if(error) { + secerror("octagon: Error calling establish: %@", error); + + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else { + self.error = error; + } + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); - self.nextState = self.ckksConflictState; + self.peerID = peerID; + + NSError* localError = nil; + BOOL persisted = [self.operationDependencies.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist results: %@", localError); + self.error = localError; } else { - self.error = error; + self.nextState = self.intendedState; } - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - self.peerID = peerID; - - NSError* localError = nil; - BOOL persisted = [self.operationDependencies.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist results: %@", localError); - self.error = localError; - } else { - self.nextState = self.intendedState; - } - - // Tell CKKS about our shiny new records! - for (id key in self.operationDependencies.viewManager.views) { - CKKSKeychainView* view = self.operationDependencies.viewManager.views[key]; - secnotice("octagon-ckks", "Providing records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + // Tell CKKS about our shiny new records! + for (id key in self.operationDependencies.viewManager.views) { + CKKSKeychainView* view = self.operationDependencies.viewManager.views[key]; + secnotice("octagon-ckks", "Providing records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTFetchViewsOperation.m b/keychain/ot/OTFetchViewsOperation.m index f041885c..cbe4e56a 100644 --- a/keychain/ot/OTFetchViewsOperation.m +++ b/keychain/ot/OTFetchViewsOperation.m @@ -59,47 +59,37 @@ if ([self.ckm useCKKSViewsFromPolicy]) { WEAKIFY(self); - NSXPCConnection* proxy = [self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [self.deps.cuttlefishXPCWrapper fetchPolicyWithContainer:self.deps.containerName context:self.deps.contextID reply:^(TPPolicy* _Nullable policy, NSError* _Nullable error) { STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventFetchViews withAttributes:nil]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - }]; - if (proxy) { - [proxy fetchPolicyWithContainer:self.deps.containerName context:self.deps.contextID reply:^(TPPolicy* _Nullable policy, NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon: failed to retrieve policy: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - if (policy == nil) { - secerror("octagon: no policy returned"); - } - self.policy = policy; - WEAKIFY(self); - NSArray* sosViews = [sosViewList allObjects]; - [proxy getViewsWithContainer:self.deps.containerName context:self.deps.contextID inViews:sosViews reply:^(NSArray* _Nullable outViews, NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon: failed to retrieve list of views: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + if (error) { + secerror("octagon: failed to retrieve policy: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + if (policy == nil) { + secerror("octagon: no policy returned"); + } + self.policy = policy; + NSArray* sosViews = [sosViewList allObjects]; + [self.deps.cuttlefishXPCWrapper getViewsWithContainer:self.deps.containerName context:self.deps.contextID inViews:sosViews reply:^(NSArray* _Nullable outViews, NSError* _Nullable error) { + STRONGIFY(self); + if (error) { + secerror("octagon: failed to retrieve list of views: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + if (outViews == nil) { + secerror("octagon: bad results from getviews"); } else { - if (outViews == nil) { - secerror("octagon: bad results from getviews"); - } else { - self.viewList = [NSSet setWithArray:outViews]; - } - [self complete]; + self.viewList = [NSSet setWithArray:outViews]; } - }]; - } - }]; - } + [self complete]; + } + }]; + } + }]; } else { [self complete]; } diff --git a/keychain/ot/OTFollowup.h b/keychain/ot/OTFollowup.h index f7aea060..e6f738ca 100644 --- a/keychain/ot/OTFollowup.h +++ b/keychain/ot/OTFollowup.h @@ -38,13 +38,7 @@ typedef NS_ENUM(uint8_t, OTFollowupContextType) { OTFollowupContextTypeStateRepair, OTFollowupContextTypeOfflinePasscodeChange, }; - -typedef NS_ENUM(uint8_t, OTFollowupStatus) { - OTFollowupStatusIdle = 0, - OTFollowupStatusSuccess = 1, - OTFollowupStatusFailed = 2, - OTFollowupStatusPending = 3, -}; +NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType); @protocol OctagonFollowUpControllerProtocol - (BOOL)postFollowUpWithContext:(CDPFollowUpContext *)context error:(NSError **)error; @@ -54,7 +48,6 @@ typedef NS_ENUM(uint8_t, OTFollowupStatus) { @end @interface OTFollowup : NSObject -@property (readonly) OTFollowupStatus followupStatus; - (id)initWithFollowupController:(id)cdpFollowupController; - (BOOL)postFollowUp:(OTFollowupContextType)contextType diff --git a/keychain/ot/OTFollowup.m b/keychain/ot/OTFollowup.m index ad73b695..419f399c 100644 --- a/keychain/ot/OTFollowup.m +++ b/keychain/ot/OTFollowup.m @@ -30,8 +30,6 @@ #define HAVE_COREFOLLOW_UP 1 #endif -#undef HAVE_COREFOLLOW_UP // XXX - #import #import @@ -39,6 +37,20 @@ static NSString * const kOTFollowupEventCompleteKey = @"OTFollowupContextType"; +NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType) +{ + switch(contextType) { + case OTFollowupContextTypeNone: + return @"none"; + case OTFollowupContextTypeRecoveryKeyRepair: + return @"recovery key"; + case OTFollowupContextTypeStateRepair: + return @"repair"; + case OTFollowupContextTypeOfflinePasscodeChange: + return @"offline passcode change"; + } +} + @interface OTFollowup() @property id cdpd; @property NSTimeInterval previousFollowupEnd; diff --git a/keychain/ot/OTIdentity.h b/keychain/ot/OTIdentity.h deleted file mode 100644 index 487cf7c2..00000000 --- a/keychain/ot/OTIdentity.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#include -NS_ASSUME_NONNULL_BEGIN - -@interface OTIdentity : NSObject - -@property (nonatomic, readonly) NSString* peerID; -@property (nonatomic, readonly) NSString* spID; -@property (nonatomic, readonly) SFECKeyPair* peerSigningKey; -@property (nonatomic, readonly) SFECKeyPair* peerEncryptionKey; - - -- (instancetype) initWithPeerID:(nullable NSString*)peerID - spID:(nullable NSString*)spID - peerSigningKey:(SFECKeyPair*)peerSigningKey - peerEncryptionkey:(SFECKeyPair*)peerEncryptionKey - error:(NSError**)error; - -+ (nullable instancetype) currentIdentityFromSOS:(NSError**)error; - --(BOOL)isEqual:(OTIdentity* _Nullable)identity; - - -+(BOOL) storeOctagonIdentityIntoKeychain:(_SFECKeyPair *)restoredSigningKey - restoredEncryptionKey:(_SFECKeyPair *)restoredEncryptionKey - escrowSigningPubKeyHash:(NSString *)escrowSigningPubKeyHash - restoredPeerID:(NSString *)peerID - error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTIdentity.m b/keychain/ot/OTIdentity.m deleted file mode 100644 index 616a2576..00000000 --- a/keychain/ot/OTIdentity.m +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import "OTIdentity.h" - -#import -#import -#import "keychain/ot/OTDefines.h" - -#import "keychain/SecureObjectSync/SOSAccountTransaction.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#import "keychain/SecureObjectSync/SOSAccount.h" -#pragma clang diagnostic pop - -@interface OTIdentity () - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) SFECKeyPair* peerEncryptionKey; - -@end - -@implementation OTIdentity - -- (instancetype) initWithPeerID:(nullable NSString*)peerID - spID:(nullable NSString*)spID - peerSigningKey:(SFECKeyPair*)peerSigningKey - peerEncryptionkey:(SFECKeyPair*)peerEncryptionKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _peerID = peerID; - _spID = spID; - _peerSigningKey = peerSigningKey; - _peerEncryptionKey = peerEncryptionKey; - } - return self; -} - -+ (nullable instancetype) currentIdentityFromSOS:(NSError**)error -{ - CFErrorRef circleCheckError = NULL; - SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(&circleCheckError); - if(circleStatus != kSOSCCInCircle){ - if(circleCheckError){ - secerror("octagon: cannot retrieve octagon keys from SOS, not in circle, error: %@", circleCheckError); - if(error){ - *error = (__bridge NSError*)circleCheckError; - } - } - secerror("octagon: current circle status: %d",circleStatus); - return nil; - } - __block NSString* sosPeerID = nil; - __block NSError* sosPeerIDError = nil; - - SOSCCPerformWithPeerID(^(CFStringRef peerID, CFErrorRef error) { - sosPeerID = (__bridge NSString *)(peerID); - if(error){ - secerror("octagon: retrieving sos peer id error: %@", error); - sosPeerIDError = CFBridgingRelease(error); - } - }); - - if(sosPeerID == nil || sosPeerIDError != nil){ - secerror("octagon: cannot retrieve peer id from SOS, error: %@", sosPeerIDError); - if(error){ - *error = sosPeerIDError; - } - return nil; - } - - __block SFECKeyPair *peerEncryptionKey; - __block SFECKeyPair *peerSigningKey; - __block NSError* localError = nil; - - SOSCCPerformWithAllOctagonKeys(^(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef cferror) { - if(cferror) { - localError = (__bridge NSError*)cferror; - return; - } - if (!cferror && octagonEncryptionKey && octagonSigningKey) { - peerSigningKey = [[SFECKeyPair alloc] initWithSecKey:octagonSigningKey]; - peerEncryptionKey = [[SFECKeyPair alloc] initWithSecKey:octagonEncryptionKey]; - - } - }); - - if(!peerEncryptionKey || !peerSigningKey || localError != nil){ - secerror("octagon: failed to retrieve octagon keys from sos: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - return [[OTIdentity alloc] initWithPeerID:nil - spID:sosPeerID - peerSigningKey:peerSigningKey - peerEncryptionkey:peerEncryptionKey - error:error]; -} - --(BOOL)isEqual:(OTIdentity*)identity -{ - return [self.peerID isEqualToString:identity.peerID] && - [self.spID isEqualToString:identity.spID] && - [self.peerSigningKey isEqual:identity.peerSigningKey] && - [self.peerEncryptionKey isEqual:identity.peerEncryptionKey]; -} - -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error -{ - BOOL result = NO; - - CFTypeRef results = NULL; - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results); - - NSError* localerror = nil; - - if(status == errSecDuplicateItem || status == errSecSuccess) { - result = YES; - } else { - localerror = [NSError errorWithDomain:@"securityd" - code:status - userInfo:nil]; - } - if(status != errSecSuccess) { - CFReleaseNull(results); - - if(error) { - *error = localerror; - } - } - - return result; -} - -+ (BOOL)storeOtagonKey:(NSData*)keyData - octagonKeyType:(OctagonKeyType)octagonKeyType - restoredPeerID:(NSString*)restoredPeerID - escrowSigningPubKeyHash:(NSString*)escrowSigningPubKeyHash - error:(NSError**)error -{ - NSNumber *keyType = [[NSNumber alloc]initWithInt:octagonKeyType]; - - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassInternetPassword, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrLabel : escrowSigningPubKeyHash, - (id)kSecAttrAccount : restoredPeerID, - (id)kSecAttrType : keyType, - (id)kSecAttrServer : (octagonKeyType == 1) ? @"Octagon Signing Key" : @"Octagon Encryption Key", - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecValueData : keyData, - }; - return [OTIdentity setKeyMaterialInKeychain:query error:error]; - -} - -+(BOOL) storeOctagonIdentityIntoKeychain:(_SFECKeyPair *)restoredSigningKey - restoredEncryptionKey:(_SFECKeyPair *)restoredEncryptionKey - escrowSigningPubKeyHash:(NSString *)escrowSigningPubKeyHash - restoredPeerID:(NSString *)peerID - error:(NSError**)error -{ - NSError* localError = nil; - - BOOL result = [OTIdentity storeOtagonKey:[restoredSigningKey keyData] octagonKeyType:OctagonSigningKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store octagon signing key in keychain:%@", localError); - if(error){ - *error = localError; - } - return NO; - } - result = [OTIdentity storeOtagonKey:[restoredEncryptionKey keyData] octagonKeyType:OctagonEncryptionKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store octagon encryption key in keychain:%@", localError); - if(error){ - *error = localError; - } - return NO; - } - return result; -} - -@end -#endif diff --git a/keychain/ot/OTJoinWithVoucherOperation.m b/keychain/ot/OTJoinWithVoucherOperation.m index b8fba538..f68765d5 100644 --- a/keychain/ot/OTJoinWithVoucherOperation.m +++ b/keychain/ot/OTJoinWithVoucherOperation.m @@ -43,10 +43,6 @@ @property OctagonState* ckksConflictState; @property NSOperation* finishedOp; -@property int retries; -@property int maxRetries; -@property int delay; -@property CKKSNearFutureScheduler* retrySched; @end @implementation OTJoinWithVoucherOperation @@ -64,10 +60,6 @@ if((self = [super init])) { _deps = dependencies; - _retries = 0; - _maxRetries = 5; - _delay = 1; - _intendedState = intendedState; _nextState = errorState; _ckksConflictState = ckksConflictState; @@ -102,107 +94,62 @@ [self runBeforeGroupFinished:proceedWithKeys]; } -- (BOOL)isRetryable:(NSError* _Nonnull)error { - return [error isCuttlefishError:CuttlefishErrorTransactionalFailure]; -} - -- (int)retryDelay:(NSError* _Nonnull)error { - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - int ret = self->_delay; - if (underlyingError) { - id tmp = underlyingError.userInfo[@"retryafter"]; - if ([tmp isKindOfClass:[NSNumber class]]) { - ret = [(NSNumber*)tmp intValue]; - } - } - ret = MAX(MIN(ret, 32), self->_delay); - self->_delay *= 2; - return ret; -} - - (void)proceedWithKeys:(NSArray*)viewKeySets pendingTLKShares:(NSArray*)pendingTLKShares { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] joinWithContainer:self.deps.containerName - context:self.deps.contextID - voucherData:self.voucherData - voucherSig:self.voucherSig - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:self.preapprovedKeys - reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { - if(error){ - secerror("octagon: Error joining with voucher: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; - - if (self.retries < self.maxRetries && [self isRetryable:error]) { - ++self.retries; - if (!self.retrySched) { - self.retrySched = [[CKKSNearFutureScheduler alloc] initWithName:@"cuttlefish-join-retry" - delay:1*NSEC_PER_SEC - keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"vouch-with-keys" - withBlock:^{ - STRONGIFY(self); - secnotice("octagon", "retrying (%d/%d) join", self.retries, self->_maxRetries); - [self proceedWithKeys:viewKeySets - pendingTLKShares:pendingTLKShares]; - }]; - STRONGIFY(self); - [self runBeforeGroupFinished:proceedWithKeys]; - }]; + [self.deps.cuttlefishXPCWrapper joinWithContainer:self.deps.containerName + context:self.deps.contextID + voucherData:self.voucherData + voucherSig:self.voucherSig + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:self.preapprovedKeys + reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + if(error){ + secerror("octagon: Error joining with voucher: %@", error); + [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; + + // IF this is a CKKS conflict error, don't retry + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; going to state '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else if ([error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { + secnotice("octagon", "requesting cuttlefish health check"); + self.nextState = OctagonStateCuttlefishTrustCheck; + self.error = error; + } else { + self.error = error; } - int delay_s = [self retryDelay:error]; - [self.retrySched waitUntil:delay_s*NSEC_PER_SEC]; - [self.retrySched trigger]; - return; - } - - // IF this is a CKKS conflict error, don't retry - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; going to state '%@'", self.ckksConflictState); - self.nextState = self.ckksConflictState; - } else { - self.error = error; - } - } else { - self.peerID = peerID; - - [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventJoinWithVoucher]; - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist results: %@", localError); - self.error = localError; } else { - secerror("octagon: join successful"); - self.nextState = self.intendedState; - } + self.peerID = peerID; + + [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventJoinWithVoucher]; + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist results: %@", localError); + self.error = localError; + } else { + secerror("octagon: join successful"); + self.nextState = self.intendedState; + } - // Tell CKKS about our shiny new records! - for (id key in self.deps.viewManager.views) { - CKKSKeychainView* view = self.deps.viewManager.views[key]; - secnotice("octagon-ckks", "Providing join() records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; + // Tell CKKS about our shiny new records! + for (id key in self.deps.viewManager.views) { + CKKSKeychainView* view = self.deps.viewManager.views[key]; + secnotice("octagon-ckks", "Providing join() records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } } - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLeaveCliqueOperation.m b/keychain/ot/OTLeaveCliqueOperation.m index e61e9b2f..af8ad2eb 100644 --- a/keychain/ot/OTLeaveCliqueOperation.m +++ b/keychain/ot/OTLeaveCliqueOperation.m @@ -58,34 +58,28 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper departByDistrustingSelfWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to depart for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); + self.error = error; + } else { + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistNewTrustState:OTAccountMetadataClassC_TrustState_UNTRUSTED + error:&localError]; + if(!persisted || localError) { + secerror("octagon: unable to persist clique departure: %@", localError); + self.error = localError; + } else { + secnotice("octagon", "Successfully departed clique"); + self.nextState = self.intendedState; + } + } - }] departByDistrustingSelfWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to depart for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); - self.error = error; - } else { - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistNewTrustState:OTAccountMetadataClassC_TrustState_UNTRUSTED - error:&localError]; - if(!persisted || localError) { - secerror("octagon: unable to persist clique departure: %@", localError); - self.error = localError; - } else { - secnotice("octagon", "Successfully departed clique"); - self.nextState = self.intendedState; - } - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLocalCuttlefishReset.h b/keychain/ot/OTLocalCuttlefishReset.h index 9e1b59bf..90011df7 100644 --- a/keychain/ot/OTLocalCuttlefishReset.h +++ b/keychain/ot/OTLocalCuttlefishReset.h @@ -27,6 +27,7 @@ #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" NS_ASSUME_NONNULL_BEGIN @@ -36,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN contextID:(NSString*)contextID intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC; +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTLocalCuttlefishReset.m b/keychain/ot/OTLocalCuttlefishReset.m index 91a49b21..30cd3608 100644 --- a/keychain/ot/OTLocalCuttlefishReset.m +++ b/keychain/ot/OTLocalCuttlefishReset.m @@ -32,8 +32,7 @@ @interface OTLocalResetOperation () @property NSString* containerName; @property NSString* contextID; -@property id cuttlefishXPC; - +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property NSOperation* finishedOp; @end @@ -45,7 +44,7 @@ contextID:(NSString*)contextID intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; @@ -53,7 +52,7 @@ _containerName = containerName; _contextID = contextID; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; } return self; } @@ -66,26 +65,20 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] localResetWithContainer:self.containerName - context:self.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.containerName, self.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully reset local cuttlefish"); - self.nextState = self.intendedState; - } + [self.cuttlefishXPCWrapper localResetWithContainer:self.containerName + context:self.contextID + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.containerName, self.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully reset local cuttlefish"); + self.nextState = self.intendedState; + } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLocalStore.h b/keychain/ot/OTLocalStore.h deleted file mode 100644 index 74c4fa09..00000000 --- a/keychain/ot/OTLocalStore.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef OTLocalStore_h -#define OTLocalStore_h -#if OCTAGON - -#import -#import -#import -#import "keychain/ot/OTBottledPeerRecord.h" -#import "keychain/ot/OTContextRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTLocalStore : NSObject - -@property (nonatomic, readonly) NSString* dbPath; -@property (nonatomic, readonly) PQLConnection* pDB; -@property (nonatomic, readonly) dispatch_queue_t serialQ; -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) sqlite3* _db; - --(instancetype) initWithContextID:(NSString*)contextID dsid:(NSString*)dsid path:(nullable NSString*)path error:(NSError**)error; - --(BOOL)isProposedColumnNameInTable:(NSString*)proposedColumnName tableName:(NSString*)tableName; - -// OT Context Record routines --(BOOL)initializeContextTable:(NSString*)contextID dsid:(NSString*)dsid error:(NSError**)error; --(OTContextRecord* _Nullable)readLocalContextRecordForContextIDAndDSID:(NSString*)contextAndDSID error:(NSError**)error; --(BOOL)insertLocalContextRecord:(NSDictionary*)attributes error:(NSError**)error; --(BOOL)updateLocalContextRecordRowWithContextID:(NSString*)contextIDAndDSID columnName:(NSString*)columnName newValue:(void*)newValue error:(NSError**)error; --(BOOL)deleteLocalContext:(NSString*)contextIDAndDSID error:(NSError**)error; --(BOOL) deleteAllContexts:(NSError**)error; - -//OT Bottled Peer routines -- (nullable OTBottledPeerRecord *)readLocalBottledPeerRecordWithRecordID:(NSString *)recordID - error:(NSError**)error; -- (nullable NSArray*) readAllLocalBottledPeerRecords:(NSError**)error; --(BOOL)deleteBottledPeer:(NSString*) recordID error:(NSError**)error; --(BOOL) deleteBottledPeersForContextAndDSID:(NSString*)contextIDAndDSID - error:(NSError**)error; --(BOOL)removeAllBottledPeerRecords:(NSError**)error; --(BOOL)insertBottledPeerRecord:(OTBottledPeerRecord *)bp - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error; -- (nullable NSArray*) readLocalBottledPeerRecordsWithMatchingPeerID:(NSString*)peerID error:(NSError**)error; - -// generic DB routines --(BOOL)openDBWithError:(NSError**)error; --(BOOL)closeDBWithError:(NSError**)error;; --(BOOL)createDirectoryAtPath:(NSString*)path error:(NSError **)error; -@end -NS_ASSUME_NONNULL_END -#endif -#endif /* OTLocalStore_h */ diff --git a/keychain/ot/OTLocalStore.m b/keychain/ot/OTLocalStore.m deleted file mode 100644 index e859c337..00000000 --- a/keychain/ot/OTLocalStore.m +++ /dev/null @@ -1,684 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#if OCTAGON - -#import -#import -#import -#import -#include -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTConstants.h" -#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR -#include -#else -#include -#endif - -#import "OTLocalStore.h" -#import "OTBottledPeerSigned.h" - -static NSString* const contextSchema = @"create table if not exists context (contextIDAndDSID text primary key, contextID text, accountDSID text, contextName text, zoneCreated boolean, subscribedToChanges boolean, changeToken blob, egoPeerID text, egoPeerCreationDate date, recoverySigningSPKI text, recoveryEncryptionSPKI text);"; - -static NSString* const bottledPeerSchema = @"create table if not exists bp (bottledPeerRecordID text primary key, contextIDAndDSID text, escrowRecordID text, peerID text, spID text, bottle text, escrowSigningSPKI text, peerSigningSPKI text, signatureUsingEscrow text, signatureUsingPeerKey text, encodedRecord text, launched text);"; - -static const NSInteger user_version = 0; - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextAndDSID = @"contextIDAndDSID"; -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordBottle = @"bottle"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordEncodedRecord = @"encodedRecord"; -static NSString* OTCKRecordLaunched = @"launched"; - -/* Octagon Table Names */ -static NSString* const contextTable = @"context"; -static NSString* const peerTable = @"peer"; -static NSString* const bottledPeerTable = @"bp"; - -/* Octagon Trust Schemas */ -static NSString* const octagonZoctagonErrorDomainoneName = @"OctagonTrustZone"; - -/* Octagon Cloud Kit defines */ -static NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* OTCKRecordName = @"bp-"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -static NSArray* _Nullable selectAll(PQLResultSet *rs, Class class) -{ - NSMutableArray *arr = [NSMutableArray array]; - for (id o in [rs enumerateObjectsOfClass:class]) { - [arr addObject:o]; - } - if (rs.error) { - return nil; - } - return arr; -} -#define selectArrays(db, sql, ...) \ -selectAll([db fetch:sql, ##__VA_ARGS__], [NSArray class]) - -#define selectDictionaries(db, sql, ...) \ -selectAll([db fetch:sql, ##__VA_ARGS__], [NSDictionary class]) - - -@interface NSDictionary (PQLResultSetInitializer) -@end -@implementation NSDictionary (PQLResultSetInitializer) -- (instancetype)initFromPQLResultSet:(PQLResultSet *)rs - error:(NSError **)error -{ - NSUInteger cols = rs.columns; - NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:cols]; - - for (NSUInteger i = 0; i < cols; i++) { - id obj = rs[i]; - if (obj) { - dict[[rs columnNameAtIndex:(int)i]] = obj; - } - } - - return [self initWithDictionary:dict]; -} -@end - - -@implementation OTLocalStore - --(instancetype) initWithContextID:(NSString*)contextID dsid:(NSString*)dsid path:(nullable NSString*)path error:(NSError**)error -{ - self = [super init]; - if(self){ - if (!path) { - NSURL* urlPath = (__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"otdb.db"); - path = [urlPath path]; - } - _dbPath = [path copy]; - _pDB = [[PQLConnection alloc] init]; - _contextID = [contextID copy]; - _dsid = [dsid copy]; - _serialQ = dispatch_queue_create("com.apple.security.ot.db", DISPATCH_QUEUE_SERIAL); - - NSError* localError = nil; - if(![self openDBWithError:&localError]) - { - secerror("octagon: could not open db: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - } - return self; -} - -- (BOOL) createDirectoryAtPath:(NSString*)path error:(NSError **)error -{ - BOOL success = YES; - NSError *localError; - NSFileManager *fileManager = [NSFileManager defaultManager]; - - if (![fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&localError]) { - if (![localError.domain isEqualToString:NSCocoaErrorDomain] || localError.code != NSFileWriteFileExistsError) { - success = NO; - if(error){ - *error = localError; - } - } - } - -#if TARGET_OS_IPHONE - if (success) { - NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:&localError]; - if (![attributes[NSFileProtectionKey] isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) { - [fileManager setAttributes:@{ NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication } - ofItemAtPath:path error:&localError]; - } - } -#endif - if (!success) { - if (error) *error = localError; - } - return success; -} - --(BOOL)openDBWithError:(NSError**)error -{ - BOOL result = NO; - NSError *localError = nil; - - if(!(result = [_pDB openAtURL:[NSURL URLWithString:_dbPath] sharedCache:NO error:&localError])){ - secerror("octagon: could not open db: %@", localError); - if(error){ - *error = localError; - } - return NO; - } - if(![_pDB execute:bottledPeerSchema]){ - secerror("octagon: could not create bottled peer schema"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEntropyCreationFailure userInfo:@{NSLocalizedDescriptionKey: @"could not create bottled peer schema"}]; - } - result = NO; - } - if(![_pDB execute:contextSchema]){ - secerror("octagon: could not create contextschema"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not create context schema"}]; - } - result = NO; - } - if(![_pDB setupPragmas]){ - secerror("octagon: could not set up db pragmas"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not set up db pragmas"}]; - } - result = NO; - } - if(![_pDB setUserVersion:user_version]){ - secerror("octagon: could not set version"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not set version"}]; - } - result = NO; - } - return result; -} - --(BOOL)closeDBWithError:(NSError**)error -{ - BOOL result = NO; - NSError *localError = nil; - - if(!(result =[_pDB close:&localError])){ - secerror("octagon: could not close db: %@", localError); - if(error){ - *error = localError; - } - } - return result; -} - --(BOOL)isProposedColumnNameInTable:(NSString*)proposedColumnName tableName:(NSString*)tableName -{ - BOOL result = NO; - - if([tableName isEqualToString:contextTable]) - { - if([proposedColumnName isEqualToString:OTCKRecordContextAndDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordContextID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordContextName]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordZoneCreated]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSubscribedToChanges]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordChangeToken]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEgoPeerID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEgoPeerCreationDate]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecoverySigningSPKI]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecoveryEncryptionSPKI]){ - result = YES; - } - else{ - secerror("octagon: column name unknown: %@", proposedColumnName); - } - } - else if([tableName isEqualToString:peerTable]){ //not using yet! - result = NO; - secerror("octagon: not using this table yet!"); - } - else if([tableName isEqualToString:bottledPeerTable]) - { - if([proposedColumnName isEqualToString:OTCKRecordContextAndDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecordID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEscrowRecordID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSPID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordPeerID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordBottle]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSignatureFromEscrow]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSignatureFromPeerKey]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEncodedRecord]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordLaunched]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordPeerSigningSPKI]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEscrowSigningSPKI]){ - result = YES; - } - else{ - secerror("octagon: column name unknown: %@", proposedColumnName); - } - } - else{ - secerror("octagon: table name unknown: %@", tableName); - } - return result; -} - -///// -// Local Context Record -///// --(OTContextRecord* _Nullable)readLocalContextRecordForContextIDAndDSID:(NSString*)contextAndDSID error:(NSError**)error -{ - OTContextRecord* record = [[OTContextRecord alloc]init]; - NSDictionary* attributes = nil; - NSArray *selectArray = nil; - - selectArray = selectDictionaries(_pDB, @"SELECT * from context WHERE contextIDAndDSID == %@;", PQLName(contextAndDSID)); - if(selectArray && [selectArray count] > 0){ - attributes = [selectArray objectAtIndex:0]; - } - if(attributes && [attributes count] > 0){ - record.contextID = attributes[OTCKRecordContextID]; - record.dsid = attributes[OTCKRecordDSID]; - record.contextName = attributes[OTCKRecordContextName]; - record.zoneCreated = (BOOL)attributes[OTCKRecordZoneCreated]; - record.subscribedToChanges = (BOOL)attributes[OTCKRecordSubscribedToChanges]; - record.changeToken = attributes[OTCKRecordChangeToken]; - record.egoPeerID = attributes[OTCKRecordEgoPeerID]; - record.egoPeerCreationDate = attributes[OTCKRecordEgoPeerCreationDate]; - record.recoverySigningSPKI = dataFromBase64(attributes[OTCKRecordRecoverySigningSPKI]); - record.recoveryEncryptionSPKI = dataFromBase64(attributes[OTCKRecordRecoveryEncryptionSPKI]); - } - else{ - secerror("octagon: no context attributes found"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"no context attributes found"}]; - } - } - - return record; -} - --(BOOL)initializeContextTable:(NSString*)contextID dsid:(NSString*)dsid error:(NSError**)error -{ - BOOL result = NO; - NSError* localError = nil; - NSString* contextName = nil; -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - contextName = (__bridge_transfer NSString *)MGCopyAnswer(kMGQUserAssignedDeviceName, NULL); -#else - contextName = (__bridge_transfer NSString *)SCDynamicStoreCopyComputerName(NULL, NULL); -#endif - - NSDictionary *contextAttributes = @{ - OTCKRecordContextAndDSID : [NSString stringWithFormat:@"%@-%@", contextID, dsid], - OTCKRecordContextID : contextID, - OTCKRecordDSID : dsid, - OTCKRecordContextName : contextName, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"ego peer id", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [NSData data], - OTCKRecordRecoveryEncryptionSPKI : [NSData data]}; - - result = [self insertLocalContextRecord:contextAttributes error:&localError]; - if(!result || localError != nil){ - secerror("octagon: context table init failed: %@", localError); - if(error){ - *error = localError; - } - } - return result; -} - --(BOOL)insertLocalContextRecord:(NSDictionary*)attributes error:(NSError**)error -{ - BOOL result = NO; - - NSString* dsidAndContext = [NSString stringWithFormat:@"%@-%@", attributes[OTCKRecordContextID], attributes[OTCKRecordDSID]]; - result = [_pDB execute:@"insert into context (contextIDAndDSID, contextID, accountDSID, contextName, zoneCreated, subscribedToChanges, changeToken, egoPeerID, egoPeerCreationDate, recoverySigningSPKI, recoveryEncryptionSPKI) values (%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@)", - dsidAndContext, attributes[OTCKRecordContextID], attributes[OTCKRecordDSID], attributes[OTCKRecordContextName], attributes[OTCKRecordZoneCreated], - attributes[OTCKRecordSubscribedToChanges], attributes[OTCKRecordChangeToken], - attributes[OTCKRecordEgoPeerID], attributes[OTCKRecordEgoPeerCreationDate], - [attributes[OTCKRecordRecoverySigningSPKI] base64EncodedStringWithOptions:0], [attributes[OTCKRecordRecoveryEncryptionSPKI] base64EncodedStringWithOptions:0]]; - - - if(_pDB.lastError){ - secerror("octagon: failed to insert local context: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL)updateLocalContextRecordRowWithContextID:(NSString*)contextIDAndDSID columnName:(NSString*)columnName newValue:(void*)newValue error:(NSError**)error -{ - BOOL result = NO; - if([self isProposedColumnNameInTable:columnName tableName:contextTable]){ - result = [_pDB execute:@"update context set %@ = %@ where contextIDAndDSID == %@", - PQLName(columnName), newValue, PQLName(_contextID)]; - if(!result && error){ - secerror("octagon: error updating table: %@", _pDB.lastError); - *error = _pDB.lastError; - } - } - else{ - secerror("octagon: failed to update local context record: %@", _pDB.lastError); - - if(error != nil){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorNoColumn userInfo:nil]; - } - } - return result; -} - --(BOOL) deleteLocalContext:(NSString*)contextIDAndDSID error:(NSError**)error -{ - BOOL result = NO; - secnotice("octagon", "deleting local context: %@", contextIDAndDSID); - - result = [_pDB execute:@"delete from context where contextIDAndDSID == %@", - PQLName(contextIDAndDSID)]; - - if(!result){ - secerror("octagon: error updating table: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteAllContexts:(NSError**)error -{ - BOOL result = NO; - secnotice("octagon", "deleting all local context"); - - result = [_pDB execute:@"delete from context"]; - - if(!result){ - secerror("octagon: error updating table: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - -///// -// Local Bottled Peer Record -///// - -- (BOOL) insertBottledPeerRecord:(OTBottledPeerRecord *)rec - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error -{ - BOOL result; - - result = [_pDB execute:@"insert or replace into bp (bottledPeerRecordID, contextIDAndDSID, escrowRecordID, peerID, spID, bottle, escrowSigningSPKI, peerSigningSPKI, signatureUsingEscrow, signatureUsingPeerKey, encodedRecord, launched) values (%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@)", - rec.recordName, - [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], - escrowRecordID, - rec.peerID, - rec.spID, - [rec.bottle base64EncodedStringWithOptions:0], - [rec.escrowedSigningSPKI base64EncodedStringWithOptions:0], - [rec.peerSigningSPKI base64EncodedStringWithOptions:0], - [rec.signatureUsingEscrowKey base64EncodedStringWithOptions:0], - [rec.signatureUsingPeerKey base64EncodedStringWithOptions:0], - [rec.encodedRecord base64EncodedStringWithOptions:0], - rec.launched]; - - if (!result) { - secerror("octagon: error inserting bottled peer record: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) removeAllBottledPeerRecords:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid]]; - - if (!result) { - secerror("octagon: error removing bottled peer records: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteBottledPeer:(NSString*) recordID - error:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@ AND bottledPeerRecordID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], recordID]; - - if (!result) { - secerror("octagon: error removing bottled peer record:%@, error: %@", recordID, _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteBottledPeersForContextAndDSID:(NSString*) contextIDAndDSID - error:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@;", contextIDAndDSID]; - - if (!result) { - secerror("octagon: error removing bottled peer record:%@, error: %@", contextIDAndDSID, _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - -- (nullable OTBottledPeerRecord *)readLocalBottledPeerRecordWithRecordID:(NSString *)recordID - error:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp WHERE contextIDAndDSID == %@ AND bottledPeerRecordID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], recordID); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entry for %@", recordID); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] > 1) { - secerror("octagon: error multiple records exist in local store for %@", recordID); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"error multiple records exist in local store"}]; - } - return nil; - } - else if([selectArray count] == 0){ - secerror("octagon: record does not exist: %@", recordID); - return nil; - } - NSDictionary *attributes = [selectArray objectAtIndex:0]; - - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.escrowRecordID = attributes[OTCKRecordEscrowRecordID]; - rec.peerID = attributes[OTCKRecordPeerID]; - rec.spID = attributes[OTCKRecordSPID]; - rec.bottle = dataFromBase64(attributes[OTCKRecordBottle]); - rec.escrowedSigningSPKI = dataFromBase64(attributes[OTCKRecordEscrowSigningSPKI]); - rec.peerSigningSPKI = dataFromBase64(attributes[OTCKRecordPeerSigningSPKI]); - rec.signatureUsingEscrowKey = dataFromBase64(attributes[OTCKRecordSignatureFromEscrow]); - rec.signatureUsingPeerKey = dataFromBase64(attributes[OTCKRecordSignatureFromPeerKey]); - rec.encodedRecord = dataFromBase64(attributes[OTCKRecordEncodedRecord]); - rec.launched = attributes[OTCKRecordLaunched]; - return rec; -} - -- (NSMutableArray*) convertResultsToBottles:(NSArray*) selectArray -{ - NSMutableArray *arrayOfBottleRecords = [NSMutableArray array]; - for(NSDictionary* bottle in selectArray){ - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.escrowRecordID = bottle[OTCKRecordEscrowRecordID]; - rec.peerID = bottle[OTCKRecordPeerID]; - rec.spID = bottle[OTCKRecordSPID]; - rec.bottle = dataFromBase64(bottle[OTCKRecordBottle]); - rec.escrowedSigningSPKI = dataFromBase64(bottle[OTCKRecordEscrowSigningSPKI]); - rec.peerSigningSPKI = dataFromBase64(bottle[OTCKRecordPeerSigningSPKI]); - rec.signatureUsingEscrowKey = dataFromBase64(bottle[OTCKRecordSignatureFromEscrow]); - rec.signatureUsingPeerKey = dataFromBase64(bottle[OTCKRecordSignatureFromPeerKey]); - rec.encodedRecord = dataFromBase64(bottle[OTCKRecordEncodedRecord]); - rec.launched = bottle[OTCKRecordLaunched]; - - [arrayOfBottleRecords addObject:rec]; - } - return arrayOfBottleRecords; -} - -- (nullable NSArray*) readAllLocalBottledPeerRecords:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp where contextIDAndDSID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid]); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entries"); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] == 0) { - secerror("octagon: there are no bottled peer entries in local store"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"there are no bottled peer entries in local store"}]; - } - return nil; - } - - return [self convertResultsToBottles:selectArray]; -} - -- (nullable NSArray*) readLocalBottledPeerRecordsWithMatchingPeerID:(NSString*)peerID error:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp where spID == %@;", peerID); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entries"); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] == 0) { - secerror("octagon: there are no bottled peer entries in local store"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"there are no bottled peer entries in local store"}]; - } - return nil; - } - - return [self convertResultsToBottles:selectArray]; -} - -static NSData * _Nullable dataFromBase64(NSString * _Nullable base64) -{ - if (base64 && [base64 length] > 0) { - return [[NSData alloc] initWithBase64EncodedString:base64 options:0]; - } - return nil; -} - -@end -#endif diff --git a/keychain/ot/OTManager.h b/keychain/ot/OTManager.h index e5eee25d..88a1820f 100644 --- a/keychain/ot/OTManager.h +++ b/keychain/ot/OTManager.h @@ -27,7 +27,7 @@ #if OCTAGON #import "Analytics/SFAnalytics.h" #import "keychain/ot/OTManager.h" -#import "keychain/ot/OTContext.h" +#import "keychain/ot/OTRamping.h" #import "keychain/ot/OTFollowup.h" #import "keychain/ot/OTControlProtocol.h" #import "keychain/ot/OTSOSAdapter.h" @@ -36,7 +36,7 @@ #import "keychain/ot/OTCuttlefishAccountStateHolder.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" #import "keychain/ckks/CKKSAccountStateTracker.h" -#include +#include "keychain/securityd/SecDbItem.h" #import NS_ASSUME_NONNULL_BEGIN @@ -48,39 +48,31 @@ NS_ASSUME_NONNULL_BEGIN @interface OTManager : NSObject -@property (nonatomic, readonly) NSDate *lastPostedCoreFollowUp; @property (nonatomic, readonly) CKKSLockStateTracker* lockStateTracker; @property id accountStateTracker; --(instancetype)init; - --(instancetype) initWithContext:(OTContext* _Nullable)context - localStore:(OTLocalStore* _Nullable)localStore - enroll:(OTRamp* _Nullable)enroll - restore:(OTRamp* _Nullable)restore - cfu:(OTRamp* _Nullable)cfu - cfuScheduler:(CKKSNearFutureScheduler* _Nullable)cfuScheduler - sosAdapter:(id)sosAdapter - authKitAdapter:(id)authKitAdapter - deviceInformationAdapter:(id)deviceInformationAdapter - apsConnectionClass:(Class)apsConnectionClass - escrowRequestClass:(Class)escrowRequestClass - loggerClass:(Class _Nullable)loggerClass - lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker - accountStateTracker:(id)accountStateTracker - cuttlefishXPCConnection:(id _Nullable)cuttlefishXPCConnection - cdpd:(id)cdpd; +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithSOSAdapter:(id)sosAdapter + authKitAdapter:(id)authKitAdapter + deviceInformationAdapter:(id)deviceInformationAdapter + apsConnectionClass:(Class)apsConnectionClass + escrowRequestClass:(Class)escrowRequestClass + loggerClass:(Class _Nullable)loggerClass + lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker + accountStateTracker:(id)accountStateTracker + cuttlefishXPCConnection:(id _Nullable)cuttlefishXPCConnection + cdpd:(id)cdpd; // Call this to start up the state machinery - (void)initializeOctagon; -- (void) moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context; +- (BOOL)waitForReady:(NSString* _Nullable)containerName context:(NSString*)context wait:(int64_t)wait; +- (void)moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context; + (instancetype _Nullable)manager; + (instancetype _Nullable)resetManager:(bool)reset to:(OTManager* _Nullable)obj; - (void)xpc24HrNotification:(NSString* _Nullable)containerName context:(NSString*)context skipRateLimitingCheck:(BOOL)skipRateLimitingCheck reply:(void (^)(NSError *error))reply; --(BOOL)scheduledCloudKitRampCheck:(NSError**)error; - - (OTCuttlefishContext*)contextForContainerName:(NSString* _Nullable)containerName contextID:(NSString*)contextID sosAdapter:(id)sosAdapter diff --git a/keychain/ot/OTManager.m b/keychain/ot/OTManager.m index 4e6f4461..323919c1 100644 --- a/keychain/ot/OTManager.m +++ b/keychain/ot/OTManager.m @@ -32,13 +32,11 @@ #import "keychain/ot/OTControlProtocol.h" #import "keychain/ot/OTControl.h" #import "keychain/ot/OTClique.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTManager.h" #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTRamping.h" #import "keychain/ot/OT.h" #import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTBottledPeerState.h" #import "keychain/ot/OTCuttlefishContext.h" #import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTStates.h" @@ -102,19 +100,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; @end #endif -@interface OTManager () +@interface OTManager () @property NSXPCListener *listener; -@property (nonatomic, strong) OTContext* context; -@property (nonatomic, strong) OTLocalStore *localStore; -@property (nonatomic, strong) OTRamp *enrollRamp; -@property (nonatomic, strong) OTRamp *restoreRamp; -@property (nonatomic, strong) OTRamp *cfuRamp; + @property (nonatomic, strong) OTRamp *gbmidRamp; @property (nonatomic, strong) OTRamp *gbserialRamp; @property (nonatomic, strong) OTRamp *gbAgeRamp; -@property (nonatomic, strong) CKKSNearFutureScheduler *cfuScheduler; -@property (nonatomic, strong) NSDate *lastPostedCoreFollowUp; -@property (nonatomic, strong) OTBottledPeerState *bottleState; @property (nonatomic, strong) CKKSLockStateTracker *lockStateTracker; @property (nonatomic, strong) id cdpd; @@ -142,82 +133,45 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; @synthesize authKitAdapter = _authKitAdapter; @synthesize deviceInformationAdapter = _deviceInformationAdapter; --(instancetype)init +- (instancetype)init { - OTLocalStore* localStore = nil; - OTContext* context = nil; - - NSString* dsid = [self askAccountsForDSID]; - if(dsid){ - localStore = [[OTLocalStore alloc]initWithContextID:OTDefaultContext dsid:dsid path:nil error:nil]; - context = [[OTContext alloc]initWithContextID:OTDefaultContext dsid:dsid localStore:self.localStore cloudStore:nil identityProvider:self error:nil]; - } - //initialize our scheduler - CKKSNearFutureScheduler *cfuScheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"scheduling-cfu" initialDelay:NUM_NSECS_IN_24_HRS continuingDelay:NUM_NSECS_IN_24_HRS keepProcessAlive:true dependencyDescriptionCode:CKKSResultDescriptionNone block:^{ - secnotice("octagon", "running scheduled cfu block"); - NSError* error = nil; - [self scheduledCloudKitRampCheck:&error]; - }]; - - //initialize our ramp objects - [self initRamps]; - // Under Octagon, the sos adatper is not considered essential. id sosAdapter = (OctagonPlatformSupportsSOS() ? [[OTSOSActualAdapter alloc] initAsEssential:NO] : [[OTSOSMissingAdapter alloc] init]); - return [self initWithContext:context - localStore:localStore - enroll:self.enrollRamp - restore:self.restoreRamp - cfu:self.cfuRamp - cfuScheduler:cfuScheduler - sosAdapter:sosAdapter - authKitAdapter:[[OTAuthKitActualAdapter alloc] init] - deviceInformationAdapter:[[OTDeviceInformationActualAdapter alloc] init] - apsConnectionClass:[APSConnection class] - escrowRequestClass:[EscrowRequestServer class] // Use the server class here to skip the XPC layer - loggerClass:[CKKSAnalytics class] - lockStateTracker:[CKKSLockStateTracker globalTracker] - // The use of CKKS's account tracker here is an inversion, and will be fixed with CKKS-for-all when we - // have Octagon own the CKKS objects - accountStateTracker:[CKKSViewManager manager].accountTracker - cuttlefishXPCConnection:nil - cdpd:[[CDPFollowUpController alloc] init]]; -} - --(instancetype) initWithContext:(OTContext*)context - localStore:(OTLocalStore*)localStore - enroll:(OTRamp*)enroll - restore:(OTRamp*)restore - cfu:(OTRamp*)cfu - cfuScheduler:(CKKSNearFutureScheduler*)cfuScheduler - sosAdapter:(id)sosAdapter - authKitAdapter:(id)authKitAdapter - deviceInformationAdapter:(id)deviceInformationAdapter - apsConnectionClass:(Class)apsConnectionClass - escrowRequestClass:(Class)escrowRequestClass - loggerClass:(Class)loggerClass - lockStateTracker:(CKKSLockStateTracker*)lockStateTracker - accountStateTracker:(id)accountStateTracker - cuttlefishXPCConnection:(id)cuttlefishXPCConnection - cdpd:(id)cdpd + return [self initWithSOSAdapter:sosAdapter + authKitAdapter:[[OTAuthKitActualAdapter alloc] init] + deviceInformationAdapter:[[OTDeviceInformationActualAdapter alloc] init] + apsConnectionClass:[APSConnection class] + escrowRequestClass:[EscrowRequestServer class] // Use the server class here to skip the XPC layer + loggerClass:[CKKSAnalytics class] + lockStateTracker:[CKKSLockStateTracker globalTracker] + // The use of CKKS's account tracker here is an inversion, and will be fixed with CKKS-for-all when we + // have Octagon own the CKKS objects + accountStateTracker:[CKKSViewManager manager].accountTracker + cuttlefishXPCConnection:nil + cdpd:[[CDPFollowUpController alloc] init]]; +} + +-(instancetype)initWithSOSAdapter:(id)sosAdapter + authKitAdapter:(id)authKitAdapter + deviceInformationAdapter:(id)deviceInformationAdapter + apsConnectionClass:(Class)apsConnectionClass + escrowRequestClass:(Class)escrowRequestClass + loggerClass:(Class)loggerClass + lockStateTracker:(CKKSLockStateTracker*)lockStateTracker + accountStateTracker:(id)accountStateTracker + cuttlefishXPCConnection:(id)cuttlefishXPCConnection + cdpd:(id)cdpd { - self = [super init]; - if(self){ - self.context = context; - self.localStore = localStore; - self.cfuRamp = cfu; - self.enrollRamp = enroll; - self.restoreRamp = restore; + if((self = [super init])) { _sosAdapter = sosAdapter; _authKitAdapter = authKitAdapter; _deviceInformationAdapter = deviceInformationAdapter; _loggerClass = loggerClass; _lockStateTracker = lockStateTracker; _accountStateTracker = accountStateTracker; - self.cfuScheduler = cfuScheduler; _sosEnabledForPlatform = OctagonPlatformSupportsSOS(); _cuttlefishXPCConnection = cuttlefishXPCConnection; @@ -258,6 +212,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; } } +- (BOOL)waitForReady:(NSString* _Nullable)containerName context:(NSString*)context wait:(int64_t)wait +{ + OTCuttlefishContext* c = [self contextForContainerName:containerName contextID:context]; + return [c waitForReady:wait]; +} + - (void) moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context { OTCuttlefishContext* c = [self contextForContainerName:containerName @@ -324,10 +284,8 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; return manager; } --(BOOL) initRamps +- (void)ensureRampsInitialized { - BOOL initResult = NO; - CKContainer* container = [CKKSViewManager manager].container; CKDatabase* database = [container privateCloudDatabase]; CKRecordZoneID* zoneID = [[CKRecordZoneID alloc] initWithZoneName:kOTRampZoneName ownerName:CKCurrentUserDefaultName]; @@ -336,104 +294,41 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; CKKSReachabilityTracker *reachabilityTracker = [CKKSViewManager manager].reachabilityTracker; CKKSLockStateTracker *lockStateTracker = [CKKSViewManager manager].lockStateTracker; - self.cfuRamp = [[OTRamp alloc]initWithRecordName:kOTRampForCFURecordName - localSettingName:@"cfu" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.enrollRamp = [[OTRamp alloc]initWithRecordName:kOTRampForEnrollmentRecordName - localSettingName:@"enroll" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - - self.restoreRamp = [[OTRamp alloc]initWithRecordName:kOTRampForRestoreRecordName - localSettingName:@"restore" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbmidRamp = [[OTRamp alloc]initWithRecordName:kOTRampForGhostBustMIDName - localSettingName:@"ghostBustMID" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbserialRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustSerialName - localSettingName:@"ghostBustSerial" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbAgeRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustAgeName - localSettingName:@"ghostBustAge" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - if(self.cfuRamp && self.enrollRamp && self.restoreRamp && self.gbmidRamp && self.gbserialRamp && self.gbAgeRamp){ - initResult = YES; - } - return initResult; -} - --(BOOL) initializeManagerPropertiesForContext:(NSString*)dsid error:(NSError**)error -{ - NSError *localError = nil; - BOOL initialized = YES; - - if(dsid == nil){ - dsid = [self askAccountsForDSID]; - } - - //create local store - self.localStore = [[OTLocalStore alloc] initWithContextID:OTDefaultContext dsid:dsid path:nil error:&localError]; - if(!self.localStore){ - secerror("octagon: could not create localStore: %@", localError); - initialized = NO; - } - - //create context - self.context = [[OTContext alloc]initWithContextID:OTDefaultContext dsid:dsid localStore:self.localStore cloudStore:nil identityProvider:self error:&localError]; - if(!self.context){ - secerror("octagon: could not create context: %@", localError); - self.localStore = nil; - initialized = NO; - } - - //just in case, init the ramp objects - [self initRamps]; - - if(localError && error){ - *error = localError; + if(!self.gbmidRamp) { + self.gbmidRamp = [[OTRamp alloc]initWithRecordName:kOTRampForGhostBustMIDName + localSettingName:@"ghostBustMID" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; + } + + if(!self.gbserialRamp) { + self.gbserialRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustSerialName + localSettingName:@"ghostBustSerial" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; + } + + if(!self.gbAgeRamp) { + self.gbAgeRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustAgeName + localSettingName:@"ghostBustAge" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; } - return initialized; } //// @@ -513,90 +408,10 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; NSError* _Nullable error))reply { secnotice("octagon", "handleIdentityChangeForSigningKey: %@", peerID); - NSError* error = nil; - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(NO,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(NO,error); - return; - - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(NO,error); - return; - } - - CKKSAnalytics* logger = [CKKSAnalytics logger]; - SFAnalyticsActivityTracker *tracker = [logger logSystemMetricsForActivityNamed:CKKSActivityOctagonUpdateBottle withAction:nil]; - - [tracker start]; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(NO,error); - [tracker cancel]; - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - //got an error from ramp check, we should log it - if(error){ - [logger logRecoverableError:error - forEvent:OctagonEventRamp - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"ramp check for updating bottle" - }]; - } - - if(!isFeatureOn){ //the feature is off for this device - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - [tracker cancel]; - reply(NO, error); - return; - } - - BOOL updated = [self.context updateAllBottlesForPeerID:peerID newSigningKey:peerSigningKey newEncryptionKey:encryptionKey error:&error]; - - if(!updated || error != nil) { - secerror("octagon: failed to update bottles for %@, error: %@", peerID, error); - [logger logUnrecoverableError:error forEvent:OctagonEventUpdateBottle withAttributes:@{ OctagonEventAttributeFailureReason : @"failed to update bottles"}]; - [tracker cancel]; - reply(NO, error); - return; - } - - [tracker stop]; - [logger logSuccessForEventNamed:OctagonEventUpdateBottle]; - - secnotice("octagon", "handleIdentityChangeForSigningKey completed, updated bottles for: %@", peerID); - - reply(YES, error); + reply(NO, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)preflightBottledPeer:(NSString*)contextID @@ -607,45 +422,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; NSError* _Nullable error))reply { secnotice("octagon", "preflightBottledPeer: %@ %@", contextID, dsid); - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:dsid error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,nil,nil,error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ //feature is off for this device - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(nil, nil, nil, error); - return; - } - - NSData* entropy = [self.context makeMeSomeEntropy:OTMasterSecretLength]; - if(!entropy){ - secerror("octagon: entropy creation failed: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEntropyCreationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to create entropy"}]; - reply(nil, nil, nil, error); - return; - } - - OTPreflightInfo* result = [self.context preflightBottledPeer:contextID entropy:entropy error:&error]; - if(!result || error){ - secerror("octagon: preflight failed: %@", error); - reply(nil, nil, nil, error); - return; - } - - secnotice("octagon", "preflightBottledPeer completed, created: %@", result.bottleID); - - reply(entropy, result.bottleID, result.escrowedSigningSPKI, error); + reply(nil, + nil, + nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)launchBottledPeer:(NSString*)contextID @@ -653,156 +435,28 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; reply:(void (^ _Nullable)(NSError* _Nullable error))reply { secnotice("octagon", "launchBottledPeer"); - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - reply(error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(error); - return; - } - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:bottleID error:&error]; - if(!bprecord || error){ - secerror("octagon: could not retrieve record for: %@, error: %@", bottleID, error); - reply(error); - return; - } - BOOL result = [self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error]; - if(!result || error){ - secerror("octagon: could not upload record for bottleID %@, error: %@", bottleID, error); - reply(error); - return; - } - - secnotice("octagon", "successfully launched: %@", bprecord.recordName); - - reply(error); + reply([NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError *))reply { - //check if configuration zone allows restore - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:dsid error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,nil,error); - return; - } - } - - BOOL isFeatureOn = [self.restoreRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(nil, nil, error); - return; - } - - if(!escrowRecordID || [escrowRecordID length] == 0){ - secerror("octagon: missing escrowRecordID"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyEscrowRecordID userInfo:@{NSLocalizedDescriptionKey: @"Escrow Record ID is empty or missing"}]; - - reply(nil, nil, error); - return; - } - if(!dsid || [dsid length] == 0){ - secerror("octagon: missing dsid"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyDSID userInfo:@{NSLocalizedDescriptionKey: @"DSID is empty or missing"}]; - reply(nil, nil, error); - return; - } - if(!secret || [secret length] == 0){ - secerror("octagon: missing secret"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptySecret userInfo:@{NSLocalizedDescriptionKey: @"Secret is empty or missing"}]; - reply(nil, nil, error); - return; - } - - OTBottledPeerSigned *bps = [_context restoreFromEscrowRecordID:escrowRecordID secret:secret error:&error]; - if(!bps || error != nil){ - secerror("octagon: failed to restore bottled peer: %@", error); - reply(nil, nil, error); - return; - } - - SFECKeyPair *encryptionKey = bps.bp.peerEncryptionKey; - SFPublicKey *encryptionPublicKey = encryptionKey.publicKey; - NSData* encryptionKeyData = encryptionPublicKey.keyData;// FIXME - - if(!encryptionKeyData){ - secerror("octagon: restored octagon encryption key is nil: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRestoredPeerEncryptionKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to retrieve restored Octagon Peer Encryption Key"}]; - reply(nil,nil,error); - return; - } - - SFECKeyPair *signingKey = bps.bp.peerSigningKey; - SFPublicKey *signingKeyPublicKey = signingKey.publicKey; - NSData* signingKeyData = signingKeyPublicKey.keyData;// FIXME - - if(!signingKeyData){ - secerror("octagon: restored octagon signing key is nil: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRestoredPeerSigningKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to retrieve restored Octagon Peer Signing Key"}]; - reply(nil,nil,error); - return; - } - - secnotice("octagon", "restored bottled peer: %@", escrowRecordID); - - reply(signingKeyData, encryptionKeyData, error); + secnotice("octagon", "restore"); + reply(nil, + nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)scrubBottledPeer:(NSString*)contextID bottleID:(NSString*)bottleID reply:(void (^ _Nullable)(NSError* _Nullable error))reply { - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - reply(error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(error); - return; - } - - BOOL result = [self.context scrubBottledPeer:contextID bottleID:bottleID error:&error]; - if(!result || error){ - secerror("octagon: could not scrub record for bottleID %@, error: %@", bottleID, error); - reply(error); - return; - } - - secnotice("octagon", "scrubbed bottled peer: %@", bottleID); - - reply(error); + reply([NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } //// @@ -811,243 +465,34 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; -(void)reset:(void (^)(BOOL result, NSError *))reply { - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(NO,error); - return; - } - } - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(NO,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(NO,error); - return; - - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(NO,error); - return; - } - - NSError* bottledPeerError = nil; - - BOOL result = [_context.cloudStore performReset:&bottledPeerError]; - if(!result || bottledPeerError != nil){ - secerror("octagon: resetting octagon trust zone failed: %@", bottledPeerError); - } - - NSString* contextAndDSID = [NSString stringWithFormat:@"%@-%@", self.context.contextID, self.context.dsid]; - - result = [self.localStore deleteBottledPeersForContextAndDSID:contextAndDSID error:&bottledPeerError]; - if(!result){ - secerror("octagon: could not delete bottle peer records: %@: %@", self.context.contextID, bottledPeerError); - } - - reply(result, bottledPeerError); + reply(NO, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)listOfEligibleBottledPeerRecords:(void (^)(NSArray* listOfRecords, NSError * _Nullable))reply { - NSError* error = nil; - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,error); - return; - } - } - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(nil,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(nil,error); - return; - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(nil,error); - return; - } - - NSArray* list = [_context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - if(!list || error !=nil){ - secerror("octagon: there are not eligible bottle peer records: %@", error); - reply(nil,error); - return; - } - reply(list, error); + reply(@[], + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)octagonEncryptionPublicKey:(void (^)(NSData* encryptionKey, NSError *))reply { - __block NSData *encryptionKey = NULL; - __block NSError* localError = nil; - - SOSCCPerformWithOctagonEncryptionPublicKey(^(SecKeyRef octagonPrivKey, CFErrorRef error) { - CFDataRef key; - SecKeyCopyPublicBytes(octagonPrivKey, &key); - encryptionKey = CFBridgingRelease(key); - if(error){ - localError = (__bridge NSError*)error; - } - }); - if(!encryptionKey || localError != nil){ - reply(nil, localError); - secerror("octagon: retrieving the octagon encryption public key failed: %@", localError); - return; - } - reply(encryptionKey, localError); + reply(nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } -(void)octagonSigningPublicKey:(void (^)(NSData* encryptionKey, NSError *))reply { - __block NSData *signingKey = NULL; - __block NSError* localError = nil; - - SOSCCPerformWithOctagonSigningPublicKey(^(SecKeyRef octagonPrivKey, CFErrorRef error) { - CFDataRef key; - SecKeyCopyPublicBytes(octagonPrivKey, &key); - signingKey = CFBridgingRelease(key); - if(error){ - localError = (__bridge NSError*)error; - } - }); - if(!signingKey || localError != nil){ - reply(nil, localError); - secerror("octagon: retrieving the octagon signing public key failed: %@", localError); - return; - } - reply(signingKey, localError); -} - -//// -// MARK: OT Helpers -//// - --(BOOL)scheduledCloudKitRampCheck:(NSError**)error -{ - secnotice("octagon", "scheduling a CloudKit ramping check"); - NSError* localError = nil; - BOOL cancelScheduler = YES; - - CKKSAnalytics* logger = [CKKSAnalytics logger]; - - if(self.cfuRamp){ - BOOL canCFU = [self.cfuRamp checkRampStateWithError:&localError]; - - if(localError){ - secerror("octagon: checking ramp state for CFU error'd: %@", localError); - [logger logUnrecoverableError:localError forEvent:OctagonEventRamp withAttributes:@{ - OctagonEventAttributeFailureReason : @"ramp check failed", - }]; - } - - if(canCFU){ - secnotice("octagon", "CFU is enabled, checking if this device has a bottle"); - OctagonBottleCheckState bottleStatus = [self.context doesThisDeviceHaveABottle:&localError]; - - if(bottleStatus == NOBOTTLE){ - //time to post a follow up! - secnotice("octagon", "device does not have a bottle, posting a follow up"); - if(!SecCKKSTestsEnabled()){ - //40347954 removing cfu invocations until we can add CDP without creating a cycle. - //[self.context postFollowUp]; - secnotice("octagon", "would have posted a follow up"); - } - NSInteger timeDiff = -1; - - NSDate *currentDate = [NSDate date]; - if(self.lastPostedCoreFollowUp){ - timeDiff = [currentDate timeIntervalSinceDate:self.lastPostedCoreFollowUp]; - } - - //log how long we last posted a followup, if any - [logger logRecoverableError:localError - forEvent:OctagonEventCoreFollowUp - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"No bottle for peer", - OctagonEventAttributeTimeSinceLastPostedFollowUp: [NSNumber numberWithInteger:timeDiff], - }]; - - self.lastPostedCoreFollowUp = currentDate; - //if the followup failed or succeeded, we should continue the scheduler until we have a bottle. - cancelScheduler = NO; - }else if(bottleStatus == BOTTLE){ - secnotice("octagon", "device has a bottle"); - [logger logSuccessForEventNamed:OctagonEventBottleCheck]; - } - - if(localError){ - [logger logRecoverableError:localError - forEvent:OctagonEventBottleCheck - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"bottle check", - }]; - } - } - } - if(cancelScheduler == NO){ - secnotice("octagon", "requesting bottle check again"); - [self.cfuScheduler trigger]; - } - - if(error && localError){ - *error = localError; - } - return cancelScheduler; -} - --(void)scheduleCFUForFuture -{ - secnotice("octagon", "scheduling a query to cloudkit to see if this device can post a core follow up"); - - [self.cfuScheduler trigger]; -} - -- (nullable OTIdentity *) currentIdentity:(NSError**)error -{ - return [OTIdentity currentIdentityFromSOS:error]; + reply(nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)setCuttlefishXPCConnection:(id)cuttlefishXPCConnection @@ -1298,13 +743,14 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; - (void)resetAndEstablish:(NSString *)container context:(NSString *)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError * _Nullable))reply { SFAnalyticsActivityTracker *tracker = [[self.loggerClass logger] startLogSystemMetricsForActivityNamed:OctagonActivityResetAndEstablish]; OTCuttlefishContext* cfshContext = [self contextForContainerName:container contextID:context]; [cfshContext startOctagonStateMachine]; - [cfshContext rpcResetAndEstablish:^(NSError* resetAndEstablishError) { + [cfshContext rpcResetAndEstablish:resetReason reply:^(NSError* resetAndEstablishError) { [tracker stopWithEvent:OctagonEventResetAndEstablish result:resetAndEstablishError]; reply(resetAndEstablishError); }]; @@ -1497,14 +943,17 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; //// -(BOOL) ghostbustByMidEnabled { + [self ensureRampsInitialized]; return [self.gbmidRamp checkRampStateWithError:nil]; } -(BOOL) ghostbustBySerialEnabled { + [self ensureRampsInitialized]; return [self.gbserialRamp checkRampStateWithError:nil]; } -(BOOL) ghostbustByAgeEnabled { + [self ensureRampsInitialized]; return [self.gbAgeRamp checkRampStateWithError:nil]; } @@ -1553,10 +1002,10 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; // 3. Users in a bad state who have acted on the CFU will have no pending CFU, but will have CFU failures. // // We also record the time window between the last followup completion and invocation. - OTFollowup *followupHandler = cuttlefishContext.followupHandler; NSDate* dateOfLastFollowup = [[CKKSAnalytics logger] datePropertyForKey: OctagonAnalyticsLastCoreFollowup]; values[OctagonAnalyticsLastCoreFollowup] = @([CKKSAnalytics fuzzyDaysSinceDate:dateOfLastFollowup]); - values[OctagonAnalyticsCoreFollowupStatus] = @(followupHandler.followupStatus); + // We used to report this, but it was never set + //values[OctagonAnalyticsCoreFollowupStatus] = @(followupHandler.followupStatus); for (NSString *type in [self cdpContextTypes]) { NSString *metricName = [NSString stringWithFormat:@"%@%@", OctagonAnalyticsCDPStateRun, type]; @@ -1643,17 +1092,22 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; } CFErrorRef validateError = NULL; - bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, CFBridgingRetain(recoveryKey), &validateError); + bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, (__bridge CFStringRef)recoveryKey, &validateError); if (!res) { + NSError *validateErrorWrapper = nil; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = @"malformed recovery key"; + if(validateError) { + userInfo[NSUnderlyingErrorKey] = CFBridgingRelease(validateError); + } + + validateErrorWrapper = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRecoveryKeyMalformed userInfo:userInfo]; + secerror("recovery failed validation with error:%@", validateError); - NSError *validateErrorWrapper = (__bridge_transfer NSError *)validateError; [tracker stopWithEvent:OctagonEventSetRecoveryKeyValidationFailed result:validateErrorWrapper]; - - if (validateErrorWrapper) { - reply(validateErrorWrapper); - return; - } + reply(validateErrorWrapper); + return; } OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID]; @@ -1676,17 +1130,22 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; SFAnalyticsActivityTracker *tracker = [[self.loggerClass logger] startLogSystemMetricsForActivityNamed:OctagonActivityJoinWithRecoveryKey]; CFErrorRef validateError = NULL; - bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, CFBridgingRetain(recoveryKey), &validateError); + bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, (__bridge CFStringRef)recoveryKey, &validateError); if (!res) { + NSError *validateErrorWrapper = nil; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = @"malformed recovery key"; + if(validateError) { + userInfo[NSUnderlyingErrorKey] = CFBridgingRelease(validateError); + } + + validateErrorWrapper = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRecoveryKeyMalformed userInfo:userInfo]; + secerror("recovery failed validation with error:%@", validateError); - NSError *validateErrorWrapper = (__bridge_transfer NSError *)validateError; [tracker stopWithEvent:OctagonEventJoinRecoveryKeyValidationFailed result:validateErrorWrapper]; - - if (validateErrorWrapper) { - reply(validateErrorWrapper); - return; - } + reply(validateErrorWrapper); + return; } OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID]; @@ -1699,7 +1158,7 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; secerror("octagon, recovery key is not enrolled in octagon, resetting octagon circle"); [[self.loggerClass logger] logResultForEvent:OctagonEventJoinRecoveryKeyCircleReset hardFailure:NO result:error]; - [cfshContext rpcResetAndEstablish:^(NSError *resetError) { + [cfshContext rpcResetAndEstablish:CuttlefishResetReasonRecoveryKey reply:^(NSError *resetError) { if (resetError) { secerror("octagon, failed to reset octagon"); [tracker stopWithEvent:OctagonEventJoinRecoveryKeyCircleResetFailed result:resetError]; diff --git a/keychain/ot/OTOperationDependencies.h b/keychain/ot/OTOperationDependencies.h index bd569114..e9e5aeb6 100644 --- a/keychain/ot/OTOperationDependencies.h +++ b/keychain/ot/OTOperationDependencies.h @@ -1,10 +1,12 @@ #import +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/ot/OctagonStateMachine.h" #import "keychain/ot/OTSOSAdapter.h" #import "keychain/ot/OTAuthKitAdapter.h" #import "keychain/ot/OTCuttlefishAccountStateHolder.h" +#import "keychain/ot/OTDeviceInformationAdapter.h" #import "keychain/ckks/CKKSViewManager.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" @@ -23,7 +25,8 @@ NS_ASSUME_NONNULL_BEGIN @property id sosAdapter; @property (nullable) id octagonAdapter; @property id authKitAdapter; -@property id cuttlefishXPC; +@property id deviceInformationAdapter; +@property (readonly) CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property CKKSViewManager* viewManager; @property CKKSLockStateTracker* lockStateTracker; @property Class escrowRequestClass; @@ -35,9 +38,10 @@ NS_ASSUME_NONNULL_BEGIN sosAdapter:(id)sosAdapter octagonAdapter:(id _Nullable)octagonAdapter authKitAdapter:(id)authKitAdapter + deviceInfoAdapter:(id)deviceInfoAdapter viewManager:(CKKSViewManager*)viewManager lockStateTracker:(CKKSLockStateTracker *)lockStateTracker - cuttlefishXPC:(id)cuttlefishXPC + cuttlefishXPCWrapper:(CuttlefishXPCWrapper *)cuttlefishXPCWrapper escrowRequestClass:(Class)escrowRequestClass; @end diff --git a/keychain/ot/OTOperationDependencies.m b/keychain/ot/OTOperationDependencies.m index 058217a0..a1ec5c20 100644 --- a/keychain/ot/OTOperationDependencies.m +++ b/keychain/ot/OTOperationDependencies.m @@ -9,9 +9,10 @@ sosAdapter:(id)sosAdapter octagonAdapter:(id _Nullable)octagonAdapter authKitAdapter:(id)authKitAdapter + deviceInfoAdapter:(id)deviceInfoAdapter viewManager:(CKKSViewManager*)viewManager lockStateTracker:(CKKSLockStateTracker*)lockStateTracker - cuttlefishXPC:(id)cuttlefishXPC + cuttlefishXPCWrapper:(CuttlefishXPCWrapper *)cuttlefishXPCWrapper escrowRequestClass:(Class)escrowRequestClass { if((self = [super init])) { @@ -22,9 +23,10 @@ _sosAdapter = sosAdapter; _octagonAdapter = octagonAdapter; _authKitAdapter = authKitAdapter; + _deviceInformationAdapter = deviceInfoAdapter; _viewManager = viewManager; _lockStateTracker = lockStateTracker; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; _escrowRequestClass = escrowRequestClass; } return self; diff --git a/keychain/ot/OTPreflightInfo.h b/keychain/ot/OTPreflightInfo.h deleted file mode 100644 index c39b0bf4..00000000 --- a/keychain/ot/OTPreflightInfo.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#ifndef OTPreflightInfo_h -#define OTPreflightInfo_h - -#import - -@interface OTPreflightInfo : NSObject - -@property (nonatomic, strong) NSData* escrowedSigningSPKI; -@property (nonatomic, strong) NSString* bottleID; - -@end - - -#endif /* OTPreflightInfo_h */ -#endif /* OCTAGON */ diff --git a/keychain/ot/OTPreflightInfo.m b/keychain/ot/OTPreflightInfo.m deleted file mode 100644 index 539856d4..00000000 --- a/keychain/ot/OTPreflightInfo.m +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import "OTPreflightInfo.h" - -@implementation OTPreflightInfo - -@end - -#endif diff --git a/keychain/ot/OTPrepareOperation.m b/keychain/ot/OTPrepareOperation.m index 7c9f1b98..b2e5dd96 100644 --- a/keychain/ot/OTPrepareOperation.m +++ b/keychain/ot/OTPrepareOperation.m @@ -128,66 +128,59 @@ secerror("octagon: failed to save 'attempted join' state: %@", persistError); } - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventPrepareIdentity withAttributes:nil]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] prepareWithContainer:self.deps.containerName - context:self.deps.contextID - epoch:self.epoch - machineID:self.deviceInfo.machineID - bottleSalt:bottleSalt - bottleID:[NSUUID UUID].UUIDString - modelID:self.deviceInfo.modelID - deviceName:self.deviceInfo.deviceName - serialNumber:self.deviceInfo.serialNumber - osVersion:self.deviceInfo.osVersion - policyVersion:nil - policySecrets:nil -signingPrivKeyPersistentRef:signingKeyPersistRef - encPrivKeyPersistentRef:encryptionKeyPersistRef - reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error]; - if(error) { - secerror("octagon: Error preparing identity: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - secnotice("octagon", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); - self.peerID = peerID; - self.permanentInfo = permanentInfo; - self.permanentInfoSig = permanentInfoSig; - self.stableInfo = stableInfo; - self.stableInfoSig = stableInfoSig; - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistNewEgoPeerID:peerID error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist peer ID: %@", localError); - self.error = localError; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - WEAKIFY(self); - - CKKSResultOperation *doneOp = [CKKSResultOperation named:@"ot-prepare" - withBlock:^{ - STRONGIFY(self); - self.nextState = self.intendedState; - }]; - - OTFetchViewsOperation *fetchViewsOp = [[OTFetchViewsOperation alloc] initWithDependencies:self.deps]; - [self runBeforeGroupFinished:fetchViewsOp]; - [doneOp addDependency:fetchViewsOp]; - [self runBeforeGroupFinished:doneOp]; - [self.finishedOp addDependency:doneOp]; - [self runBeforeGroupFinished:self.finishedOp]; - } - } - }]; + [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName + context:self.deps.contextID + epoch:self.epoch + machineID:self.deviceInfo.machineID + bottleSalt:bottleSalt + bottleID:[NSUUID UUID].UUIDString + modelID:self.deviceInfo.modelID + deviceName:self.deviceInfo.deviceName + serialNumber:self.deviceInfo.serialNumber + osVersion:self.deviceInfo.osVersion + policyVersion:nil + policySecrets:nil + signingPrivKeyPersistentRef:signingKeyPersistRef + encPrivKeyPersistentRef:encryptionKeyPersistRef + reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error]; + if(error) { + secerror("octagon: Error preparing identity: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + secnotice("octagon", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); + self.peerID = peerID; + self.permanentInfo = permanentInfo; + self.permanentInfoSig = permanentInfoSig; + self.stableInfo = stableInfo; + self.stableInfoSig = stableInfoSig; + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistNewEgoPeerID:peerID error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist peer ID: %@", localError); + self.error = localError; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + WEAKIFY(self); + + CKKSResultOperation *doneOp = [CKKSResultOperation named:@"ot-prepare" + withBlock:^{ + STRONGIFY(self); + self.nextState = self.intendedState; + }]; + + OTFetchViewsOperation *fetchViewsOp = [[OTFetchViewsOperation alloc] initWithDependencies:self.deps]; + [self runBeforeGroupFinished:fetchViewsOp]; + [doneOp addDependency:fetchViewsOp]; + [self runBeforeGroupFinished:doneOp]; + [self.finishedOp addDependency:doneOp]; + [self runBeforeGroupFinished:self.finishedOp]; + } + } + }]; } @end diff --git a/keychain/ot/OTRemovePeersOperation.m b/keychain/ot/OTRemovePeersOperation.m index 72cbe6ef..231e9b17 100644 --- a/keychain/ot/OTRemovePeersOperation.m +++ b/keychain/ot/OTRemovePeersOperation.m @@ -62,26 +62,20 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] distrustPeerIDsWithContainer:self.deps.containerName - context:self.deps.contextID - peerIDs:self.peerIDs - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to remove peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully removed peers"); - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper distrustPeerIDsWithContainer:self.deps.containerName + context:self.deps.contextID + peerIDs:self.peerIDs + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to remove peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully removed peers"); + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTResetOperation.h b/keychain/ot/OTResetOperation.h index c331aa90..33379393 100644 --- a/keychain/ot/OTResetOperation.h +++ b/keychain/ot/OTResetOperation.h @@ -26,18 +26,22 @@ #import #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/ot/OTAuthKitAdapter.h" - +#import "keychain/ot/OTConstants.h" NS_ASSUME_NONNULL_BEGIN @interface OTResetOperation : CKKSGroupOperation - (instancetype)init:(NSString*)containerName contextID:(NSString*)contextID + reason:(CuttlefishResetReason)reason intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC; +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; + +@property CuttlefishResetReason resetReason; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTResetOperation.m b/keychain/ot/OTResetOperation.m index 79eb5dfe..49140e45 100644 --- a/keychain/ot/OTResetOperation.m +++ b/keychain/ot/OTResetOperation.m @@ -30,7 +30,7 @@ @interface OTResetOperation () @property NSString* containerName; @property NSString* contextID; -@property id cuttlefishXPC; +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; // Since we're making callback based async calls, use this operation trick to hold off the ending of this operation @property NSOperation* finishedOp; @@ -42,9 +42,10 @@ - (instancetype)init:(NSString*)containerName contextID:(NSString*)contextID + reason:(CuttlefishResetReason)reason intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; @@ -52,7 +53,8 @@ _containerName = containerName; _contextID = contextID; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; + _resetReason = reason; } return self; } @@ -65,29 +67,23 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventReset withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.cuttlefishXPCWrapper resetWithContainer:self.containerName + context:self.contextID + resetReason:self.resetReason + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventReset hardFailure:true result:error]; + + if(error) { + secnotice("octagon", "Unable to reset for (%@,%@): %@", self.containerName, self.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully reset Octagon"); + self.nextState = self.intendedState; + } - }] resetWithContainer:self.containerName - context:self.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventReset hardFailure:true result:error]; - - if(error) { - secnotice("octagon", "Unable to reset for (%@,%@): %@", self.containerName, self.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully reset Octagon"); - self.nextState = self.intendedState; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSOSAdapter.h b/keychain/ot/OTSOSAdapter.h index f8adfb8b..dddda03b 100644 --- a/keychain/ot/OTSOSAdapter.h +++ b/keychain/ot/OTSOSAdapter.h @@ -1,6 +1,7 @@ #if OCTAGON #import "keychain/ckks/CKKSPeer.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/ot/OTDefines.h" #import "keychain/SecureObjectSync/SOSCloudCircle.h" diff --git a/keychain/ot/OTSOSAdapter.m b/keychain/ot/OTSOSAdapter.m index 41b65403..69ed211f 100644 --- a/keychain/ot/OTSOSAdapter.m +++ b/keychain/ot/OTSOSAdapter.m @@ -7,7 +7,7 @@ #import "keychain/SecureObjectSync/SOSCloudCircleInternal.h" #include "keychain/SecureObjectSync/SOSViews.h" -#import "OSX/sec/securityd/SOSCloudCircleServer.h" +#import "keychain/securityd/SOSCloudCircleServer.h" #import "OSX/utilities/SecCFWrappers.h" #import "keychain/categories/NSError+UsefulConstructors.h" @@ -282,6 +282,27 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + __block CKKSPeerProviderState* result = nil; + + [SOSAccount performOnQuietAccountQueue: ^{ + NSError* selfPeersError = nil; + CKKSSelves* currentSelfPeers = [self fetchSelfPeers:&selfPeersError]; + + NSError* trustedPeersError = nil; + NSSet>* currentTrustedPeers = [self fetchTrustedPeers:&trustedPeersError]; + + result = [[CKKSPeerProviderState alloc] initWithPeerProviderID:self.providerID + essential:self.essential + selfPeers:currentSelfPeers + selfPeersError:selfPeersError + trustedPeers:currentTrustedPeers + trustedPeersError:trustedPeersError]; + }]; + + return result; +} + + (NSArray*)peerPublicSigningKeySPKIs:(NSSet>* _Nullable)peerSet { NSMutableArray* publicSigningSPKIs = [NSMutableArray array]; @@ -373,6 +394,19 @@ // no op } +- (nonnull CKKSPeerProviderState *)currentState { + NSError* unimplementedError = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + description:@"SOS unsupported on this platform"]; + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:self.providerID + essential:self.essential + selfPeers:nil + selfPeersError:unimplementedError + trustedPeers:nil + trustedPeersError:unimplementedError]; +} + + @end #endif // OCTAGON diff --git a/keychain/ot/OTSOSUpdatePreapprovalsOperation.m b/keychain/ot/OTSOSUpdatePreapprovalsOperation.m index e388dfbf..7abf6522 100644 --- a/keychain/ot/OTSOSUpdatePreapprovalsOperation.m +++ b/keychain/ot/OTSOSUpdatePreapprovalsOperation.m @@ -59,10 +59,11 @@ // Is this a very scary error? bool fatal = false; - NSTimeInterval ckdelay = CKRetryAfterSecondsForError(self.error); - NSTimeInterval delay = 30; - if(ckdelay != 0) { - delay = ckdelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = 30; } if([self.error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { @@ -98,26 +99,20 @@ NSArray* publicSigningSPKIs = [OTSOSActualAdapter peerPublicSigningKeySPKIs:peerSet]; secnotice("octagon-sos", "Updating SOS preapproved keys to %@", publicSigningSPKIs); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, update of preapproved keys is lost: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] setPreapprovedKeysWithContainer:self.deps.containerName - context:self.deps.contextID - preapprovedKeys:publicSigningSPKIs - reply:^(NSError* error) { - STRONGIFY(self); - if(error) { - secerror("octagon-sos: unable to update preapproved keys: %@", error); - self.error = error; - } else { - secnotice("octagon-sos", "Updated SOS preapproved keys"); - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper setPreapprovedKeysWithContainer:self.deps.containerName + context:self.deps.contextID + preapprovedKeys:publicSigningSPKIs + reply:^(NSError* error) { + STRONGIFY(self); + if(error) { + secerror("octagon-sos: unable to update preapproved keys: %@", error); + self.error = error; + } else { + secnotice("octagon-sos", "Updated SOS preapproved keys"); + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSOSUpgradeOperation.m b/keychain/ot/OTSOSUpgradeOperation.m index 3df7a768..fad75dd8 100644 --- a/keychain/ot/OTSOSUpgradeOperation.m +++ b/keychain/ot/OTSOSUpgradeOperation.m @@ -97,6 +97,13 @@ return; } + // Now that we have some non-error SOS status, write down that we attempted an SOS Upgrade. + NSError* persistError = nil; + BOOL persisted = [self.deps.stateHolder persistOctagonJoinAttempt:OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED error:&persistError]; + if(!persisted || persistError) { + secerror("octagon: failed to save 'attempted join' state: %@", persistError); + } + if(sosCircleStatus != kSOSCCInCircle) { secnotice("octagon-sos", "Device is not in SOS circle (state: %@), quitting SOS upgrade", SOSAccountGetSOSCCStatusString(sosCircleStatus)); self.nextState = OctagonStateBecomeUntrusted; @@ -133,10 +140,11 @@ // Is this a very scary error? bool fatal = false; - NSTimeInterval ckdelay = CKRetryAfterSecondsForError(self.error); - NSTimeInterval delay = 30; - if(ckdelay != 0) { - delay = ckdelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = 30; } if([self.error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { @@ -176,92 +184,73 @@ } } - NSError* persistError = nil; - BOOL persisted = [self.deps.stateHolder persistOctagonJoinAttempt:OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED error:&persistError]; - if(!persisted || persistError) { - secerror("octagon: failed to save 'attempted join' state: %@", persistError); - } + [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName + context:self.deps.contextID + epoch:self.deviceInfo.epoch + machineID:self.deviceInfo.machineID + bottleSalt:bottleSalt + bottleID:[NSUUID UUID].UUIDString + modelID:self.deviceInfo.modelID + deviceName:self.deviceInfo.deviceName + serialNumber:self.self.deviceInfo.serialNumber + osVersion:self.deviceInfo.osVersion + policyVersion:nil + policySecrets:nil + signingPrivKeyPersistentRef:signingKeyPersistRef + encPrivKeyPersistentRef:encryptionKeyPersistRef + reply:^(NSString * _Nullable peerID, + NSData * _Nullable permanentInfo, + NSData * _Nullable permanentInfoSig, + NSData * _Nullable stableInfo, + NSData * _Nullable stableInfoSig, + NSError * _Nullable error) { + STRONGIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePrepare hardFailure:true result:error]; - }] prepareWithContainer:self.deps.containerName - context:self.deps.contextID - epoch:self.deviceInfo.epoch - machineID:self.deviceInfo.machineID - bottleSalt:bottleSalt - bottleID:[NSUUID UUID].UUIDString - modelID:self.deviceInfo.modelID - deviceName:self.deviceInfo.deviceName - serialNumber:self.self.deviceInfo.serialNumber - osVersion:self.deviceInfo.osVersion - policyVersion:nil - policySecrets:nil -signingPrivKeyPersistentRef:signingKeyPersistRef - encPrivKeyPersistentRef:encryptionKeyPersistRef - reply:^(NSString * _Nullable peerID, - NSData * _Nullable permanentInfo, - NSData * _Nullable permanentInfoSig, - NSData * _Nullable stableInfo, - NSData * _Nullable stableInfoSig, - NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePrepare hardFailure:true result:error]; - - if(error) { - secerror("octagon-sos: Error preparing identity: %@", error); - self.error = error; - [self handlePrepareErrors:error nextExpectedState:OctagonStateBecomeUntrusted]; - - [self runBeforeGroupFinished:self.finishedOp]; - } else { - secnotice("octagon-sos", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); - - [self afterPrepare]; - } + if(error) { + secerror("octagon-sos: Error preparing identity: %@", error); + self.error = error; + [self handlePrepareErrors:error nextExpectedState:OctagonStateBecomeUntrusted]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + secnotice("octagon-sos", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); + + [self afterPrepare]; + } + + }]; } - (void)afterPrepare { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] preflightPreapprovedJoinWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(BOOL launchOkay, NSError * _Nullable error) { - STRONGIFY(self); + [self.deps.cuttlefishXPCWrapper preflightPreapprovedJoinWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(BOOL launchOkay, NSError * _Nullable error) { + STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; - if(error) { - secerror("octagon-sos: preflightPreapprovedJoin failed: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; + if(error) { + secerror("octagon-sos: preflightPreapprovedJoin failed: %@", error); - self.error = error; - self.nextState = OctagonStateBecomeUntrusted; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } + self.error = error; + self.nextState = OctagonStateBecomeUntrusted; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - if(!launchOkay) { - secnotice("octagon-sos", "TPH believes a preapprovedJoin will fail; aborting."); - self.nextState = OctagonStateBecomeUntrusted; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } + if(!launchOkay) { + secnotice("octagon-sos", "TPH believes a preapprovedJoin will fail; aborting."); + self.nextState = OctagonStateBecomeUntrusted; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - secnotice("octagon-sos", "TPH believes a preapprovedJoin might succeed; continuing."); - [self afterPreflight]; - }]; + secnotice("octagon-sos", "TPH believes a preapprovedJoin might succeed; continuing."); + [self afterPreflight]; + }]; } - (void)afterPreflight @@ -369,66 +358,59 @@ signingPrivKeyPersistentRef:signingKeyPersistRef secnotice("octagon-sos", "Beginning SOS upgrade with %d key sets and %d SOS peers", (int)viewKeySets.count, (int)peerSet.count); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSilentEscrow hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper attemptPreapprovedJoinWithContainer:self.deps.containerName + context:self.deps.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:publicSigningSPKIs + reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); - }] attemptPreapprovedJoinWithContainer:self.deps.containerName - context:self.deps.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:publicSigningSPKIs - reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreapprovedJoin hardFailure:true result:error]; - if(error) { - secerror("octagon-sos: attemptPreapprovedJoin failed: %@", error); - - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; requesting reset"); - self.nextState = self.ckksConflictState; - } else { - self.error = error; - self.nextState = OctagonStateBecomeUntrusted; - } - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - [self requestSilentEscrowUpdate]; - - secerror("octagon-sos: attemptPreapprovedJoin succeded"); - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - - if(!persisted || localError) { - secnotice("octagon-sos", "Couldn't persist results: %@", localError); - self.error = localError; - self.nextState = OctagonStateError; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - self.nextState = self.intendedState; - - // Tell CKKS about our shiny new records! - for (id key in self.deps.viewManager.views) { - CKKSKeychainView* view = self.deps.viewManager.views[key]; - secnotice("octagon-ckks", "Providing ck records (from sos upgrade) to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreapprovedJoin hardFailure:true result:error]; + if(error) { + secerror("octagon-sos: attemptPreapprovedJoin failed: %@", error); + + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; requesting reset"); + self.nextState = self.ckksConflictState; + } else { + self.error = error; + self.nextState = OctagonStateBecomeUntrusted; + } + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + [self requestSilentEscrowUpdate]; + + secerror("octagon-sos: attemptPreapprovedJoin succeded"); + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + + if(!persisted || localError) { + secnotice("octagon-sos", "Couldn't persist results: %@", localError); + self.error = localError; + self.nextState = OctagonStateError; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + self.nextState = self.intendedState; + + // Tell CKKS about our shiny new records! + for (id key in self.deps.viewManager.views) { + CKKSKeychainView* view = self.deps.viewManager.views[key]; + secnotice("octagon-ckks", "Providing ck records (from sos upgrade) to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSetRecoveryKeyOperation.m b/keychain/ot/OTSetRecoveryKeyOperation.m index e066172c..b83cbefa 100644 --- a/keychain/ot/OTSetRecoveryKeyOperation.m +++ b/keychain/ot/OTSetRecoveryKeyOperation.m @@ -93,29 +93,23 @@ { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventRecoveryKey withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - - }] setRecoveryKeyWithContainer:self.deps.containerName - context:self.deps.contextID - recoveryKey:self.recoveryKey - salt:salt - ckksKeys:viewKeySets - reply:^(NSError * _Nullable setError) { - if(setError){ - [[CKKSAnalytics logger] logResultForEvent:OctagonEventSetRecoveryKey hardFailure:true result:setError]; - secerror("octagon: Error setting recovery key: %@", setError); - self.error = setError; - [self runBeforeGroupFinished:self.finishOp]; - } else { - secnotice("octagon", "successfully set recovery key"); - [self runBeforeGroupFinished:self.finishOp]; - } - }]; + [self.deps.cuttlefishXPCWrapper setRecoveryKeyWithContainer:self.deps.containerName + context:self.deps.contextID + recoveryKey:self.recoveryKey + salt:salt + ckksKeys:viewKeySets + reply:^(NSError * _Nullable setError) { + STRONGIFY(self); + if(setError){ + [[CKKSAnalytics logger] logResultForEvent:OctagonEventSetRecoveryKey hardFailure:true result:setError]; + secerror("octagon: Error setting recovery key: %@", setError); + self.error = setError; + [self runBeforeGroupFinished:self.finishOp]; + } else { + secnotice("octagon", "successfully set recovery key"); + [self runBeforeGroupFinished:self.finishOp]; + } + }]; } @end diff --git a/keychain/ot/OTStates.h b/keychain/ot/OTStates.h index 279e7434..5133b381 100644 --- a/keychain/ot/OTStates.h +++ b/keychain/ot/OTStates.h @@ -100,6 +100,7 @@ extern OctagonState* const OctagonStateSecurityTrustCheck; extern OctagonState* const OctagonStateTPHTrustCheck; extern OctagonState* const OctagonStateCuttlefishTrustCheck; extern OctagonState* const OctagonStatePostRepairCFU; +extern OctagonState* const OctagonStateHealthCheckReset; // End of account reset state flow @@ -124,6 +125,8 @@ extern OctagonState* const OctagonStateDetermineiCloudAccountState; // CKKS sometimes needs an assist. These states are supposed to handle those cases extern OctagonState* const OctagonStateAssistCKKSTLKUpload; +extern OctagonState* const OctagonStateAssistCKKSTLKUploadCKKSReset; +extern OctagonState* const OctagonStateAssistCKKSTLKUploadAfterCKKSReset; // Call out to otpaird (KCPairing via IDS), then proceed to BecomeUntrusted extern OctagonState* const OctagonStateStartCompanionPairing; @@ -146,6 +149,8 @@ NSSet* OctagonInAccountStates(void); NSSet* OctagonHealthSourceStates(void); ////// State machine flags +extern OctagonFlag* const OctagonFlagIDMSLevelChanged; + extern OctagonFlag* const OctagonFlagEgoPeerPreapproved; extern OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload; @@ -161,8 +166,7 @@ extern OctagonFlag* const OctagonFlagAttemptSOSUpgrade; extern OctagonFlag* const OctagonFlagUnlocked; extern OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals; - -extern OctagonFlag* const OctagonFlagPerformHealthCheck; +extern OctagonFlag* const OctagonFlagAttemptSOSConsistency; extern OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation; diff --git a/keychain/ot/OTStates.m b/keychain/ot/OTStates.m index 448c356d..18e42299 100644 --- a/keychain/ot/OTStates.m +++ b/keychain/ot/OTStates.m @@ -99,12 +99,15 @@ OctagonState* const OctagonStateTPHTrustCheck = (OctagonState*) @"tph_trust_chec OctagonState* const OctagonStateCuttlefishTrustCheck = (OctagonState*) @"cuttlefish_trust_check"; OctagonState* const OctagonStatePostRepairCFU = (OctagonState*) @"post_repair_cfu"; OctagonState* const OctagonStateSecurityTrustCheck = (OctagonState*) @"security_trust_check"; +OctagonState* const OctagonStateHealthCheckReset = (OctagonState*) @"health_check_reset"; /* signout */ OctagonState* const OctagonStateNoAccountDoReset = (OctagonState*) @"no_account_do_reset"; OctagonState* const OctagonStateWaitForUnlock = (OctagonState*) @"wait_for_unlock"; OctagonState* const OctagonStateAssistCKKSTLKUpload = (OctagonState*) @"assist_ckks_tlk_upload"; +OctagonState* const OctagonStateAssistCKKSTLKUploadCKKSReset = (OctagonState*) @"assist_ckks_tlk_upload_ckks_reset"; +OctagonState* const OctagonStateAssistCKKSTLKUploadAfterCKKSReset = (OctagonState*) @"assist_ckks_tlk_upload_after_ckks_reset"; /* escrow */ OctagonState* const OctagonStateEscrowTriggerUpdate = (OctagonState*) @"escrow-trigger-update"; @@ -175,6 +178,9 @@ NSDictionary* OctagonStateMap(void) { OctagonStateInitiatorJoinCKKSReset: @47U, OctagonStateInitiatorJoinAfterCKKSReset: @48U, OctagonStateHSA2HealthCheck: @49U, + OctagonStateHealthCheckReset: @50U, + OctagonStateAssistCKKSTLKUploadCKKSReset: @51U, + OctagonStateAssistCKKSTLKUploadAfterCKKSReset: @52U, }; }); return map; @@ -190,7 +196,6 @@ NSDictionary* OctagonStateInverseMap(void) { return backwardMap; } -// This mistakenly includes OctagonStateWaitForHSA2, which should not be considered an "In Account" state. NSSet* OctagonInAccountStates(void) { static NSSet* s = nil; @@ -206,6 +211,7 @@ NSSet* OctagonInAccountStates(void) [sourceStates removeObject:OctagonStateDetermineiCloudAccountState]; [sourceStates removeObject:OctagonStateWaitingForCloudKitAccount]; [sourceStates removeObject:OctagonStateCloudKitNewlyAvailable]; + [sourceStates removeObject:OctagonStateWaitForHSA2]; s = sourceStates; }); @@ -231,6 +237,7 @@ NSSet* OctagonHealthSourceStates(void) } // Flags +OctagonFlag* const OctagonFlagIDMSLevelChanged = (OctagonFlag*) @"idms_level"; OctagonFlag* const OctagonFlagEgoPeerPreapproved = (OctagonFlag*) @"preapproved"; OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload = (OctagonFlag*) @"tlk_upload_needed"; OctagonFlag* const OctagonFlagCuttlefishNotification = (OctagonFlag*) @"recd_push"; @@ -239,6 +246,6 @@ OctagonFlag* const OctagonFlagAttemptSOSUpgrade = (OctagonFlag*)@"attempt_sos_up OctagonFlag* const OctagonFlagFetchAuthKitMachineIDList = (OctagonFlag*)@"attempt_machine_id_list"; OctagonFlag* const OctagonFlagUnlocked = (OctagonFlag*)@"unlocked"; OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals = (OctagonFlag*)@"attempt_sos_update_preapprovals"; -OctagonFlag* const OctagonFlagPerformHealthCheck = (OctagonFlag*)@"perform_health_check"; +OctagonFlag* const OctagonFlagAttemptSOSConsistency = (OctagonFlag*)@"attempt_sos_consistency"; OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation = (OctagonFlag*)@"escrowrequest_inform_cloudservices"; #endif // OCTAGON diff --git a/keychain/ot/OTUpdateTPHOperation.m b/keychain/ot/OTUpdateTPHOperation.m index d87e9be7..5a24b829 100644 --- a/keychain/ot/OTUpdateTPHOperation.m +++ b/keychain/ot/OTUpdateTPHOperation.m @@ -67,9 +67,6 @@ pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag conditions:OctagonPendingConditionsDeviceUnlocked]; fatal = false; - } else if ([self.error isCuttlefishError:CuttlefishErrorTransactionalFailure]) { - secnotice("octagon", "Transaction failure in cuttlefishm, retrying: %@", self.error); - fatal = false; } else { // more CloudKit errors should trigger a retry here secnotice("octagon", "Error is currently unknown, aborting: %@", self.error); @@ -78,7 +75,13 @@ if(!fatal) { if(!pendingFlag) { NSTimeInterval baseDelay = SecCKKSTestsEnabled() ? 2 : 30; - NSTimeInterval delay = CKRetryAfterSecondsForError(self.error) ?: baseDelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = baseDelay; + } + pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag delayInSeconds:delay]; } @@ -91,62 +94,56 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, update is lost: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] updateWithContainer:self.deps.containerName - context:self.deps.contextID - deviceName:nil - serialNumber:nil - osVersion:nil - policyVersion:nil - policySecrets:nil - reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) { - STRONGIFY(self); - if(error || !peerState) { - secerror("octagon: update errored: %@", error); - self.error = error; - - // On an error, for now, go back to the intended state - // Octagon: handle lock state errors in update() - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - secnotice("octagon", "update complete: %@", peerState); - - if(peerState.identityIsPreapproved) { - secnotice("octagon-sos", "Self peer is now preapproved!"); - [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved]; - } - if (peerState.memberChanges) { - secnotice("octagon", "Member list changed"); - [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate]; - } - - if (peerState.unknownMachineIDsPresent) { - secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch"); - [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList]; - } - - if(peerState.peerStatus & TPPeerStatusExcluded) { - secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID); - self.nextState = OctagonStateBecomeUntrusted; - - } else if(peerState.peerStatus & TPPeerStatusUnknown) { - secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID); - self.nextState = OctagonStateBecomeUntrusted; - - } else { - self.nextState = self.intendedState; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName + context:self.deps.contextID + deviceName:self.deps.deviceInformationAdapter.deviceName + serialNumber:self.deps.deviceInformationAdapter.serialNumber + osVersion:self.deps.deviceInformationAdapter.osVersion + policyVersion:nil + policySecrets:nil + reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) { + STRONGIFY(self); + if(error || !peerState) { + secerror("octagon: update errored: %@", error); + self.error = error; + + // On an error, for now, go back to the intended state + // Octagon: handle lock state errors in update() + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "update complete: %@", peerState); + + if(peerState.identityIsPreapproved) { + secnotice("octagon-sos", "Self peer is now preapproved!"); + [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved]; + } + if (peerState.memberChanges) { + secnotice("octagon", "Member list changed"); + [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate]; + } + + if (peerState.unknownMachineIDsPresent) { + secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch"); + [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList]; + } + + if(peerState.peerStatus & TPPeerStatusExcluded) { + secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID); + self.nextState = OctagonStateBecomeUntrusted; + + } else if(peerState.peerStatus & TPPeerStatusUnknown) { + secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID); + self.nextState = OctagonStateBecomeUntrusted; + + } else { + self.nextState = self.intendedState; + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTUpdateTrustedDeviceListOperation.m b/keychain/ot/OTUpdateTrustedDeviceListOperation.m index 814fab55..5f8a8763 100644 --- a/keychain/ot/OTUpdateTrustedDeviceListOperation.m +++ b/keychain/ot/OTUpdateTrustedDeviceListOperation.m @@ -111,38 +111,29 @@ - (void)afterAuthKitFetch:(NSSet*)allowedMachineIDs { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - if (self.logForUpgrade) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; - } - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] setAllowedMachineIDsWithContainer:self.deps.containerName - context:self.deps.contextID - allowedMachineIDs:allowedMachineIDs - reply:^(BOOL listDifferences, NSError * _Nullable error) { - STRONGIFY(self); - - if (self.logForUpgrade) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; - } - if(error) { - secnotice("octagon-authkit", "Unable to save machineID allow-list: %@", error); - self.error = error; - } else { - secnotice("octagon-authkit", "Successfully saved machineID allow-list (%@ change)", listDifferences ? @"some" : @"no"); - if(listDifferences) { - self.nextState = self.stateIfListUpdates; - } else { - self.nextState = self.intendedState; - } - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper setAllowedMachineIDsWithContainer:self.deps.containerName + context:self.deps.contextID + allowedMachineIDs:allowedMachineIDs + reply:^(BOOL listDifferences, NSError * _Nullable error) { + STRONGIFY(self); + + if (self.logForUpgrade) { + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; + } + if(error) { + secnotice("octagon-authkit", "Unable to save machineID allow-list: %@", error); + self.error = error; + } else { + secnotice("octagon-authkit", "Successfully saved machineID allow-list (%@ change)", listDifferences ? @"some" : @"no"); + if(listDifferences) { + self.nextState = self.stateIfListUpdates; + } else { + self.nextState = self.intendedState; + } + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTUploadNewCKKSTLKsOperation.h b/keychain/ot/OTUploadNewCKKSTLKsOperation.h index f59562bb..3feeab6a 100644 --- a/keychain/ot/OTUploadNewCKKSTLKsOperation.h +++ b/keychain/ot/OTUploadNewCKKSTLKsOperation.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies intendedState:(OctagonState*)intendedState + ckksConflictState:(OctagonState*)ckksConflictState errorState:(OctagonState*)errorState; @property OctagonState* nextState; diff --git a/keychain/ot/OTUploadNewCKKSTLKsOperation.m b/keychain/ot/OTUploadNewCKKSTLKsOperation.m index 069a433b..f5430804 100644 --- a/keychain/ot/OTUploadNewCKKSTLKsOperation.m +++ b/keychain/ot/OTUploadNewCKKSTLKsOperation.m @@ -19,11 +19,9 @@ @interface OTUploadNewCKKSTLKsOperation () @property OTOperationDependencies* deps; +@property OctagonState* ckksConflictState; + @property NSOperation* finishedOp; -@property int retries; -@property int maxRetries; -@property int delay; -@property CKKSNearFutureScheduler* retrySched; @end @implementation OTUploadNewCKKSTLKsOperation @@ -31,16 +29,14 @@ - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies intendedState:(OctagonState*)intendedState + ckksConflictState:(OctagonState*)ckksConflictState errorState:(OctagonState*)errorState { if((self = [super init])) { _deps = dependencies; - _retries = 0; - _maxRetries = 5; - _delay = 1; - _intendedState = intendedState; + _ckksConflictState = ckksConflictState; _nextState = errorState; } return self; @@ -91,24 +87,6 @@ [self runBeforeGroupFinished:proceedWithKeys]; } -- (BOOL)isRetryable:(NSError* _Nonnull)error { - return [error isCuttlefishError:CuttlefishErrorTransactionalFailure]; -} - -- (int)retryDelay:(NSError* _Nonnull)error { - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - int ret = self->_delay; - if (underlyingError) { - id tmp = underlyingError.userInfo[@"retryafter"]; - if ([tmp isKindOfClass:[NSNumber class]]) { - ret = [(NSNumber*)tmp intValue]; - } - } - ret = MAX(MIN(ret, 32), self->_delay); - self->_delay *= 2; - return ret; -} - - (void)proceedWithKeys:(NSArray*)viewKeySets pendingTLKShares:(NSArray*)pendingTLKShares viewsToUpload:(NSSet*)viewsToUpload @@ -116,59 +94,32 @@ WEAKIFY(self); secnotice("octagon-ckks", "Beginning tlk upload with keys: %@", viewKeySets); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-ckks: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventEstablishIdentity withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] updateTLKsWithContainer:self.deps.containerName - context:self.deps.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - reply:^(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - if(error) { - secerror("octagon: Error calling tlk upload: %@", error); - if (self.retries < self.maxRetries && [self isRetryable:error]) { - ++self.retries; - if (!self.retrySched) { - self.retrySched = [[CKKSNearFutureScheduler alloc] initWithName:@"cuttlefish-updatetlk-retry" - delay:1*NSEC_PER_SEC - keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - CKKSResultOperation* retryOp = [CKKSResultOperation named:@"retry-updatetlk" - withBlock:^{ - STRONGIFY(self); - secnotice("octagon", "retrying (%d/%d) updateTLKs", self.retries, self->_maxRetries); - [self proceedWithKeys:viewKeySets pendingTLKShares:pendingTLKShares viewsToUpload:viewsToUpload]; - }]; - STRONGIFY(self); - [self runBeforeGroupFinished:retryOp]; - }]; - } - int delay_s = [self retryDelay:error]; - [self.retrySched waitUntil:delay_s*NSEC_PER_SEC]; - [self.retrySched trigger]; - return; - } - self.error = error; - - } else { - - // Tell CKKS about our shiny new records! - for(CKKSKeychainView* view in viewsToUpload) { - secnotice("octagon-ckks", "Providing records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper updateTLKsWithContainer:self.deps.containerName + context:self.deps.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + reply:^(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + + if(error) { + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else { + secerror("octagon: Error calling tlk upload: %@", error); + self.error = error; + } + } else { + // Tell CKKS about our shiny new records! + for(CKKSKeychainView* view in viewsToUpload) { + secnotice("octagon-ckks", "Providing records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTVouchWithBottleOperation.m b/keychain/ot/OTVouchWithBottleOperation.m index eb9b31c6..c96ba590 100644 --- a/keychain/ot/OTVouchWithBottleOperation.m +++ b/keychain/ot/OTVouchWithBottleOperation.m @@ -71,9 +71,10 @@ if(self.bottleSalt != nil) { secnotice("octagon", "using passed in altdsid, altdsid is: %@", self.bottleSalt); } else{ - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - secnotice("octagon", "using auth kit adapter, altdsid is: %@", self.deps.authKitAdapter.primaryiCloudAccountAltDSID); - self.bottleSalt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSString* altDSID = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + if(altDSID){ + secnotice("octagon", "fetched altdsid is: %@", altDSID); + self.bottleSalt = altDSID; } else { NSError* accountError = nil; @@ -107,38 +108,65 @@ - (void)proceedWithKeys:(NSArray*)viewKeySets tlkShares:(NSArray*)tlkShares { + // Preflight the vouch: this will tell us the peerID of the recovering peer. + // Then, filter the tlkShares array to include only tlks sent to that peer. WEAKIFY(self); - - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [self.deps.cuttlefishXPCWrapper preflightVouchWithBottleWithContainer:self.deps.containerName + context:self.deps.contextID + bottleID:self.bottleID + reply:^(NSString * _Nullable peerID, NSError * _Nullable error) { STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventVoucherWithBottle withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] vouchWithBottleWithContainer:self.deps.containerName - context:self.deps.contextID - bottleID:self.bottleID - entropy:self.entropy - bottleSalt:self.bottleSalt - tlkShares:tlkShares - reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithBottle hardFailure:true result:error]; - - if(error){ - secerror("octagon: Error preparing voucher using bottle: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - secnotice("octagon", "Received bottle voucher"); - - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventPreflightVouchWithBottle hardFailure:true result:error]; + + if(error){ + secerror("octagon: Error preflighting voucher using bottle: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "Bottle %@ is for peerID %@", self.bottleID, peerID); + + NSMutableArray* filteredTLKShares = [NSMutableArray array]; + for(CKKSTLKShare* share in tlkShares) { + // If we didn't get a peerID, just pass every tlkshare and hope for the best + if(peerID == nil || [share.receiverPeerID isEqualToString:peerID]) { + [filteredTLKShares addObject:share]; + } + } + + [self proceedWithKeys:viewKeySets filteredTLKShares:filteredTLKShares]; + }]; +} + +- (void)proceedWithKeys:(NSArray*)viewKeySets filteredTLKShares:(NSArray*)tlkShares +{ + WEAKIFY(self); + + [self.deps.cuttlefishXPCWrapper vouchWithBottleWithContainer:self.deps.containerName + context:self.deps.contextID + bottleID:self.bottleID + entropy:self.entropy + bottleSalt:self.bottleSalt + tlkShares:tlkShares + reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithBottle hardFailure:true result:error]; + + if(error){ + secerror("octagon: Error preparing voucher using bottle: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "Received bottle voucher"); + + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTVouchWithRecoveryKeyOperation.m b/keychain/ot/OTVouchWithRecoveryKeyOperation.m index b4fc0bc9..cded9242 100644 --- a/keychain/ot/OTVouchWithRecoveryKeyOperation.m +++ b/keychain/ot/OTVouchWithRecoveryKeyOperation.m @@ -108,31 +108,25 @@ { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventVoucherWithBottle withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - - }] vouchWithRecoveryKeyWithContainer:self.deps.containerName - context:self.deps.contextID - recoveryKey:self.recoveryKey - salt:salt - tlkShares:tlkShares - reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { - if(error){ - [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithRecoveryKey hardFailure:true result:error]; - secerror("octagon: Error preparing voucher using recovery key: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - return; - } - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishOp]; - }]; + [self.deps.cuttlefishXPCWrapper vouchWithRecoveryKeyWithContainer:self.deps.containerName + context:self.deps.contextID + recoveryKey:self.recoveryKey + salt:salt + tlkShares:tlkShares + reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { + STRONGIFY(self); + if(error){ + [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithRecoveryKey hardFailure:true result:error]; + secerror("octagon: Error preparing voucher using recovery key: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishOp]; + return; + } + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishOp]; + }]; } @end diff --git a/keychain/ot/OctagonCKKSPeerAdapter.m b/keychain/ot/OctagonCKKSPeerAdapter.m index 3aacf713..2aac36d8 100644 --- a/keychain/ot/OctagonCKKSPeerAdapter.m +++ b/keychain/ot/OctagonCKKSPeerAdapter.m @@ -181,38 +181,34 @@ __block NSMutableSet> * peers = nil; WEAKIFY(self); - [[self.deps.cuttlefishXPC synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - localerror = error; - - }] fetchTrustStateWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, - NSArray * _Nullable trustedPeers, - NSError * _Nullable operror) { - STRONGIFY(self); - if(operror) { - secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror); - localerror = operror; - - } else { - peers = [NSMutableSet set]; - - // Turn these peers into CKKSPeers - for(TrustedPeersHelperPeer* peer in trustedPeers) { - SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI]; - SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI]; - - CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID - encryptionPublicKey:encryptionKey - signingPublicKey:signingKey - viewList:peer.viewList]; - secnotice("octagon", "Have trusted peer %@", ckkspeer); - - [peers addObject:ckkspeer]; - } - } - }]; + [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, + NSArray * _Nullable trustedPeers, + NSError * _Nullable operror) { + STRONGIFY(self); + if(operror) { + secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror); + localerror = operror; + + } else { + peers = [NSMutableSet set]; + + // Turn these peers into CKKSPeers + for(TrustedPeersHelperPeer* peer in trustedPeers) { + SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI]; + SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI]; + + CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID + encryptionPublicKey:encryptionKey + signingPublicKey:signingKey + viewList:peer.viewList]; + secnotice("octagon", "Have trusted peer %@", ckkspeer); + + [peers addObject:ckkspeer]; + } + } + }]; if(error && localerror) { *error = localerror; @@ -237,6 +233,11 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + + @end #endif // OCTAGON diff --git a/keychain/ot/OctagonCheckTrustStateOperation.m b/keychain/ot/OctagonCheckTrustStateOperation.m index 0e05403c..9fe406bf 100644 --- a/keychain/ot/OctagonCheckTrustStateOperation.m +++ b/keychain/ot/OctagonCheckTrustStateOperation.m @@ -45,28 +45,22 @@ // Make sure we're in agreement with TPH about _which_ peer ID we should have WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, can't ensure check trust state: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] fetchTrustStateWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, - NSArray * _Nullable trustedPeers, - NSError * _Nullable error) { - STRONGIFY(self); - if(error || !selfPeerState || !trustedPeers) { - secerror("octagon: TPH was unable to determine current peer state: %@", error); - self.error = error; - self.nextState = OctagonStateError; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, + NSArray * _Nullable trustedPeers, + NSError * _Nullable error) { + STRONGIFY(self); + if(error || !selfPeerState || !trustedPeers) { + secerror("octagon: TPH was unable to determine current peer state: %@", error); + self.error = error; + self.nextState = OctagonStateError; + [self runBeforeGroupFinished:self.finishedOp]; - } else { - [self afterTPHTrustState:selfPeerState trustedPeers:trustedPeers]; - } - }]; + } else { + [self afterTPHTrustState:selfPeerState trustedPeers:trustedPeers]; + } + }]; } - (void)afterTPHTrustState:(TrustedPeersHelperPeerState*)peerState @@ -169,6 +163,17 @@ secnotice("octagon-consistency", "Saved new account metadata"); } + // See if we possibly should do an update because peer data in Octagon + // is different from local state, ie we upgraded + if (peerState.osVersion) { + NSString *osVersion = self.deps.deviceInformationAdapter.osVersion; + if (osVersion && ![osVersion isEqualToString:peerState.osVersion]) { + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.deps.flagHandler handlePendingFlag:pendingFlag]; + } + } + // And determine where to go from here! if(currentAccountMetadata.peerID && currentAccountMetadata.trustState == OTAccountMetadataClassC_TrustState_TRUSTED) { @@ -178,19 +183,10 @@ } else if(self.deps.sosAdapter.sosEnabled && currentAccountMetadata.trustState != OTAccountMetadataClassC_TrustState_TRUSTED && OctagonPerformSOSUpgrade()) { - secnotice("octagon", "Have iCloud account but not trusted in Octagon yet; inspecting SOS status: %@", + secnotice("octagon", "Have iCloud account but not trusted in Octagon yet: %@; attempting SOS upgrade", [currentAccountMetadata trustStateAsString:currentAccountMetadata.trustState]); - NSError* circleError = nil; - SOSCCStatus sosStatus = [self.deps.sosAdapter circleStatus:&circleError]; - - if(sosStatus == kSOSCCInCircle) { - secnotice("octagon", "SOS status is 'trusted'; requesting SOS upgrade"); - [self.deps.flagHandler handleFlag:OctagonFlagAttemptSOSUpgrade]; - } else { - secnotice("octagon", "SOS status is %d (error: %@)", (int)sosStatus, circleError); - } - self.nextState = OctagonStateBecomeUntrusted; + self.nextState = OctagonStateAttemptSOSUpgrade; } else if(currentAccountMetadata.trustState != OTAccountMetadataClassC_TrustState_TRUSTED) { secnotice("octagon", "Have iCloud account but not trusted in Octagon (%@)", diff --git a/keychain/ot/tests/OTBottledPeerTLK.m b/keychain/ot/tests/OTBottledPeerTLK.m deleted file mode 100644 index 9a88281f..00000000 --- a/keychain/ot/tests/OTBottledPeerTLK.m +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLEself.LICENSEself.HEADERself.START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLEself.LICENSEself.HEADERself.END@ - */ - -#if OCTAGON - -#import "OTTestsBase.h" - -@interface BottledPeerRestoreTLKTests : OTTestsBase -@property CKKSSOSSelfPeer* remotePeer1; -@property CKKSSOSPeer* remotePeer2; -@property CKKSSOSSelfPeer* untrustedPeer; - -@end - -@implementation BottledPeerRestoreTLKTests - -- (void)setUp -{ - [super setUp]; - - //set up a bottled peer and stick it in localStore - NSError* error = nil; - - self.remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:self.sosPeerID - encryptionKey:self.peerEncryptionKey - signingKey:self.peerSigningKey]; - - [self.currentPeers addObject:self.remotePeer1]; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - OTBottledPeerRecord* record = [bpSigned asRecord:[self currentIdentity:&error].spID]; - self.recordName = record.recordName; - - OTIdentity* identity = [self currentIdentity:&error]; - [self.localStore insertBottledPeerRecord:record escrowRecordID:identity.spID error:&error]; - - self.remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote-peer1" - encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] - signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]]; - - self.remotePeer2 = [[CKKSSOSPeer alloc] initWithSOSPeerID:@"remote-peer2" - encryptionPublicKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]].publicKey - signingPublicKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]].publicKey]; - - // Local SOS trusts these peers - [self.currentPeers addObject:self.remotePeer1]; - [self.currentPeers addObject:self.remotePeer2]; - - self.untrustedPeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"untrusted-peer" - encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] - signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]]; -} - -- (void)tearDown -{ - _remotePeer1 = nil; - _remotePeer2 = nil; - _untrustedPeer = nil; - [super tearDown]; -} - --(void) testTLKSharingWithRestoredBottledPeer -{ - NSError* error = nil; - - OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:self.recordName error:&error]; - XCTAssertNotNil(rec, @"rec should not be nil: %@", error); - XCTAssertNil(error, @"error should be nil: %@", error); - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:self.escrowKeys - error:&error]; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bps, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); - - - CKKSSelves* selves = [[CKKSViewManager manager] fetchSelfPeers:&error]; - XCTAssertNotNil(selves, @"selves should not be nil: %@", error); - - XCTAssertTrue([selves.allSelves count] == 2, @"should have 2 selves"); - NSArray *arrayOfSelves = [selves.allSelves allObjects]; - XCTAssertNotNil(arrayOfSelves, @"arrayOfSelves should not be nil: %@", error); - - CKKSSOSSelfPeer *ourRestoredPeer = [arrayOfSelves objectAtIndex:0]; - if([ourRestoredPeer.peerID isEqualToString:@"spid-local-peer"]){ - ourRestoredPeer = [arrayOfSelves objectAtIndex:1]; - } - - XCTAssertTrue([ourRestoredPeer.peerID containsString:self.sosPeerID], @"peer ids should match!"); - XCTAssertTrue([ourRestoredPeer.signingKey isEqual:self.peerSigningKey], @"signing keys should match"); - XCTAssertTrue([ourRestoredPeer.encryptionKey isEqual:self.peerEncryptionKey], @"encryption keys should match"); - - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - [self putFakeDeviceStatusInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - // The CKKS subsystem should not try to write anything to the CloudKit database, but it should enter waitfortlk - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "Key state should become waitfortlk"); - - // peer1 arrives to save the day - // The CKKS subsystem should accept the keys, and share the TLK back to itself - [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; - - [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:ourRestoredPeer zoneID:self.keychainZoneID]; - [self.keychainView notifyZoneChange:nil]; - [self.keychainView waitForFetchAndIncomingQueueProcessing]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready"); - - // We expect a single record to be uploaded for each key class - [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID - checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; - [self addGenericPassword: @"data" account: @"account-delete-me"]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID - checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; - [self addGenericPassword:@"asdf" - account:@"account-class-A" - viewHint:nil - access:(id)kSecAttrAccessibleWhenUnlocked - expecting:errSecSuccess - message:@"Adding class A item"]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); -} - -- (nullable OTIdentity *)currentIdentity:(NSError * _Nullable __autoreleasing * _Nullable)error { - return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif diff --git a/keychain/ot/tests/OTBottledPeerTests.m b/keychain/ot/tests/OTBottledPeerTests.m deleted file mode 100644 index 20cdbe42..00000000 --- a/keychain/ot/tests/OTBottledPeerTests.m +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import -#import -#import -#import "OTTestsBase.h" -#import -#import -#import -#import -#import - -#import "keychain/ot/OTBottledPeer.h" -#import "keychain/ot/OTBottledPeerSigned.h" - -#import "keychain/ckks/CKKS.h" - -static NSString* const testDSID = @"123456789"; - -@interface UnitTestOTBottledPeer : OTTestsBase - -@end - -@implementation UnitTestOTBottledPeer - -- (void)setUp -{ - [super setUp]; - self.continueAfterFailure = NO; - NSError* error = nil; - - self.sosPeerID = @"spID"; - self.egoPeerID = @"egoPeerID"; - self.peerSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.peerEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void)testBottledPeerCreation -{ - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"bottled peer should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - -} - --(void)testSignedBottledPeerCreation -{ - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(bpSigned, @"bottled peer signed should not be nil"); - -} - --(void)testCreatingBottledPeerFromRecord -{ - NSError* error = nil; - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - OTBottledPeerRecord* record = [bpSigned asRecord:@"escrowRecordID"]; - OTBottledPeerSigned *bpRestored = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:record escrowKeys:self.escrowKeys error:&error]; - XCTAssertNotNil(bpRestored, @"bottled peer signed should not be nil"); -} - --(void)testRestoringBottledPeerSigned -{ - NSError* error = nil; - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - - SFECKeySpecifier *keySpecifier = [[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]; - id digestOperation = [[SFSHA384DigestOperation alloc] init]; - SFEC_X962SigningOperation* xso = [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:keySpecifier digestOperation:digestOperation]; - - NSData* signatureUsingEscrow = [xso sign:bp.data withKey:self.escrowKeys.signingKey error:&error].signature; - XCTAssertNil(error, @"error should not be nil"); - - NSData* signatureUsingPeerKey = [xso sign:bp.data withKey:self.peerSigningKey error:&error].signature; - XCTAssertNil(error, @"error should not be nil"); - - XCTAssertNotNil(signatureUsingEscrow, @"signature using escrow signing key should not be nil"); - XCTAssertNotNil(signatureUsingPeerKey, @"signature using peer signing key should not be nil"); - - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp signatureUsingEscrow:signatureUsingEscrow signatureUsingPeerKey:signatureUsingPeerKey escrowedSigningPubKey:[self.escrowKeys.signingKey publicKey] error:&error]; - - XCTAssertNotNil(bpSigned, @"bottled peer signed should not be nil"); - - bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp signatureUsingEscrow:[NSData data] signatureUsingPeerKey:[NSData data] escrowedSigningPubKey:[self.escrowKeys.signingKey publicKey] error:&error]; - - XCTAssertNil(bpSigned, @"bottled peer signed should be nil"); - XCTAssertNotNil(error, @"error should not be nil"); - -} - -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m b/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m deleted file mode 100644 index bb762dc1..00000000 --- a/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" -#import "keychain/ot/OTConstants.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTUpdateBottlesTests : OTTestsBase - -@end - -@implementation OTUpdateBottlesTests - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. -} - -- (void)tearDown { - [super tearDown]; -} - --(void)testUpdatingExistingBottle -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottle SPI should fire"]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating identity SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result, "result should be YES"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void)testUpdatingNonExistentBottles -{ - self.spiBlockExpectation = [self expectationWithDescription:@"updating identity SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertFalse(result, "result should be NO"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void)testUpdatingBottleMissingKeys -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - NSError *localError = nil; - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottle SPI should fire"]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - //delete escrow keys - OTEscrowKeys* keySet = [[OTEscrowKeys alloc] initWithSecret:localEntropy dsid:testDSID error:&localError]; - XCTAssertNotNil(keySet, "keySet should not be nil"); - XCTAssertNil(localError, "localError should be nil"); - - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecReturnAttributes: @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - } mutableCopy]; - - OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); - XCTAssertEqual(status, 0, @"status should be 0"); - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating bottle SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertFalse(result, "result should be NO"); - XCTAssertNotNil(error, "error should not be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void)testUpdatingMultipleBottlesForSamePeer -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - __block NSData* localEntropy1 = nil; - __block NSString* localBottleID1 = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy1 = entropy; - localBottleID1 = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launching bottle SPI should fire"]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID1 reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - __block NSData* localEntropy2 = nil; - __block NSString* localBottleID2 = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy2 = entropy; - localBottleID2 = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launching bottle SPI should fire"]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID2 reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForCKModifications]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating bottle SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result, "result should be YES"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); -} - - -@end - -#endif - diff --git a/keychain/ot/tests/OTCliqueTests.m b/keychain/ot/tests/OTCliqueTests.m deleted file mode 100644 index 69b7d9c7..00000000 --- a/keychain/ot/tests/OTCliqueTests.m +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import -#import "OTClique.h" -#import -#import - -@interface CliqueUnitTests : XCTestCase -@property (nonatomic, strong) OTClique* testClique; -@property (nonatomic, strong) OTConfigurationContext* testData; -@property (nonatomic, copy) NSString* testContextName; -@property (nonatomic, copy) NSString* testDSID; -@property (nonatomic, copy) NSString* testAltDSID; -@property (nonatomic, strong) SFSignInAnalytics *analytics; -@property (nonatomic, strong) XCTestExpectation *spiBlockExpectation; - -@end - -@implementation CliqueUnitTests - -- (void)setUp -{ - NSError *error = NULL; - - [super setUp]; - self.continueAfterFailure = NO; - _testDSID = @"123456789"; - _testContextName = @"contextName"; - _testAltDSID = @"testAltDSID"; - _testData = [[OTConfigurationContext alloc]init]; - _testData.context = _testContextName; - _testData.dsid = _testDSID; - _testData.altDSID = _testAltDSID; - _testData.analytics = _analytics; - - _analytics = [[SFSignInAnalytics alloc]initWithSignInUUID:[NSUUID UUID].UUIDString category:@"com.apple.cdp" eventName:@"signed in"]; - XCTAssertNotNil(_analytics, "sign in analytics object should not be nil"); - - _testClique = [[OTClique alloc]initWithContextData:_testData error:&error]; - XCTAssertNotNil(_testClique, "clique should not be nil: %@", error); -} - -- (void)tearDown -{ - _analytics = nil; - _testClique = nil; - - [super tearDown]; -} - - --(void) testCliqueStatus -{ - NSError *error = NULL; - CliqueStatus clique = [_testClique fetchCliqueStatus:&error]; - XCTAssertTrue(clique == CliqueStatusIn || clique == CliqueStatusError, "circle status should be in circle"); - XCTAssertTrue(error == nil || [error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be nil"); -} - --(void) testCachedCliqueStatus -{ - NSError *error = NULL; -#pragma clang push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CliqueStatus clique = [_testClique cachedCliqueStatus:YES error:&error]; -#pragma clang pop - XCTAssertTrue(clique == CliqueStatusIn || clique == CliqueStatusError, "circle status should be in circle"); - XCTAssertTrue(error == nil || [error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be nil"); -} - -- (void) testMakeNewFriends -{ - NSError *error = NULL; - OTConfigurationContext* newData = [[OTConfigurationContext alloc]init]; - newData.context = _testContextName; - newData.dsid = _testDSID; - newData.altDSID = _testAltDSID; - newData.analytics = _analytics; - - OTClique* clique = [OTClique newFriendsWithContextData:newData error:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertNil(clique, "clique should be nil"); - } - else{ - XCTAssertNotNil(clique, "new clique should be nil"); - XCTAssertNil(error, "error should be nil"); - } -} - -- (void) testRemoveFriendFromClique -{ - NSError *error = NULL; - CFErrorRef validPeerError = NULL; - CFArrayRef peerList = SOSCCCopyValidPeerPeerInfo(&validPeerError); - if(validPeerError){ - BOOL result = [_testClique removeFriendsInClique:@[@""] error:&error]; - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertFalse(result, "should have returned NO, attempting to remove friends when not valid in the circle"); - }else{ - BOOL result = [_testClique removeFriendsInClique:@[@""] error:&error]; - XCTAssertFalse(result, "should have returned NO, we passed an empty list"); - } - CFReleaseNull(peerList); -} - -- (void) testLeaveClique -{ - NSError *error = NULL; - BOOL result = [_testClique leaveClique:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertFalse(result, "result should be NO"); - }else{ - XCTAssertNil(error, "error should be nil"); - } -} - -- (void) testListFriendIDs -{ - NSError *error = NULL; - NSDictionary *friends = [_testClique peerDeviceNamesByPeerID:&error]; - if(error){ - XCTAssertEqual([friends count], 0, "friends should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(friends, "friends should not be nil"); - } -} - -- (void) testWaitForInitialSync -{ - NSError *error = NULL; - BOOL result = [_testClique waitForInitialSync:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "wait for initial sync should succeed"); - } -} - -- (void) testCopyViewUnawarePeerInfo -{ - NSError *error = NULL; - NSArray* result = [_testClique copyViewUnawarePeerInfo:&error]; - if(error){ - XCTAssertNil(result, "result should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(result, "copy view unaware peer info should return an array of peer infos"); - } -} - -- (void) testSetUserCredentialsAndDSID -{ - NSError *error = NULL; - - BOOL result = [_testClique setUserCredentialsAndDSID:[NSString string] password:[NSData data] error:&error]; - if(error) { - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:@"SyncedDefaults"] , "error should be from sos or KVS"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -- (void) testTryUserCredentialsAndDSID -{ - NSError *error = NULL; - - BOOL result = [_testClique tryUserCredentialsAndDSID:[NSString string] password:[NSData data] error:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -- (void) testCopyPeerPeerInfo -{ - NSError *error = NULL; - - NSArray* result = [_testClique copyPeerPeerInfo:&error]; - if(error){ - XCTAssertNil(result, "result should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(result, "result should not be nil"); - } -} - -- (void) testPeersHaveViewsEnabled -{ - NSError *error = NULL; - - BOOL result = [_testClique peersHaveViewsEnabled:[NSArray array] error:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - } - XCTAssertFalse(result, "result should be NO"); -} -- (void) testRequestToJoinCircle -{ - NSError *error = NULL; - - BOOL result = [_testClique requestToJoinCircle:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -@end diff --git a/keychain/ot/tests/OTCloudStoreTests.m b/keychain/ot/tests/OTCloudStoreTests.m deleted file mode 100644 index 3b60a1b9..00000000 --- a/keychain/ot/tests/OTCloudStoreTests.m +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; - -@interface OTCloudStoreUnitTests : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation OTCloudStoreUnitTests - - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; - self.fakeBottledPeerRecord = [[OTBottledPeerRecord alloc] init]; - self.fakeBottledPeerRecord.bottle = [@"bottled peer data" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.signatureUsingEscrowKey = [@"bottled peer escrow sig" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.signatureUsingPeerKey = [@"bottled peer peer sig" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.peerID = @"peer id"; - self.fakeBottledPeerRecord.spID = @"sos peer id"; - self.fakeBottledPeerRecord.escrowRecordID = @"escrowRecordID"; - self.fakeBottledPeerRecord.escrowedSigningSPKI = [@"escrowedSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.peerSigningSPKI = [@"peerSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding]; -} - -- (void)tearDown { - self.zones = nil; - self.operationQueue = nil; - - [super tearDown]; -} - -- (void)testWriteSameBottledPeerTwiceToFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; -} - -- (void)testWriteBottledPeerToFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; -} - -- (void)testWriteMultipleBottledPeersToSAMEFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - - [self waitForCKModifications]; - - XCTAssertNil(error, "error should be nil"); - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - } -} - -- (void)testWriteBottledPeersToDifferentFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - NSString *escrowID = [NSString stringWithFormat:@"bp-sospeer%d-hash", i]; - self.fakeBottledPeerRecord.escrowRecordID = escrowID; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:escrowID error:&error], @"should create bottled peer record"); - [self waitForCKModifications]; - - XCTAssertNil(error, "error should be nil"); - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - } - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 10, @"should have 1 record"); -} - - -- (void)testReadBottledPeerRecordFromCloudKit { - NSError *error = nil; - [self startCKKSSubsystem]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self.otFakeZone addToZone:newRecord]; - - [self.cloudStore notifyZoneChange:nil]; - - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have 1 record"); -} - --(void) testOTCloudStoreDownloadBP{ - NSError* error = nil; - [self startCKKSSubsystem]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self.otFakeZone addToZone:newRecord]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); - XCTAssertNil(error, "error should be nil"); -} - --(void) testOTCloudStoreDownloadMultipleBP{ - NSError* error = nil; - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = [NSString stringWithFormat:@"escrowRecordID%d", i]; - [self.otFakeZone addToZone:newRecord]; - } - [self waitForCKModifications]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)10, @"should have 1 record"); -} - --(void) testOTCloudStoreUploadMultipleToSameRecord{ - NSError* error = nil; - [self startCKKSSubsystem]; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - for(int i = 0; i < 10; i++){ - [self.otFakeZone addToZone:newRecord]; - } - [self waitForCKModifications]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); -} - --(void) testRemoveRecordIDs{ - - [self startCKKSSubsystem]; - NSError *error = nil; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self expectCKFetch]; - - [self.otFakeZone addToZone:newRecord]; - [self waitForCKModifications]; - - [self.cloudStore notifyZoneChange:nil]; - [self waitForCKModifications]; - - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record"); - - [self expectCKFetch]; - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; -} - --(void) testFetchTimeout -{ - [self startCKKSSubsystem]; - - NSError* error = nil; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - - [self holdCloudKitFetches]; - - [self.cloudStore downloadBottledPeerRecord:&error]; - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-fetch-and-process-changes)) timed out waiting to start for []"], "expecting timed out error"); -} - --(void) testModifyRecordsTimeout -{ - NSError* error = nil; - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready"); - - [self holdCloudKitModifications]; - - [self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord - escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error]; - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-modify-changes)) timed out waiting to start for []"], "expecting timed out error"); - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self releaseCloudKitModificationHold]; - [self waitForCKModifications]; -} - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTContextTests.m b/keychain/ot/tests/OTContextTests.m deleted file mode 100644 index b1b65f3c..00000000 --- a/keychain/ot/tests/OTContextTests.m +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#if OCTAGON - -#import -#import -#import - -#import "OTTestsBase.h" - -static NSString* const testContextID = @"Foo"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface UnitTestOTContext : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation UnitTestOTContext - -- (void)setUp -{ - [super setUp]; - self.continueAfterFailure = NO; -} - -- (void)tearDown -{ - self.zones = nil; - self.operationQueue = nil; - [super tearDown]; -} - --(void) testEnroll -{ - NSError* error = nil; - - NSString* escrowRecordID = [self currentIdentity:&error].spID; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error); - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info:%@", error); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:escrowRecordID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); -} - --(void) testEnrollAndRestore -{ - NSError* error = nil; - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - - NSString* escrowRecordID = [self currentIdentity:&error].spID; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error); - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - [self waitForCKModifications]; - - [self releaseCloudKitFetchHold]; - - OTBottledPeerSigned* bp = [self.context restoreFromEscrowRecordID:escrowRecordID secret:self.secret error:&error]; - [self waitForCKModifications]; - - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record"); - [self waitForCKModifications]; - - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bp, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bp.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bp.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); -} - --(void)testEnrollAndRestoreFromCloudKit -{ - NSError* error = nil; - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - XCTAssertTrue([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have multiple records"); - OTIdentity *identity = [self currentIdentity:&error]; - - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(self.escrowKeys, @"escrow keys should not be nil: %@", error); - - NSString* recordName = [OTBottledPeerRecord constructRecordID:identity.spID escrowSigningSPKI:[self.escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]]; - - OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&error]; - - XCTAssertNotNil(rec.signatureUsingEscrowKey, @"signatureUsingEscrow should not be nil: %@", error); - - XCTAssertNotNil(rec.signatureUsingPeerKey, @"signatureUsingPeerKey should not be nil: %@", error); - - XCTAssertNotNil(rec.bottle, @"bottle should not be nil: %@", error); - - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:self.escrowKeys - error:&error]; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bps, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); -} - --(void) testScrubbing -{ - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - XCTAssertTrue([self.context scrubBottledPeer:testContextID bottleID:info.bottleID error:&error], @"scrubbing bottled peer should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - XCTAssertTrue([list count] == 0, @"there should be 0 records in localstore"); -} - --(void) testGettingListOfRecordIDS -{ - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - XCTAssertNotNil(list, @"list should not be nil"); - XCTAssertTrue([list count] > 0, @"list of escrow record ids should not be empty"); -} - -- (nullable OTIdentity *)currentIdentity:(NSError**)error { - - return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:@"sos peer id" peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif - diff --git a/keychain/ot/tests/OTCuttlefishContextTests.m b/keychain/ot/tests/OTCuttlefishContextTests.m deleted file mode 100644 index 5c31a4e6..00000000 --- a/keychain/ot/tests/OTCuttlefishContextTests.m +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#if OCTAGON - -#import -#import -#import -#import -#import "OTTestsBase.h" -#import "OTSOSAdapter.h" - -@interface OTCuttlefishContextTests : OTTestsBase -@end - -@implementation OTCuttlefishContextTests - -- (void)setUp -{ - [super setUp]; -} - -- (void)tearDown -{ - [super tearDown]; -} - -- (void)testStateMachineInitialization { - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateMachineNotStarted] wait:10*NSEC_PER_SEC], "State machine should enter 'not started'"); - - [self.cuttlefishContext startOctagonStateMachine]; - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateInitializing] wait:10*NSEC_PER_SEC], "State machine should enter 'initializing'"); - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateUntrusted] wait:10*NSEC_PER_SEC], "State machine should enter 'signedout'"); -} - -- (void)testPrepare { - [self.cuttlefishContext startOctagonStateMachine]; - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateUntrusted] wait:10*NSEC_PER_SEC], "State machine should enter 'signedout'"); - - XCTestExpectation* rpcCallbackOccurs = [self expectationWithDescription:@"rpcPrepare callback occurs"]; - [self.cuttlefishContext prepareForApplicant:0 reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - XCTAssertNil(error, "Should be no error calling 'prepare'"); - - XCTAssertNotNil(peerID, "Prepare should have returned a peerID"); - XCTAssertNotNil(permanentInfo, "Prepare should have returned a permanentInfo"); - XCTAssertNotNil(permanentInfoSig, "Prepare should have returned a permanentInfoSig"); - XCTAssertNotNil(stableInfo, "Prepare should have returned a stableInfo"); - XCTAssertNotNil(stableInfoSig, "Prepare should have returned a stableInfoSig"); - - [rpcCallbackOccurs fulfill]; - }]; - - [self waitForExpectations:@[rpcCallbackOccurs] timeout:10]; - -} - -- (void)testPrepareTimeoutIfStateMachineUnstarted { - - XCTestExpectation* rpcCallbackOccurs = [self expectationWithDescription:@"rpcPrepare callback occurs"]; - [self.cuttlefishContext prepareForApplicant:0 reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - XCTAssertNotNil(error, "Should be an error calling 'prepare'"); - XCTAssertEqualObjects(error.domain, CKKSResultErrorDomain, "Error domain should be CKKSResultErrorDomain"); - XCTAssertEqual(error.code, CKKSResultTimedOut, "Error result should be CKKSResultTimedOut"); - - - XCTAssertNil(peerID, "Prepare should not have returned a peerID"); - XCTAssertNil(permanentInfo, "Prepare should not have returned a permanentInfo"); - XCTAssertNil(permanentInfoSig, "Prepare should not have returned a permanentInfoSig"); - XCTAssertNil(stableInfo, "Prepare should not have returned a stableInfo"); - XCTAssertNil(stableInfoSig, "Prepare should not have returned a stableInfoSig"); - - [rpcCallbackOccurs fulfill]; - }]; - - [self waitForExpectations:@[rpcCallbackOccurs] timeout:10]; -} - -@end -#endif diff --git a/keychain/ot/tests/OTEscrowKeyTests.m b/keychain/ot/tests/OTEscrowKeyTests.m deleted file mode 100644 index 44cf9961..00000000 --- a/keychain/ot/tests/OTEscrowKeyTests.m +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import -#import -#import -#import "keychain/ot/OTEscrowKeys.h" -#import "keychain/ckks/CKKS.h" -#import "OTTestsBase.h" - -static NSString* const testDSID = @"123456789"; - -static const uint8_t signingKey_384[] = { - 0x04, 0xe4, 0x1b, 0x3e, 0x88, 0x81, 0x9f, 0x3b, 0x80, 0xd0, 0x28, 0x1c, - 0xd9, 0x07, 0xa0, 0x8c, 0xa1, 0x89, 0xa8, 0x3b, 0x69, 0x91, 0x17, 0xa7, - 0x1f, 0x00, 0x31, 0x91, 0x82, 0x89, 0x1f, 0x5c, 0x44, 0x2d, 0xd6, 0xa8, - 0x22, 0x1f, 0x22, 0x7d, 0x27, 0x21, 0xf2, 0xc9, 0x75, 0xf2, 0xda, 0x41, - 0x61, 0x55, 0x29, 0x11, 0xf7, 0x71, 0xcf, 0x66, 0x52, 0x2a, 0x27, 0xfe, - 0x77, 0x1e, 0xd4, 0x3d, 0xfb, 0xbc, 0x59, 0xe4, 0xed, 0xa4, 0x79, 0x2a, - 0x9b, 0x73, 0x3e, 0xf4, 0xf4, 0xe3, 0xaf, 0xf2, 0x8d, 0x34, 0x90, 0x92, - 0x47, 0x53, 0xd0, 0x34, 0x1e, 0x49, 0x87, 0xeb, 0x11, 0x89, 0x0f, 0x9c, - 0xa4, 0x99, 0xe8, 0x4f, 0x39, 0xbe, 0x21, 0x94, 0x88, 0xba, 0x4c, 0xa5, - 0x6a, 0x60, 0x1c, 0x2f, 0x77, 0x80, 0xd2, 0x73, 0x14, 0x33, 0x46, 0x5c, - 0xda, 0xee, 0x13, 0x8a, 0x3a, 0xdb, 0x4e, 0x05, 0x4d, 0x0f, 0x6d, 0x96, - 0xcd, 0x28, 0xab, 0x52, 0x4c, 0x12, 0x2b, 0x79, 0x80, 0xfe, 0x9a, 0xe4, - 0xf4 -}; - -static const uint8_t encryptionKey_384[] = { - 0x04, 0x99, 0xf9, 0x9a, 0x9b, 0x48, 0xe2, 0xf8, 0x69, 0xd3, 0xf9, 0x60, - 0xa0, 0xf4, 0x86, 0xda, 0xb3, 0x35, 0x3d, 0x97, 0x7d, 0xc3, 0xf4, 0x13, - 0x24, 0x78, 0x06, 0x10, 0xd5, 0x46, 0x55, 0x7a, 0x8a, 0x4d, 0x80, 0x0d, - 0x71, 0x19, 0x46, 0x4b, 0x15, 0x93, 0x36, 0xb0, 0xf4, 0x6e, 0x41, 0x30, - 0x09, 0x55, 0x25, 0x3b, 0x06, 0xdd, 0xf8, 0x85, 0xdc, 0xf2, 0x0b, 0xc7, - 0x33, 0x21, 0x99, 0x3c, 0x79, 0xa6, 0xb1, 0x0f, 0xf0, 0x55, 0xfa, 0xe8, - 0x6d, 0x3f, 0x0d, 0x57, 0x21, 0x08, 0xd2, 0x7e, 0x73, 0x4a, 0xe7, 0x4a, - 0xb3, 0xdf, 0xed, 0x86, 0x06, 0xa6, 0xf2, 0x03, 0xe6, 0x20, 0xd4, 0x82, - 0x39, 0x29, 0xcf, 0x6d, 0x76, 0x3e, 0x9a, 0xaa, 0x29, 0x4f, 0x33, 0x84, - 0x5a, 0x38, 0x50, 0x35, 0xca, 0x3f, 0x69, 0x92, 0xb1, 0xb3, 0x8b, 0x26, - 0x2b, 0xb5, 0xd6, 0x25, 0xcf, 0x2d, 0x18, 0xc4, 0x5e, 0x24, 0x34, 0xc5, - 0xcc, 0x83, 0x2f, 0xff, 0x08, 0x85, 0x0f, 0x89, 0xb5, 0xb1, 0xc1, 0x17, - 0x2a -}; - -static const uint8_t symmetricKey_384[] = { - 0x31, 0xf1, 0xe3, 0x7b, 0x76, 0x3f, 0x99, 0x65, 0x74, 0xab, 0xe8, 0x2b, - 0x8f, 0x06, 0x78, 0x57, 0x1b, 0xaa, 0x07, 0xb3, 0xab, 0x79, 0x81, 0xcb, - 0xc5, 0x89, 0x1e, 0x78, 0x28, 0x8d, 0x8e, 0x36 -}; - -@interface UnitTestEscrowKeys : OTTestsBase - -@end - -@implementation UnitTestEscrowKeys - -- (void)setUp -{ - [super setUp]; - NSError *error = nil; - - self.continueAfterFailure = NO; - NSString* secretString = @"I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - - self.secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; - - XCTAssertNil(error, @"error should be initialized"); - XCTAssertNotNil(self.escrowKeys, @"escrow keys should be initialized"); -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void) testEscrowKeyAllocations -{ - XCTAssertNotNil(self.escrowKeys.symmetricKey, @"escrowed symmetric key pair should not be nil"); - XCTAssertNotNil(self.escrowKeys.secret, @"escrowed secret should not be nil"); - XCTAssertNotNil(self.escrowKeys.dsid, @"account dsid should not be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"escrowed signing key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"escrowed encryption key should not be nil"); -} --(void) testEscrowKeyTestVectors -{ - NSError* error = nil; - - //test vectors - NSData* testv1 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:self.secret dsid:testDSID error:&error]; - NSData* signingFromBytes = [[NSData alloc] initWithBytes:signingKey_384 length:sizeof(signingKey_384)]; - XCTAssertTrue([testv1 isEqualToData:signingFromBytes], @"signing keys should match"); - - NSData* testv2 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:self.secret dsid:testDSID error:&error]; - NSData* encryptionFromBytes = [[NSData alloc] initWithBytes:encryptionKey_384 length:sizeof(encryptionKey_384)]; - XCTAssertTrue([testv2 isEqualToData:encryptionFromBytes], @"encryption keys should match"); - - NSData* testv3 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:self.secret dsid:testDSID error:&error]; - NSData* symmetricKeyFromBytes = [[NSData alloc]initWithBytes:symmetricKey_384 length:sizeof(symmetricKey_384)]; - XCTAssertTrue([testv3 isEqualToData:symmetricKeyFromBytes], @"symmetric keys should match"); - - NSString* newSecretString = @"I'm f secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - NSData* newSecret = [[NSData alloc]initWithBytes:[newSecretString UTF8String] length:[newSecretString length]]; - - NSData* testv4 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv4 isEqualToData:signingFromBytes], @"signing keys should not match"); - - NSData* testv5 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv5 isEqualToData:encryptionFromBytes], @"encryption keys should not match"); - - NSData* testv6 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv6 isEqualToData:symmetricKeyFromBytes], @"symmetric keys should not match"); -} - --(void) testEmptyArguments -{ - NSError* error = nil; - OTEscrowKeys* newSet = [[OTEscrowKeys alloc] initWithSecret:[NSData data] dsid:testDSID error:&error]; - XCTAssertNotNil(error, @"error should be initialized"); - XCTAssertNil(newSet, @"escrow keys should not be initialized"); - - newSet = [[OTEscrowKeys alloc] initWithSecret:self.secret dsid:[NSString string] error:&error]; - XCTAssertNotNil(error, @"error should be initialized"); - XCTAssertNil(newSet, @"escrow keys should not be initialized"); -} - --(void) testEscrowKeyLoadingAndStoringInKeychain -{ - NSError* error = nil; - NSString* secretString = @"secret"; - NSData* secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - - OTEscrowKeys* keys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:@"dsid-123456789" error:&error]; - XCTAssertNotNil(keys, @"keys should not be nil"); - XCTAssertNil(error, "error should be nil"); - - NSString* label = [OTEscrowKeys hashEscrowedSigningPublicKey:[[keys.signingKey publicKey] encodeSubjectPublicKeyInfo]]; - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecAttrLabel: label, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnData : @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - } mutableCopy]; - - CFTypeRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - XCTAssertNotNil((__bridge NSDictionary*)result, @"result not be nil"); - XCTAssertEqual(CFDictionaryGetCount(result), 3, @"should be 3 entries"); - - XCTAssertEqual(status, 0, @"status should be 0"); - - query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecReturnAttributes: @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - } mutableCopy]; - - status = SecItemDelete((__bridge CFDictionaryRef)query); - XCTAssertEqual(status, 0, @"status should be 0"); -} - - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTLocalStoreTests.m b/keychain/ot/tests/OTLocalStoreTests.m deleted file mode 100644 index 10adeedd..00000000 --- a/keychain/ot/tests/OTLocalStoreTests.m +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import "OTTestsBase.h" - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey"; -static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordBottle = @"bottle"; - -static NSString* const testDSID = @"123456789"; - -@interface UnitTestOTLocalStore : OTTestsBase -@end - -@implementation UnitTestOTLocalStore - -- (void)setUp -{ - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void)testDBConnection -{ - NSError* error = nil; - - XCTAssertTrue([self.localStore closeDBWithError:&error], @"failed attempt at closing the db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore openDBWithError:&error], @"could not open db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore closeDBWithError:&error], @"failed attempt at closing the db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore openDBWithError:&error], @"could not open db"); - XCTAssertNil(error, @"error should be nil:%@", error); -} - --(void) testDBLocalContextRetrieval -{ - NSString* contextAndDSID = [NSString stringWithFormat:@"testContextRetreival-%@", testDSID]; - _SFECKeyPair *recoverySigningPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - _SFECKeyPair *recoveryEncryptionPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - NSError* error = nil; - NSDictionary *attributes = @{ - OTCKRecordContextID : @"testContextRetreival", - OTCKRecordDSID : testDSID, - OTCKRecordContextName : @"newFoo", - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], - OTCKRecordRecoveryEncryptionSPKI :[[recoveryEncryptionPublicKey publicKey] keyData]}; - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTContextRecord* record = [self.localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&error]; - XCTAssertNotNil(record, @"fetching attributes returned nil"); - XCTAssertNotNil(record.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(record.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(record.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(record.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(record.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(record.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(record.recoverySigningSPKI, @"fetching attributes returned nil"); - - XCTAssertNil(error, @"failed to read local context for test local store"); - - OTContextRecord* recordToTestEquality = [[OTContextRecord alloc]init]; - recordToTestEquality.contextName = @"newFoo"; - recordToTestEquality.contextID = @"testContextRetreival"; - recordToTestEquality.dsid = testDSID; - recordToTestEquality.contextName = @"newFoo"; - recordToTestEquality.egoPeerID = @"OctagonPeerID"; - recordToTestEquality.recoveryEncryptionSPKI = [[recoveryEncryptionPublicKey publicKey] keyData]; - recordToTestEquality.recoverySigningSPKI = [[recoverySigningPublicKey publicKey] keyData]; - - OTContextRecord* recordFromDB = [self.localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&error]; - XCTAssertTrue([recordFromDB isEqual:recordToTestEquality], @"OTContext should be equal"); -} - --(void) testDBMultipleContexts -{ - NSError* error = nil; - NSString* newFooContextAndDSID = [NSString stringWithFormat:@"newFoo-%@", testDSID]; - - _SFECKeyPair *recoverySigningPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - _SFECKeyPair *recoveryEncryptionPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - NSDictionary *attributes = @{ - OTCKRecordContextID : @"newFoo", - OTCKRecordContextName : @"newFoo", - OTCKRecordDSID : testDSID, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], // FIXME not SPKI - OTCKRecordRecoveryEncryptionSPKI : [[recoveryEncryptionPublicKey publicKey] keyData]}; - - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - NSString* foo2ContextAndDSID = [NSString stringWithFormat:@"Foo2-%@", testDSID]; - attributes = @{ - OTCKRecordContextID : @"Foo2", - OTCKRecordContextName : @"Foo2", - OTCKRecordDSID : testDSID, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID2", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], // FIXME not SPKI - OTCKRecordRecoveryEncryptionSPKI :[[recoveryEncryptionPublicKey publicKey] keyData]}; - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTContextRecord* recordNewFoo = [self.localStore readLocalContextRecordForContextIDAndDSID:newFooContextAndDSID error:&error]; - - XCTAssertNotNil(recordNewFoo, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.recoverySigningSPKI, @"fetching attributes returned nil"); - - XCTAssertNil(error, @"failed to read local context for test local store"); - - OTContextRecord* recordFoo2 = [self.localStore readLocalContextRecordForContextIDAndDSID:foo2ContextAndDSID error:&error]; - - XCTAssertNotNil(recordFoo2, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.recoverySigningSPKI, @"fetching attributes returned nil"); - XCTAssertNil(error, @"failed to read local context for test local store"); - -} - --(void) testRowUpdates -{ - NSError* error = nil; - NSString* escrowRecordID = @"escrow record 1"; - NSString* escrowRecordID2 = @"escrow record 2"; - NSString* escrowRecordID3 = @"escrow record 3"; - - OTBottledPeerRecord* record = [[OTBottledPeerRecord alloc]init]; - OTBottledPeerRecord* record2 = [[OTBottledPeerRecord alloc]init]; - OTBottledPeerRecord* record3 = [[OTBottledPeerRecord alloc]init]; - - record.escrowRecordID = escrowRecordID; - record2.escrowRecordID = escrowRecordID2; - record3.escrowRecordID = escrowRecordID3; - - record.escrowedSigningSPKI = [@"escrowedSigingSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - record2.escrowedSigningSPKI = [@"escrowedSigingSPI" dataUsingEncoding:NSUTF8StringEncoding]; - record3.escrowedSigningSPKI = [@"escrowedSigingSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record escrowRecordID:escrowRecordID error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record2 escrowRecordID:escrowRecordID2 error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record3 escrowRecordID:escrowRecordID3 error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - - OTBottledPeerRecord *bp = [self.localStore readLocalBottledPeerRecordWithRecordID:record.recordName error:&error]; - XCTAssertNotNil(bp); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTBottledPeerRecord *bp2 = [self.localStore readLocalBottledPeerRecordWithRecordID:record2.recordName error:&error]; - XCTAssertNotNil(bp2); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTBottledPeerRecord *bp3 = [self.localStore readLocalBottledPeerRecordWithRecordID:record3.recordName error:&error]; - XCTAssertNotNil(bp3); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordContextName newValue:(void*)@"SuperSuperFoo" error:&error], @"could not update column:%@ with value:%@", OTCKRecordContextName, @"SuperSuperFoo"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordEgoPeerID newValue:(void*)@"NewPeerID" error:&error], @"could not update column:%@ with value:%@", OTCKRecordEgoPeerID, @"NewPeerID"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordRecoverySigningSPKI newValue:(void*)[[NSData alloc]initWithBase64EncodedString:@"I'm a string" options:NSDataBase64DecodingIgnoreUnknownCharacters] error:&error], @"could not update column:%@ with value:%@", OTCKRecordContextName, @"NewPeerID"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertFalse([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:@"ColumnName" newValue:(void*)@"value" error:&error], @"could not update column:%@ with value:%@", @"ColumnName", @"value"); - XCTAssertNotNil(error, @"error should not be nil: %@", error); -} - -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTLockStateNetworkingTests.m b/keychain/ot/tests/OTLockStateNetworkingTests.m deleted file mode 100644 index 5ddc0120..00000000 --- a/keychain/ot/tests/OTLockStateNetworkingTests.m +++ /dev/null @@ -1,675 +0,0 @@ -/* -* Copyright (c) 2017 Apple Inc. All Rights Reserved. -* -* @APPLE_LICENSE_HEADER_START@ -* -* This file contains Original Code and/or Modifications of Original Code -* as defined in and that are subject to the Apple Public Source License -* Version 2.0 (the 'License'). You may not use this file except in -* compliance with the License. Please obtain a copy of the License at -* http://www.opensource.apple.com/apsl/ and read it before using this -* file. -* -* The Original Code and all software distributed under the License are -* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -* Please see the License for the specific language governing rights and -* limitations under the License. -* -* @APPLE_LICENSE_HEADER_END@ -*/ - -#if OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey"; -static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordBottle = @"bottle"; - -static NSString* OTCKRecordPeerID = @"peerID"; - -@interface OTLockStateNetworkingTests : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation OTLockStateNetworkingTests - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - self.fakeBottledPeerRecord = [bpSigned asRecord:self.sosPeerID]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - -} - -- (void)tearDown { - - [super tearDown]; -} - -//Bottle Check tests - --(void) testGrabbingBottleLocallyCheckPerfectConditions -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"]; - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSError* localError = nil; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle"); - XCTAssertNil(localError, "error should be nil"); -} - --(void) testGrabbingBottleFromCloudKitCheckPerfectConditions -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordPeerID] = self.fakeBottledPeerRecord.peerID; - newRecord[OTCKRecordSPID] = @"spID"; - newRecord[OTCKRecordEscrowSigningSPKI] = self.fakeBottledPeerRecord.escrowedSigningSPKI; - newRecord[OTCKRecordPeerSigningSPKI] = self.fakeBottledPeerRecord.peerSigningSPKI; - newRecord[OTCKRecordEscrowRecordID] = self.fakeBottledPeerRecord.escrowRecordID; - newRecord[OTCKRecordBottle] = self.fakeBottledPeerRecord.bottle; - newRecord[OTCKRecordSignatureFromEscrow] = self.fakeBottledPeerRecord.signatureUsingEscrowKey; - newRecord[OTCKRecordSignatureFromPeerKey] = self.fakeBottledPeerRecord.signatureUsingPeerKey; - - [self.otFakeZone addToZone:newRecord]; - - [self startCKKSSubsystem]; - - NSError* localError = nil; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle"); - XCTAssertNil(localError, "error should be nil"); -} - --(void) testBottleCheckWhenLocked -{ - NSError* error = nil; - self.aksLockState = true; - [self.lockStateTracker recheck]; - [self setUpRampRecordsInCloudKitWithFeatureOff]; - - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertEqual(error.code, -25308, @"error should be interaction not allowed"); -} - --(void) testBottleCheckWithNoNetwork -{ - NSError* error = nil; - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned no network error"); -} - --(void) testBottleCheckWhenNotSignedIn -{ - NSError* error = nil; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); -} - -//Bottle Update tests --(void)testBottleUpdateNotSignedIn -{ - self.spiBlockExpectation = [self expectationWithDescription:@"handle identity change spis fired"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result == NO, @"should return NO"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testBottleUpdateWithNoNetwork -{ - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error"); - }]; -} - --(void) testBottleUpdateWhenLocked -{ - self.aksLockState = true; - [self.lockStateTracker recheck]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error"); - }]; -} - -//Preflight tests --(void)testPreflightNotSignedIn -{ - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testPreflightWithNoNetwork -{ - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error"); - }]; - -} - --(void) testPreflightWhenLocked -{ - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error"); - }]; -} - -//Launch Bottle tests --(void)testLaunchNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Scrub tests --(void)testScrubNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testScrubWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testScrubWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Restore tests --(void)testRestoreNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testRestoreWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testRestoreWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Generic Ramp tests --(void)testEnrollRampNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - -} - --(void) testEnrollRampWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); -} - --(void) testEnrollRampWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); -} - --(void) testTimeBetweenCFUAttempts -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - - [self startCKKSSubsystem]; - - [self.manager scheduledCloudKitRampCheck:&error]; - XCTAssertNotNil(error, "Should have had an error scheduling a ramp check"); - XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'"); - XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted"); - NSDate* firstTime = self.manager.lastPostedCoreFollowUp; - - sleep(2); - error = nil; - - [self.manager scheduledCloudKitRampCheck:&error]; - XCTAssertNotNil(error, "Should have had an error scheduling a ramp check"); - XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'"); - XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted"); - NSDate* secondTime = self.manager.lastPostedCoreFollowUp; - - XCTAssertTrue([secondTime timeIntervalSinceDate:firstTime] >= 2, "time difference should be slightly more than 2 seconds"); -} - -@end -#endif diff --git a/keychain/ot/tests/OTRampingTests.m b/keychain/ot/tests/OTRampingTests.m deleted file mode 100644 index 63e76f81..00000000 --- a/keychain/ot/tests/OTRampingTests.m +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" -#import "keychain/ot/OTConstants.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTRampingUnitTests : OTTestsBase - -@end - -@implementation OTRampingUnitTests - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; -} - -- (void)tearDown { - [super tearDown]; -} - --(void) testPreflightWithFeatureOnOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - -} - --(void) testBottleUpdateWithFeatureOnOn -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertNil(error, "error should be nil"); - }]; -} - --(void) testLaunchWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testRestoreWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSData* localSigningKeyData = nil; - __block NSData* localEncryptionKeyData = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:localEntropy - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - localSigningKeyData = signingKeyData; - localEncryptionKeyData = encryptionKeyData; - XCTAssertNotNil(signingKeyData, "Signing key data should not be nil"); - XCTAssertNotNil(encryptionKeyData, "encryption key data should not be nil"); - XCTAssertNil(error, "error should not be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - NSError* localError = nil; - - OTIdentity *ourSelf = [self currentIdentity:&localError]; - XCTAssertTrue([localSigningKeyData isEqualToData:[ourSelf.peerSigningKey.publicKey keyData]], @"signing keys should be equal!"); - XCTAssertTrue([localEncryptionKeyData isEqualToData:[ourSelf.peerEncryptionKey.publicKey keyData]], @"signing keys should be equal!"); -} - --(void) testScrubWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"scrub scheduler fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSError* localError = nil; - NSArray* bottles = [self.localStore readAllLocalBottledPeerRecords:&localError]; - XCTAssertNotNil(localError, "error should not be nil"); - XCTAssertTrue([bottles count] == 0, "should be 0 bottles"); -} - --(void) testPreflightWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testBottleUpdateWithFeatureOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertNotNil(error, "error should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - -} - --(void) testPreflightWithRecordNotThere -{ - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertNotNil(error, "should not be nil"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} --(void) testRestoreWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testScrubWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - [self startCKKSSubsystem]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready"); -} - --(void) testRampFetchTimeout -{ - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSError* localError = nil; - - [self holdCloudKitFetches]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - localError = error; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorCKTimeOut, "should return a OTErrorCKTimeout error"); - }]; -} - --(void)testCFUWithRampOn -{ - NSError* localError = nil; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - XCTAssertTrue([self.cfu checkRampStateWithError:&localError], @"should be true"); - XCTAssertNil(localError, "Should not have gotten an error checking ramp state (and getting true)"); -} - --(void)testCFUWithRampOff -{ - NSError* localError = nil; - [self setUpRampRecordsInCloudKitWithFeatureOff]; - - [self startCKKSSubsystem]; - - XCTAssertFalse([self.cfu checkRampStateWithError:&localError], @"should be false"); - XCTAssertNil(localError, "Should not have gotten an error checking ramp state (and getting false)"); -} - --(void)testCFUWithNonExistentRampRecord -{ - NSError* localError = nil; - - [self startCKKSSubsystem]; - - XCTAssertFalse([self.cfu checkRampStateWithError:&localError], @"should be false"); - XCTAssertNotNil(localError, "Should have gotten an error checking ramp state (and getting false)"); - XCTAssertEqual(localError.code, OTErrorRecordNotFound, "Error should be 'record not found'"); -} - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTTestsBase.h b/keychain/ot/tests/OTTestsBase.h deleted file mode 100644 index 6c5a3e0c..00000000 --- a/keychain/ot/tests/OTTestsBase.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#ifndef OTTestsBase_h -#define OTTestsBase_h - -#import -#import -#import -#import "keychain/ot/OTContext.h" -#import "keychain/ot/OTJoiningConfiguration.h" -#import "keychain/ot/OTEscrowKeys.h" -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTControl.h" -#import "keychain/ot/OTManager.h" -#import "keychain/ot/OTClique.h" -#import "keychain/ot/OTCuttlefishContext.h" -#import "keychain/ot/OTClientStateMachine.h" -#import "KeychainCircle/KCJoiningRequestSession+Internal.h" -#import "KeychainCircle/KCJoiningAcceptSession+Internal.h" -#import "KeychainCircle/KCJoiningSession.h" - -#import -#import -#import -#import -#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" - -#import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" -#import "keychain/ckks/tests/CloudKitMockXCTest.h" -#import "keychain/ckks/tests/MockCloudKit.h" -#import "keychain/ckks/tests/CKKSTests.h" -#import "keychain/ckks/CKKS.h" -#import "keychain/ckks/CKKSViewManager.h" - -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OTTestsBase : CloudKitKeychainSyncingTestsBase -@property id otControl; -@property id otControlAcceptor; - - -@property OTManager* manager; -@property OTManager* managerForAcceptor; - -@property (nonatomic, strong) OTCloudStore* cloudStore; -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) FakeCKZone* otFakeZone; -@property (nonatomic, strong) CKRecordZoneID* otZoneID; -@property (nonatomic, strong) OTContext* context; -@property (nonatomic, strong) _SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) _SFECKeyPair* peerEncryptionKey; -@property (nonatomic, strong) NSData* secret; -@property (nonatomic, strong) NSString* recordName; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSString* sosPeerID; -@property (nonatomic, strong) OTEscrowKeys* escrowKeys; - -// Manager-owned cuttlefish context -@property OTCuttlefishContext* cuttlefishContext; - -@property (nonatomic, strong) FakeCKZone* rampZone; -@property (nonatomic, strong) CKRecord *enrollRampRecord; -@property (nonatomic, strong) CKRecord *restoreRampRecord; -@property (nonatomic, strong) CKRecord *cfuRampRecord; - -@property (nonatomic, strong) OTRamp *enroll; -@property (nonatomic, strong) OTRamp *restore; -@property (nonatomic, strong) OTRamp *cfu; -@property (nonatomic, strong) CKKSNearFutureScheduler* scheduler; -@property (nonatomic, strong) XCTestExpectation *expectation; -@property (nonatomic, strong) XCTestExpectation *spiBlockExpectation; - -@property (nonatomic, strong) CKRecordZoneID* rampZoneID; - -- (OTRamp*)fakeRamp:(NSString*)recordName - featureName:(NSString*)featureName - accountTracker:(CKKSAccountStateTracker*)accountTracker - lockStateStracker:(CKKSLockStateTracker*)lockStateTracker -reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker; - --(void) expectAddedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch; --(void) expectDeletedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch; --(void) setUpRampRecordsInCloudKitWithFeatureOn; --(void) setUpRampRecordsInCloudKitWithFeatureOff; - -@end -NS_ASSUME_NONNULL_END - -#endif /* OTTestsBase_h */ -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTTestsBase.m b/keychain/ot/tests/OTTestsBase.m deleted file mode 100644 index 6c85dbf7..00000000 --- a/keychain/ot/tests/OTTestsBase.m +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#if OCTAGON - -#import "OTTestsBase.h" -#import "keychain/ot/OTSOSAdapter.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testContextForAcceptor = @"Acceptor"; - -static NSString* const testDSID = @"123456789"; - -static int _test_num = 0; -static NSString* _path; -static NSString* _dbPath; - -static NSString* OTCKZoneName = @"OctagonTrust"; - -static NSString* const kOTRampZoneName = @"metadata_zone"; -static NSString* const kOTRampForEnrollmentRecordName = @"metadata_rampstate_enroll"; -static NSString* const kOTRampForRestoreRecordName = @"metadata_rampstate_restore"; -static NSString* const kOTRampForCFURecordName = @"metadata_rampstate_cfu"; - -static NSString* kFeatureAllowedKey = @"FeatureAllowed"; -static NSString* kFeaturePromotedKey = @"FeaturePromoted"; -static NSString* kFeatureVisibleKey = @"FeatureVisible"; -static NSString* kRetryAfterKey = @"RetryAfter"; -static NSString* kRampPriorityKey = @"RampPriority"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@implementation OTTestsBase - -// Override our base class --(NSSet*)managedViewList { - return [NSSet setWithObject:@"keychain"]; -} - -+ (void)setUp { - SecCKKSEnable(); - SecCKKSResetSyncing(); - [super setUp]; -} - -- (void)setUp -{ - [super setUp]; - - self.continueAfterFailure = NO; - NSError* error = nil; - - _path = @"/tmp/ottrusttests"; - _dbPath = [_path stringByAppendingFormat:@"/ottest.db.%d",_test_num++]; - - XCTAssertTrue([[NSFileManager defaultManager] createDirectoryAtPath:_path withIntermediateDirectories:YES attributes:nil error:nil], @"directory created!"); - self.localStore = [[OTLocalStore alloc]initWithContextID:testContextID dsid:testDSID path:_dbPath error:&error]; - XCTAssertNil(error, "error should be nil"); - - self.cloudStore = [[OTCloudStore alloc] initWithContainer:self.mockContainer - zoneName:OTCKZoneName - accountTracker:self.mockAccountStateTracker - reachabilityTracker:self.mockReachabilityTracker - localStore:self.localStore - contextID:testContextID - dsid:testDSID - fetchRecordZoneChangesOperationClass:self.mockFakeCKFetchRecordZoneChangesOperation - fetchRecordsOperationClass:self.mockFakeCKFetchRecordZoneChangesOperation - queryOperationClass:self.mockFakeCKQueryOperation - modifySubscriptionsOperationClass:self.mockFakeCKModifySubscriptionsOperation - modifyRecordZonesOperationClass:self.mockFakeCKFetchRecordsOperation - apsConnectionClass:self.mockFakeCKModifySubscriptionsOperation - operationQueue:nil]; - - NSString* secretString = @"I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - self.secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - - self.context = [[OTContext alloc]initWithContextID:testContextID dsid:testDSID localStore:self.localStore cloudStore:self.cloudStore identityProvider:self error:&error]; - XCTAssertNil(error, "error should be nil"); - - self.sosPeerID = @"spID"; - self.egoPeerID = @"egoPeerID"; - self.peerSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.peerEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; - - XCTAssertNotNil(self.context, @"context not initialized"); - - self.otZoneID = [[CKRecordZoneID alloc] initWithZoneName:OTCKZoneName ownerName:CKCurrentUserDefaultName]; - - XCTAssertNotNil(self.otZoneID, @"cloudkit record zone id is not initialized"); - - self.otFakeZone = [[FakeCKZone alloc] initZone: self.otZoneID]; - XCTAssertNotNil(self.otFakeZone, @"fake ot zone is not initialized"); - - self.zones[self.otZoneID] = self.otFakeZone; - XCTAssertNotNil(self.zones, @"ot zones set is not initialized"); - - self.rampZoneID = [[CKRecordZoneID alloc] initWithZoneName:kOTRampZoneName ownerName:CKCurrentUserDefaultName]; - self.rampZone = [[FakeCKZone alloc]initZone:self.rampZoneID]; - self.zones[self.rampZoneID] = self.rampZone; - - self.cfu = [self fakeRamp:kOTRampForCFURecordName - featureName:@"FAKE-cfu" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - self.enroll = [self fakeRamp:kOTRampForEnrollmentRecordName - featureName:@"FAKE-enroll" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - self.restore = [self fakeRamp:kOTRampForRestoreRecordName - featureName:@"FAKE-restore" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - - self.scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - [self.expectation fulfill]; - }]; - self.manager = [[OTManager alloc] initWithContext:self.context - localStore:self.localStore - enroll:self.enroll - restore:self.restore - cfu:self.cfu - cfuScheduler:self.scheduler - sosAdapter:[[OTSOSActualAdapter alloc] init] - authKitAdapter:[[OTAuthKitActualAdapter alloc] init] - apsConnectionClass:[FakeAPSConnection class]]; - [OTManager resetManager:true to:self.manager]; - - self.cuttlefishContext = [self.manager contextForContainerName:OTCKContainerName - contextID:OTDefaultContext]; - - id mockConnection = OCMPartialMock([[NSXPCConnection alloc] init]); - OCMStub([mockConnection remoteObjectProxyWithErrorHandler:[OCMArg any]]).andCall(self, @selector(manager)); - self.otControl = [[OTControl alloc] initWithConnection:mockConnection sync:true]; - XCTAssertNotNil(self.otControl, "Should have received control object"); - - [self.reachabilityTracker setNetworkReachability:true]; - [self.context.reachabilityTracker recheck]; - [self.cfu.reachabilityTracker recheck]; - [self.enroll.reachabilityTracker recheck]; - [self.restore.reachabilityTracker recheck]; -} - - -- (void)tearDown -{ - NSError *error = nil; - - [_localStore removeAllBottledPeerRecords:&error]; - [_localStore deleteAllContexts:&error]; - - _context = nil; - _cloudStore = nil; - _localStore = nil; - _escrowKeys = nil; - _peerSigningKey = nil; - _peerEncryptionKey = nil; - _otFakeZone = nil; - _otZoneID = nil; - - _rampZone = nil; - _rampZoneID = nil; - _cfuRampRecord = nil; - _enrollRampRecord = nil; - _restoreRampRecord = nil; - _scheduler = nil; - - [super tearDown]; -} - -- (OTRamp*)fakeRamp:(NSString*)recordName - featureName:(NSString*)featureName - accountTracker:(CKKSAccountStateTracker*)accountTracker - lockStateStracker:(CKKSLockStateTracker*)lockStateTracker -reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker -{ - - OTRamp* ramp = [[OTRamp alloc]initWithRecordName:recordName - featureName:featureName - container:self.mockContainer - database:self.mockDatabase - zoneID:self.rampZoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:self.mockFakeCKFetchRecordsOperation]; - - return ramp; -} - --(void) setUpRampRecordsInCloudKitWithFeatureOff -{ - CKRecordID* enrollRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForEnrollmentRecordName zoneID:self.rampZoneID]; - self.enrollRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:enrollRecordID]; - self.enrollRampRecord[kFeatureAllowedKey] = @NO; - self.enrollRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.enrollRampRecord[kFeatureVisibleKey] = @NO; - self.enrollRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* restoreRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForRestoreRecordName zoneID:self.rampZoneID]; - self.restoreRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:restoreRecordID]; - self.restoreRampRecord[kFeatureAllowedKey] = @NO; - self.restoreRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.restoreRampRecord[kFeatureVisibleKey] = @NO; - self.restoreRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* cfuRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForCFURecordName zoneID:self.rampZoneID]; - self.cfuRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForCFURecordName recordID:cfuRecordID]; - self.cfuRampRecord[kFeatureAllowedKey] = @NO; - self.cfuRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.cfuRampRecord[kFeatureVisibleKey] = @NO; - self.cfuRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - [self.rampZone addToZone:self.enrollRampRecord]; - [self.rampZone addToZone:self.restoreRampRecord]; - [self.rampZone addToZone:self.cfuRampRecord]; -} - --(void) setUpRampRecordsInCloudKitWithFeatureOn -{ - CKRecordID* enrollRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForEnrollmentRecordName zoneID:self.rampZoneID]; - self.enrollRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:enrollRecordID]; - self.enrollRampRecord[kFeatureAllowedKey] = @YES; - self.enrollRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.enrollRampRecord[kFeatureVisibleKey] = @YES; - self.enrollRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* restoreRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForRestoreRecordName zoneID:self.rampZoneID]; - self.restoreRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:restoreRecordID]; - self.restoreRampRecord[kFeatureAllowedKey] = @YES; - self.restoreRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.restoreRampRecord[kFeatureVisibleKey] = @YES; - self.restoreRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* cfuRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForCFURecordName zoneID:self.rampZoneID]; - self.cfuRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForCFURecordName recordID:cfuRecordID]; - self.cfuRampRecord[kFeatureAllowedKey] = @YES; - self.cfuRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.cfuRampRecord[kFeatureVisibleKey] = @YES; - self.cfuRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - [self.rampZone addToZone:self.enrollRampRecord]; - [self.rampZone addToZone:self.restoreRampRecord]; - [self.rampZone addToZone:self.cfuRampRecord]; -} - - --(void)expectAddedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch -{ - __weak __typeof(self) weakSelf = self; - - [self expectCKModifyRecords:records - deletedRecordTypeCounts:nil - zoneID:self.otZoneID - checkModifiedRecord:^BOOL (CKRecord* record){ - if([record.recordType isEqualToString: OTCKRecordBottledPeerType]) { - return YES; - } else { //not a Bottled Peer Record Type - return NO; - } - } - runAfterModification:^{ - __strong __typeof(self) strongSelf = weakSelf; - if(shouldHoldTheFetch){ - [strongSelf holdCloudKitFetches]; - } - - } - ]; -} - --(void)expectDeletedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch -{ - __weak __typeof(self) weakSelf = self; - - [self expectCKModifyRecords:[NSMutableDictionary dictionary] - deletedRecordTypeCounts:records - zoneID:self.otZoneID - checkModifiedRecord:^BOOL (CKRecord* record){ - if([record.recordType isEqualToString: OTCKRecordBottledPeerType]) { - return YES; - } else { //not a Bottled Peer Record Type - return NO; - } - } - runAfterModification:^{ - __strong __typeof(self) strongSelf = weakSelf; - if(shouldHoldTheFetch){ - [strongSelf holdCloudKitFetches]; - } - } - ]; -} - -- (nullable OTIdentity *)currentIdentity:(NSError * _Nullable __autoreleasing * _Nullable)error { - return [[OTIdentity alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif diff --git a/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift b/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift index ed7f96f1..0b457d23 100644 --- a/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift +++ b/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift @@ -160,7 +160,7 @@ class OctagonAccountMetadataClassCPersistenceTests: CloudKitKeychainSyncingMockX state.trustState = .TRUSTED XCTAssertNoThrow(try state.saveToKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext), "saving to the keychain should work") - let deleted:Bool = try OTAccountMetadataClassC.deleteFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext) + let deleted: Bool = try OTAccountMetadataClassC.deleteFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext) XCTAssertTrue(deleted, "deleteFromKeychain should return true") XCTAssertThrowsError(try OTAccountMetadataClassC.loadFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext)) } diff --git a/keychain/ot/tests/octagon/OctagonTestMocks.swift b/keychain/ot/tests/octagon/OctagonTestMocks.swift index 61050145..a9d31759 100644 --- a/keychain/ot/tests/octagon/OctagonTestMocks.swift +++ b/keychain/ot/tests/octagon/OctagonTestMocks.swift @@ -2,29 +2,45 @@ import Foundation class OTMockSecureBackup: NSObject, OctagonEscrowRecovererPrococol { - let bottleID : String - let entropy : Data + let bottleID: String? + let entropy: Data? - init(bottleID: String, entropy: Data) { + init(bottleID: String?, entropy: Data?) { self.bottleID = bottleID self.entropy = entropy super.init() } - func recover(withInfo info: [AnyHashable : Any]!, + func recover(withInfo info: [AnyHashable: Any]!, results: AutoreleasingUnsafeMutablePointer!) -> Error! { - results.pointee = [ - "bottleID": self.bottleID, - "bottleValid": "valid", - "EscrowServiceEscrowData" : ["BottledPeerEntropy": entropy], - ] + if self.bottleID == nil && self.entropy == nil { + results.pointee = [ + "bottleValid": "invalid", + ] + } else if self.bottleID == nil && self.entropy != nil { + results.pointee = [ + "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy], + "bottleValid": "invalid", + ] + } else if self.bottleID != nil && self.entropy == nil { + results.pointee = [ + "bottleID": self.bottleID!, + "bottleValid": "invalid", + ] + } else { //entropy and bottleID must exist, so its a good bottle. + results.pointee = [ + "bottleID": self.bottleID!, + "bottleValid": "valid", + "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy], + ] + } return nil } } class OTMockFollowUpController: NSObject, OctagonFollowUpControllerProtocol { - var postedFollowUp : Bool = false + var postedFollowUp: Bool = false override init() { super.init() diff --git a/keychain/ot/tests/octagon/OctagonTests+CKKS.swift b/keychain/ot/tests/octagon/OctagonTests+CKKS.swift index 40299eab..d088ab71 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CKKS.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CKKS.swift @@ -16,7 +16,7 @@ class OctagonCKKSTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -48,7 +48,7 @@ class OctagonCKKSTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") diff --git a/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift b/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift index 8d4c26c4..5a43ca54 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift @@ -127,6 +127,8 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + // On CK account sign-out, Octagon should go back to 'wait for cloudkit account' self.accountStatus = .noAccount self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() @@ -167,11 +169,61 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) - // On CK account sign-out, Octagon should go back to 'wait for cloudkit account' + // On CK account sign-out, Octagon should stay in 'wait for hsa2': if there's no HSA2, we don't actually care about the CK account status + self.accountStatus = .noAccount + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + + // On sign-out, octagon should go back to 'no account' + self.mockAuthKit.altDSID = nil + XCTAssertNoThrow(try self.cuttlefishContext.accountNoLongerAvailable(), "sign-out shouldn't error") + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + } + + func testSAtoHSA2PromotionWithoutCloudKit() throws { + self.startCKAccountStatusMock() + + // Device is signed out + self.mockAuthKit.altDSID = nil + self.mockAuthKit.hsa2 = false + self.accountStatus = .noAccount self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + // With no account, Octagon should go directly into 'NoAccount' + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) + + // Account signs in as SA. + let newAltDSID = UUID().uuidString + self.mockAuthKit.altDSID = newAltDSID + + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(newAltDSID), "Sign-in shouldn't error") + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + // Account promotes to HSA2 + self.mockAuthKit.hsa2 = true + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + + // Octagon should go into 'waitforcloudkit' self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitingForCloudKitAccount, within: 10 * NSEC_PER_SEC) + self.assertAccountAvailable(context: self.cuttlefishContext) + + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + + // On CK account sign-in, Octagon should race to 'untrusted' + self.accountStatus = .available + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // On sign-out, octagon should go back to 'no account' self.mockAuthKit.altDSID = nil @@ -179,6 +231,47 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) self.assertNoAccount(context: self.cuttlefishContext) + // But CKKS is listening for the CK account removal, not the accountNoLongerAvailable call + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + self.accountStatus = .noAccount + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + } + + func testAPIFailureWhenSA() throws { + self.startCKAccountStatusMock() + + // Account is present, but SA + self.mockAuthKit.hsa2 = false + + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(self.mockAuthKit.altDSID!), "Sign-in shouldn't error") + + self.cuttlefishContext.startOctagonStateMachine() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + // Calling OTClique API should error (eventually) + self.cuttlefishContext.stateMachine.setWatcherTimeout(4 * NSEC_PER_SEC) + XCTAssertThrowsError(try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated), "establishing new friends in an SA account should error") + + // And octagon should still believe everything is terrible + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + XCTAssertEqual(self.cuttlefishContext.currentMemoizedTrustState(), .UNKNOWN, "Trust state should be unknown") + + let statusexpectation = self.expectation(description: "trust status returns") + let configuration = OTOperationConfiguration() + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in + XCTAssertEqual(.noCloudKitAccount, egoStatus, "cliqueStatus should be 'no cloudkit account'") + statusexpectation.fulfill() + } + self.wait(for: [statusexpectation], timeout: 10) + + self.assertNoAccount(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) } } diff --git a/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift b/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift index 87e68aba..c2692037 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift @@ -1,4 +1,3 @@ - #if OCTAGON class OctagonCoreFollowUpTests: OctagonTestsBase { @@ -54,16 +53,19 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } func testAttemptedJoinNotAttemptedStateSOSEnabled() throws { self.startCKAccountStatusMock() + self.mockSOSAdapter.sosEnabled = true + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + // Prepare an identity, then pretend like securityd thought it was in the right account let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -110,9 +112,72 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) // CKKS should be waiting for assistance - assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Since SOS isn't around to help, Octagon should post a CFU + #if os(tvOS) + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV (due to having no peers to join)") + #else + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS can't help") + #endif + } + + func testAttemptedJoinNotAttemptedStateSOSError() throws { + self.startCKAccountStatusMock() + + self.mockSOSAdapter.sosEnabled = true + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCError) + + // Prepare an identity, then pretend like securityd thought it was in the right account + let containerName = OTCKContainerName + let contextName = OTDefaultContext + + var selfPeerID: String? + let prepareExpectation = self.expectation(description: "prepare callback occurs") + tphClient.prepare(withContainer: containerName, + context: contextName, + epoch: 0, + machineID: "asdf", + bottleSalt: "123456789", + bottleID: UUID().uuidString, + modelID: "asdf", + deviceName: "asdf", + serialNumber: "1234", + osVersion: "asdf", + policyVersion: nil, + policySecrets: nil, + signingPrivKeyPersistentRef: nil, + encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in + XCTAssertNil(error, "Should be no error preparing identity") + XCTAssertNotNil(peerID, "Should be a peer ID") + XCTAssertNotNil(permanentInfo, "Should have a permenent info") + XCTAssertNotNil(permanentInfoSig, "Should have a permanent info signature") + XCTAssertNotNil(stableInfo, "Should have a stable info") + XCTAssertNotNil(stableInfoSig, "Should have a stable info signature") + selfPeerID = peerID + + prepareExpectation.fulfill() + } + self.wait(for: [prepareExpectation], timeout: 10) + + let account = OTAccountMetadataClassC()! + account.peerID = selfPeerID + account.icloudAccountState = .ACCOUNT_AVAILABLE + account.trustState = .TRUSTED + account.attemptedJoin = .NOTATTEMPTED + + XCTAssertNoThrow(try account.saveToKeychain(forContainer: containerName, contextID: contextName), "Should be no error saving fake account metadata") + + OctagonInitialize() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "should NOT have posted an repair CFU"); + // CKKS should be waiting for assistance + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Since SOS is in 'error', octagon shouldn't post until SOS can say y/n + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "should NOT have posted an repair CFU") } func testAttemptedJoinNotAttemptedStateSOSDisabled() throws { @@ -130,10 +195,10 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS is disabled"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS is disabled") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } @@ -189,10 +254,10 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } @@ -208,7 +273,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") // Now, an iphone appears! let iphone = self.manager.context(forContainerName: OTCKContainerName, @@ -221,7 +286,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { iphone.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - iphone.rpcResetAndEstablish() { resetError in + iphone.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -231,7 +296,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { // The TV should now post a CFU, as there's an iphone that can repair it self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU") } func testDontPostCFUWhenApprovalIncapablePeerJoins() throws { @@ -245,7 +310,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") // Now, a mac appears! macs cannot fix apple TVs. let mac = self.manager.context(forContainerName: OTCKContainerName, @@ -258,7 +323,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { mac.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - mac.rpcResetAndEstablish() { resetError in + mac.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -268,9 +333,96 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { // The TV should not post a CFU, as there's still no iPhone to repair it self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU; no devices present can repair it"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU; no devices present can repair it") + } + + func testDontPostCFUWhenCapablePeersAreUntrusted() throws { + self.startCKAccountStatusMock() + // Octagon only examines the JoinState if SOS is enabled + self.mockSOSAdapter.sosEnabled = false + + // An iPhone establishes some octagon state, then untrusts itself + // This is techinically an invalid situation, since Cuttlefish should have rejected the untrust, but it should trigger the condition we're interested in + + let iphone = self.manager.context(forContainerName: OTCKContainerName, + contextID: "firstPhone", + sosAdapter: self.mockSOSAdapter, + authKitAdapter: self.mockAuthKit2, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + iphone.startOctagonStateMachine() + + let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") + iphone.rpcResetAndEstablish(.testGenerated) { resetError in + XCTAssertNil(resetError, "should be no error resetting and establishing") + resetAndEstablishExpectation.fulfill() + } + self.wait(for: [resetAndEstablishExpectation], timeout: 10) + + let iphonePeerID = try iphone.accountMetadataStore.loadOrCreateAccountMetadata().peerID! + + let leaveExpectation = self.expectation(description: "rpcLeaveClique returns") + iphone.rpcLeaveClique { leaveError in + XCTAssertNil(leaveError, "Should be no error leaving") + leaveExpectation.fulfill() + } + self.wait(for: [leaveExpectation], timeout: 10) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: iphonePeerID, opinion: .excludes, target: iphonePeerID)), + "iphone should distrust itself") + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + // Ensure that the aTV has fetched properly + self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext) + + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Apple TV should not post a CFU, as the only iPhone around is untrusted + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") + + // Another iPhone resets the world + let iphone2 = self.manager.context(forContainerName: OTCKContainerName, + contextID: "firstPhone", + sosAdapter: self.mockSOSAdapter, + authKitAdapter: self.mockAuthKit3, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + iphone2.startOctagonStateMachine() + + let resetAndEstablishExpectation2 = self.expectation(description: "resetAndEstablishExpectation returns") + iphone2.rpcResetAndEstablish(.testGenerated) { resetError in + XCTAssertNil(resetError, "should be no error resetting and establishing") + resetAndEstablishExpectation2.fulfill() + } + self.wait(for: [resetAndEstablishExpectation2], timeout: 10) + + // The aTV is notified, and now posts a CFU + self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext) + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU") } #endif + + func testPostCFUAfterSOSUpgradeFails() throws { + self.startCKAccountStatusMock() + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + #if os(tvOS) + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV (due to having no peers to join)") + #else + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS can't help") + #endif + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift index f601b5f6..3fa30c28 100644 --- a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift +++ b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift @@ -17,10 +17,10 @@ class OctagonDeviceListTests: OctagonTestsBase { let expectFail = self.expectation(description: "expect to fail") do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNil(clique, "Clique should be nil") } catch { - expectFail.fulfill(); + expectFail.fulfill() } self.wait(for: [expectFail], timeout: 10) @@ -41,7 +41,7 @@ class OctagonDeviceListTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -148,7 +148,6 @@ class OctagonDeviceListTests: OctagonTestsBase { "peer 1 should distrust peer 2 after update") } - func testTrustPeerWhenMissingFromDeviceList() throws { self.startCKAccountStatusMock() @@ -394,9 +393,9 @@ class OctagonDeviceListTests: OctagonTestsBase { // Peer 2 is not on Peer 1's machine ID list yet self.mockAuthKit.otherDevices.remove(self.mockAuthKit2.currentMachineID) - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() let joiningContext = self.makeInitiatorContext(contextID: "joiner", authKitAdapter: self.mockAuthKit2) - let _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) + _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) // Now, add peer2 to the machineID list, but don't send peer1 a notification about the IDMS change self.mockAuthKit.otherDevices.insert(self.mockAuthKit2.currentMachineID) @@ -415,7 +414,7 @@ class OctagonDeviceListTests: OctagonTestsBase { // At this time, peer1 should trust peer2, but it should _not_ have fetched the AuthKit list, // because peer2 is still within the 48 hour grace period. peer1 is hoping for a push to arrive. - XCTAssertNotEqual(condition.wait(2*NSEC_PER_SEC), 0, "Octagon should not fetch the authkit machine ID list") + XCTAssertNotEqual(condition.wait(2 * NSEC_PER_SEC), 0, "Octagon should not fetch the authkit machine ID list") let peer2MIDSet = Set([self.mockAuthKit2.currentMachineID]) self.assertMIDList(context: self.cuttlefishContext, allowed: self.mockAuthKit.currentDeviceList().subtracting(peer2MIDSet), @@ -429,7 +428,7 @@ class OctagonDeviceListTests: OctagonTestsBase { if machinemo.machineID == self.mockAuthKit2.currentMachineID { foundPeer2 = true // - machinemo.modified = Date(timeIntervalSinceNow: -60*60*TimeInterval(72)) + machinemo.modified = Date(timeIntervalSinceNow: -60 * 60 * TimeInterval(72)) XCTAssertEqual(machinemo.status, Int64(TPMachineIDStatus.unknown.rawValue), "peer2's MID entry should be 'unknown'") } } @@ -441,7 +440,7 @@ class OctagonDeviceListTests: OctagonTestsBase { self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - XCTAssertEqual(condition.wait(10*NSEC_PER_SEC), 0, "Octagon should fetch the authkit machine ID list") + XCTAssertEqual(condition.wait(10 * NSEC_PER_SEC), 0, "Octagon should fetch the authkit machine ID list") self.assertMIDList(context: self.cuttlefishContext, allowed: self.mockAuthKit.currentDeviceList()) } @@ -501,7 +500,7 @@ class OctagonDeviceListTests: OctagonTestsBase { sleep(1) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) - + self.wait(for: [updateTrustExpectation], timeout: 10) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) diff --git a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift index bba5d235..e838a1af 100644 --- a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift +++ b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift @@ -1,4 +1,3 @@ - #if OCTAGON class OctagonErrorHandlingTests: OctagonTestsBase { @@ -17,7 +16,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { userInfo: [:]) } - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() self.wait(for: [establishExpectation], timeout: 10) } @@ -26,7 +25,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { let establishExpectation = self.expectation(description: "establishExpectation") - var t0: Date = Date.distantPast + var t0 = Date.distantPast self.fakeCuttlefishServer.establishListener = { [unowned self] request in self.fakeCuttlefishServer.establishListener = nil @@ -36,12 +35,40 @@ class OctagonErrorHandlingTests: OctagonTestsBase { return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .retryableServerFailure) } - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() self.wait(for: [establishExpectation], timeout: 10) let t1 = Date() let d = t0.distance(to: t1) XCTAssertGreaterThanOrEqual(d, 4) - XCTAssertLessThanOrEqual(d, 6) + // Let slower devices have a few extra seconds: we expect this after 5s, but sometimes they need a bit. + XCTAssertLessThanOrEqual(d, 8) + } + + func testRecoverFromTransactionalErrorDuringJoinWithVoucher() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + var t0 = Date.distantPast + + let joinExpectation = self.expectation(description: "joinExpectation") + self.fakeCuttlefishServer.joinListener = { [unowned self] _ in + self.fakeCuttlefishServer.joinListener = nil + joinExpectation.fulfill() + + t0 = Date() + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) + } + + let joiningContext = self.makeInitiatorContext(contextID: "joiner", authKitAdapter: self.mockAuthKit2) + _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) + + self.wait(for: [joinExpectation], timeout: 10) + let t1 = Date() + let d = t0.distance(to: t1) + XCTAssertGreaterThanOrEqual(d, 4) + // Let slower devices have a few extra seconds: we expect this after 5s, but sometimes they need a bit. + XCTAssertLessThanOrEqual(d, 8) } func testReceiveUpdateWhileUntrustedAndLocked() { @@ -66,7 +93,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -123,7 +150,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -134,9 +161,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertConsidersSelfTrusted(context: self.cuttlefishContext) self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext) - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.sendContainerChange(context: self.cuttlefishContext) @@ -155,7 +182,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -169,9 +196,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.aksLockState = true self.lockStateTracker.recheck() - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.sendContainerChange(context: self.cuttlefishContext) @@ -202,7 +229,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -215,18 +242,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { let pre = self.fakeCuttlefishServer.fetchChangesCalledCount - - let cuttlefishError = NSError(domain:CuttlefishErrorDomain, - code:CuttlefishErrorCode.transactionalFailure.rawValue, - userInfo:nil) - let ckInternalError = NSError(domain:CKInternalErrorDomain, - code:CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo:[NSUnderlyingErrorKey: cuttlefishError]) - let ckError = NSError(domain:CKErrorDomain, - code:CKError.serverRejectedRequest.rawValue, - userInfo:[NSUnderlyingErrorKey: ckInternalError]) - - + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) @@ -242,7 +258,6 @@ class OctagonErrorHandlingTests: OctagonTestsBase { XCTAssertEqual(post, pre + 2, "should have fetched two times, the first response would have been a transaction error") } - func testPreapprovedPushWhileLocked() throws { // Peer 1 becomes SOS+Octagon self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) @@ -344,9 +359,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() - let clique : OTClique + let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -376,7 +391,6 @@ class OctagonErrorHandlingTests: OctagonTestsBase { machineID: "b-machine-id", otherDevices: [self.mockAuthKit.currentMachineID]) - let bRestoreContext = self.manager.context(forContainerName: OTCKContainerName, contextID: bNewOTCliqueContext.context!, sosAdapter: OTSOSMissingAdapter(), @@ -435,6 +449,68 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.wait(for: [updateTrustExpectation], timeout: 30) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } + + func testCKKSResetRecoverFromCKKSConflict() throws { + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) + // But do NOT add them to the keychain + + // CKKS should get stuck in waitfortlk + self.startCKAccountStatusMock() + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + do { + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + } + + // Now, we should be in 'ready', and CKKS should be stuck + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) + + // Now, CKKS decides to reset the world, but a conflict occurs on hierarchy upload + self.silentZoneDeletesAllowed = true + var tlkUUIDs : [CKRecordZone.ID:String] = [:] + + self.silentFetchesAllowed = false + self.expectCKFetchAndRun(beforeFinished: { + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) + self.silentFetchesAllowed = true + + // Use the commented version below when multi-zone support is readded to the tets + tlkUUIDs[self.manateeZoneID!] = (self.keys![self.manateeZoneID!] as? ZoneKeys)?.tlk?.uuid + /* + for zoneID in self.ckksZones { + tlkUUIDs[zoneID as! CKRecordZone.ID] = (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid + } + */ + }) + + let resetExepctation = self.expectation(description: "reset callback is called") + self.cuttlefishContext.viewManager!.rpcResetCloudKit(nil, reason: "unit-test") { + error in + XCTAssertNil(error, "should be no error resetting cloudkit") + resetExepctation.fulfill() + } + + // Deletions should occur, then the fetches, then get stuck (as we don't have the TLK) + self.wait(for: [resetExepctation], timeout: 10) + self.verifyDatabaseMocks() + + // all subCKKSes should get stuck in waitfortlk + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + XCTAssertEqual(tlkUUIDs.count, self.ckksZones.count, "Should have the right number of conflicted TLKs") + for (zoneID,tlkUUID) in tlkUUIDs { + XCTAssertEqual(tlkUUID, (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid, "TLK should match conflicted version") + } + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift b/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift index 184b0dfc..64a4006f 100644 --- a/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift +++ b/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift @@ -25,7 +25,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -104,7 +104,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -171,7 +171,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -229,7 +229,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -262,8 +262,8 @@ // The first peer will upload TLKs for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() self.assertTrusts(context: self.cuttlefishContext, includedPeerIDCount: 2, excludedPeerIDCount: 0) @@ -293,7 +293,7 @@ self.assertTrusts(context: differentDevice, includedPeerIDCount: 2, excludedPeerIDCount: 1) // Then, if by some strange miracle the original peer is still around, it should bail (as it's now untrusted) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext, states: [OctagonStateUntrusted]) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) self.assertTrusts(context: self.cuttlefishContext, includedPeerIDCount: 0, excludedPeerIDCount: 1) } @@ -307,7 +307,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -363,7 +363,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -415,7 +415,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -463,10 +463,10 @@ // We will upload a new TLK for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) bottleIDs = try OTClique.findOptimalBottleIDs(withContextData: self.otcliqueContext) XCTAssertNotNil(bottleIDs.preferredBottleIDs, "preferredBottleIDs should not be nil") XCTAssertEqual(bottleIDs.preferredBottleIDs.count, 2, "preferredBottleIDs should have 2 bottle") @@ -478,7 +478,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -536,10 +536,10 @@ // We will upload a new TLK for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) bottleIDs = try OTClique.findOptimalBottleIDs(withContextData: self.otcliqueContext) XCTAssertNotNil(bottleIDs.preferredBottleIDs, "preferredBottleIDs should not be nil") @@ -591,7 +591,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) @@ -677,7 +677,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -717,7 +717,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -756,7 +756,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -796,7 +796,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -832,7 +832,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -858,7 +858,6 @@ // To get into the state we need, we need to introduce peer B and C. C should then distrust A, whose bottle it used // B shouldn't have an opinion of C. - let bNewOTCliqueContext = OTConfigurationContext() bNewOTCliqueContext.context = "restoreB" bNewOTCliqueContext.dsid = self.otcliqueContext.dsid @@ -982,7 +981,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1042,7 +1041,6 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - //now call fetchviablebottles, we should get the uncached version let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles") @@ -1068,7 +1066,6 @@ fetchViableExpectation.fulfill() } self.wait(for: [fetchViableExpectation], timeout: 10) - //now call fetchviablebottles, we should get the cached version let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles") @@ -1110,7 +1107,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1140,7 +1137,6 @@ // Note: CKKS will want to upload a TLKShare for its self self.expectCKModifyKeyRecords(0, currentKeyPointerRecords: 0, tlkShareRecords: 1, zoneID: self.manateeZoneID) - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") self.cuttlefishContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.otcliqueContext.altDSID) { error in XCTAssertNil(error, "error should be nil") @@ -1171,7 +1167,6 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - //now call fetchviablebottles, we should get the uncached version let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles") @@ -1238,7 +1233,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1268,7 +1263,6 @@ // Note: CKKS will want to upload a TLKShare for its self self.expectCKModifyKeyRecords(0, currentKeyPointerRecords: 0, tlkShareRecords: 1, zoneID: self.manateeZoneID) - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") self.cuttlefishContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.otcliqueContext.altDSID) { error in XCTAssertNil(error, "error should be nil") @@ -1302,7 +1296,7 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let bottles:[Bottle] = self.fakeCuttlefishServer.state.bottles + let bottles: [Bottle] = self.fakeCuttlefishServer.state.bottles var bottleToExclude: String? bottles.forEach { bottle in if bottle.peerID == egoPeerID { diff --git a/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift b/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift index 9d00a5ce..e1fd51bd 100644 --- a/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift +++ b/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift @@ -10,27 +10,27 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.startCKAccountStatusMock() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - + let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") throw error } - + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) XCTAssertEqual(2, accountState.trustState.rawValue, "saved account should be trusted") } catch { XCTFail("error loading account state: \(error)") } - + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in XCTAssertNil(error, "error should be nil") @@ -47,7 +47,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { dumpCallback.fulfill() } self.wait(for: [dumpCallback], timeout: 10) - + self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } @@ -68,11 +68,18 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + #if os(tvOS) XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV") + #else + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, true, "Should have posted a CFU (due to being untrusted)") + #endif self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + // Reset flag for remainder of test + self.cuttlefishContext.setPostedBool(false) + // Set the "have I attempted to join" bit; TVs should still not CFU, but other devices should try! self.cuttlefishContext.accountMetadataStore.persistOctagonJoinAttempt(.ATTEMPTED) @@ -89,7 +96,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, true, "Should have posted a CFU") #endif } - + func testHealthCheckSecurityDStateNOTTrusted() throws { let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -101,17 +108,17 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") throw error } - + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + //now let's ruin account state, and say we are untrusted do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) @@ -121,14 +128,14 @@ class OctagonHealthCheckTests: OctagonTestsBase { } catch { XCTFail("error loading account state: \(error)") } - + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNil(error, "error should be nil") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) - + self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: cuttlefishContext) @@ -146,11 +153,11 @@ class OctagonHealthCheckTests: OctagonTestsBase { dumpCallback.fulfill() } self.wait(for: [dumpCallback], timeout: 10) - + self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } - + func testHealthCheckTrustedPeersHelperStateNOTTrusted() throws { let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -162,7 +169,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -172,21 +179,21 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) XCTAssertEqual(2, accountState.trustState.rawValue, "Saved account state should be trusted") } catch { XCTFail("error loading account state: \(error)") } - + var healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNil(error, "error should be nil") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) - + // now lets completely wipe cuttlefish state let resetCallback = self.expectation(description: "resetCallback callback occurs") self.tphClient.localReset(withContainer: containerName, context: contextName) { error in @@ -194,7 +201,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { resetCallback.fulfill() } self.wait(for: [resetCallback], timeout: 10) - + healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNotNil(error, "error should not be nil") @@ -220,7 +227,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -269,22 +276,22 @@ class OctagonHealthCheckTests: OctagonTestsBase { func testCuttlefishResponseNoAction() throws { self.fakeCuttlefishServer.returnNoActionResponse = true let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertFalse(self.otFollowUpController.postedFollowUp, "should not have posted a CFU"); - XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted a CFU"); + XCTAssertFalse(self.otFollowUpController.postedFollowUp, "should not have posted a CFU") + XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted a CFU") } func testCuttlefishResponseRepairAccount() throws { self.fakeCuttlefishServer.returnRepairAccountResponse = true let (_, _) = try responseTestsSetup() - XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU"); + XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU") } func testCuttlefishResponseRepairEscrow() throws { self.fakeCuttlefishServer.returnRepairEscrowResponse = true OTMockSecEscrowRequest.self.populateStatuses = false let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU"); - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, true, "should have posted an escrow CFU"); + XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU") + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, true, "should have posted an escrow CFU") } func testCuttlefishResponseResetOctagon() throws { @@ -315,12 +322,11 @@ class OctagonHealthCheckTests: OctagonTestsBase { } func testCuttlefishResponseError() throws { - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - self.fakeCuttlefishServer.returnRepairErrorResponse = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + self.fakeCuttlefishServer.returnRepairErrorResponse = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired) let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted an account repair CFU"); - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should not have posted an escrow repair CFU"); + XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted an account repair CFU") + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should not have posted an escrow repair CFU") } func testHealthCheckBeforeStateMachineStarts() throws { @@ -328,19 +334,19 @@ class OctagonHealthCheckTests: OctagonTestsBase { let containerName = OTCKContainerName let cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: contextName) - cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in XCTAssertNotNil(error, "Should be an error calling 'healthCheck'") XCTAssertEqual(error!._domain, CKKSResultErrorDomain, "Error domain should be CKKSResultErrorDomain") - XCTAssertEqual(error!._code , CKKSResultTimedOut, "Error result should be CKKSResultTimedOut") + XCTAssertEqual(error!._code, CKKSResultTimedOut, "Error result should be CKKSResultTimedOut") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) self.startCKAccountStatusMock() - cuttlefishContext.stateMachine.setWatcherTimeout(60*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(60 * NSEC_PER_SEC) cuttlefishContext.startOctagonStateMachine() @@ -353,7 +359,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { otcliqueContext.altDSID = self.mockAuthKit.altDSID! otcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: otcliqueContext) + clique = try OTClique.newFriends(withContextData: otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -405,7 +411,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -454,10 +460,9 @@ class OctagonHealthCheckTests: OctagonTestsBase { } self.wait(for: [healthCheckCallback], timeout: 10) - let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -505,7 +510,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) let cuttlefishContext = self.manager.context(forContainerName: containerName, contextID: contextName) - cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in @@ -530,7 +535,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -583,7 +588,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -709,7 +714,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -745,9 +750,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { } self.wait(for: [fetchViableExpectation], timeout: 10) - let userInfo: Dictionary = ["NSLocalizedDescription" : "Reachability validation failed, graph is not reachable"] - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.resultGraphNotFullyReachable.rawValue, userInfo: userInfo) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .resultGraphNotFullyReachable) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) let joinListenerExpectation = self.expectation(description: "joinWithVoucherExpectation callback occurs") @@ -773,13 +776,15 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.wait(for: [healthExpectation], timeout: 100) self.fakeCuttlefishServer.joinListener = nil self.fakeCuttlefishServer.healthListener = nil + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) } func testCuttlefishDontPostEscrowCFUDueToPendingPrecord() throws { self.fakeCuttlefishServer.returnRepairEscrowResponse = true OTMockSecEscrowRequest.self.populateStatuses = true let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should NOT have posted an escrow CFU"); + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should NOT have posted an escrow CFU") } func testHealthCheckWhileLocked() throws { @@ -793,7 +798,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { diff --git a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift index 397a9354..0bf2b04c 100644 --- a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift +++ b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift @@ -5,7 +5,6 @@ super.setUp() } - func testSetRecoveryKey() throws { self.startCKAccountStatusMock() self.manager.setSOSEnabledForPlatformFlag(false) @@ -17,7 +16,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -51,7 +50,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -157,7 +156,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -210,7 +209,7 @@ // The first peer will upload TLKs for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() let stableInfoCheckDumpCallback = self.expectation(description: "stableInfoCheckDumpCallback callback occurs") @@ -272,7 +271,7 @@ self.verifyDatabaseMocks() - self.sendContainerChangeWaitForFetchForState(context: thirdPeerContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: thirdPeerContext) let thirdPeerStableInfoCheckDumpCallback = self.expectation(description: "thirdPeerStableInfoCheckDumpCallback callback occurs") self.tphClient.dump(withContainer: OTCKContainerName, context: thirdPeerContextID) { dump, _ in @@ -325,7 +324,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit2.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -354,14 +353,14 @@ } self.wait(for: [createRecoveryExpectation], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: establishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: establishContext) let recoveryContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) recoveryContext.startOctagonStateMachine() self.assertEnters(context: recoveryContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: recoveryContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: recoveryContext) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs") recoveryContext.join(withRecoveryKey: recoveryKey) { error in @@ -441,7 +440,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit2.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -464,7 +463,7 @@ } self.wait(for: [createRecoveryExpectation], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: establishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: establishContext) self.silentFetchesAllowed = false self.expectCKFetchAndRun(beforeFinished: { @@ -477,7 +476,7 @@ recoveryContext.startOctagonStateMachine() self.assertEnters(context: recoveryContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: recoveryContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: recoveryContext) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs") recoveryContext.join(withRecoveryKey: recoveryKey) { error in @@ -502,7 +501,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -537,7 +536,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -580,7 +579,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -652,8 +651,8 @@ } self.wait(for: [setRecoveryKeyExpectationAgain], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) var initiatorRecoverySigningKey: Data? var initiatorRecoveryEncryptionKey: Data? @@ -736,7 +735,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -775,7 +774,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -858,7 +857,7 @@ self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") - TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey:recoveryKey!) { error in + TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in XCTAssertNil(error, "error should be nil") joinWithRecoveryKeyExpectation.fulfill() } @@ -897,7 +896,7 @@ self.manager.setSOSEnabledForPlatformFlag(false) self.startCKAccountStatusMock() - + self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) @@ -905,7 +904,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -948,7 +947,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -994,7 +993,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1023,7 +1022,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1062,7 +1061,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1098,7 +1097,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1144,7 +1143,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1155,5 +1154,77 @@ } self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) } + + func testMalformedRecoveryKey() throws { + OctagonRecoveryKeySetIsEnabled(true) + self.manager.setSOSEnabledForPlatformFlag(false) + self.startCKAccountStatusMock() + + let establishContextID = "establish-context-id" + let establishContext = self.createEstablishContext(contextID: establishContextID) + + establishContext.startOctagonStateMachine() + self.assertEnters(context: establishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = establishContextID + recoverykeyotcliqueContext.dsid = "1234" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + + self.assertEnters(context: establishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: establishContext) + + // Fake that this peer also created some TLKShares for itself + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + try self.putSelfTLKShareInCloudKit(context: establishContext, zoneID: self.manateeZoneID) + + self.assertSelfTLKSharesInCloudKit(context: establishContext) + + let recoveryKey = "malformedRecoveryKey" + XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") + self.manager.setSOSEnabledForPlatformFlag(true) + + + let createKeyExpectation = self.expectation(description: "createKeyExpectation returns") + self.manager.createRecoveryKey(OTCKContainerName, contextID: self.otcliqueContext.context ?? "defaultContext", recoveryKey: recoveryKey) { error in + XCTAssertNotNil(error, "error should NOT be nil") + XCTAssertEqual((error! as NSError).code, 41, "error code should be 41/malformed recovery key") + XCTAssertEqual((error! as NSError).domain, "com.apple.security.octagon", "error code domain should be com.apple.security.octagon") + createKeyExpectation.fulfill() + } + self.wait(for: [createKeyExpectation], timeout: 10) + + let newCliqueContext = OTConfigurationContext() + newCliqueContext.context = OTDefaultContext + newCliqueContext.dsid = self.otcliqueContext.dsid + newCliqueContext.altDSID = self.mockAuthKit.altDSID! + newCliqueContext.otControl = self.otControl + + let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + newGuyContext.startOctagonStateMachine() + + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) + + self.manager.setSOSEnabledForPlatformFlag(true) + let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") + + OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in + XCTAssertNotNil(error, "error should NOT be nil") + XCTAssertEqual((error! as NSError).code, 41, "error code should be 41/malformed recovery key") + XCTAssertEqual((error! as NSError).domain, "com.apple.security.octagon", "error code domain should be com.apple.security.octagon") + joinWithRecoveryKeyExpectation.fulfill() + } + self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+Reset.swift b/keychain/ot/tests/octagon/OctagonTests+Reset.swift index cb8120ae..562d6270 100644 --- a/keychain/ot/tests/octagon/OctagonTests+Reset.swift +++ b/keychain/ot/tests/octagon/OctagonTests+Reset.swift @@ -9,7 +9,7 @@ class OctagonResetTests: OctagonTestsBase { _ = try self.cuttlefishContext.accountAvailable("13453464") - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -23,7 +23,7 @@ class OctagonResetTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -39,7 +39,7 @@ class OctagonResetTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -66,7 +66,8 @@ class OctagonResetTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -96,7 +97,7 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -123,7 +124,8 @@ class OctagonResetTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -136,14 +138,14 @@ class OctagonResetTests: OctagonTestsBase { // CKKS should have all gone into waitfortrust during that time for condition in waitfortrusts { - XCTAssertEqual(0, condition.wait(10*NSEC_PER_MSEC), "CKKS should have entered waitfortrust") + XCTAssertEqual(0, condition.wait(10 * NSEC_PER_MSEC), "CKKS should have entered waitfortrust") } } func testOctagonResetAlsoResetsCKKSViewsMissingTLKs() { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -155,14 +157,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys") @@ -173,7 +175,7 @@ class OctagonResetTests: OctagonTestsBase { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) - (self.zones![self.manateeZoneID]! as! FakeCKZone).currentDatabase.allValues.forEach { record in + (self.zones![self.manateeZoneID!]! as! FakeCKZone).currentDatabase.allValues.forEach { record in let r = record as! CKRecord if(r.recordType == SecCKRecordDeviceStateType) { r.creationDate = NSDate.distantPast @@ -181,7 +183,7 @@ class OctagonResetTests: OctagonTestsBase { } } - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -192,14 +194,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys") @@ -210,7 +212,7 @@ class OctagonResetTests: OctagonTestsBase { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -221,14 +223,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys") @@ -237,9 +239,9 @@ class OctagonResetTests: OctagonTestsBase { func testOctagonResetWithTLKsDoesNotResetCKKS() { // CKKS has the keys keys self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - self.saveTLKMaterial(toKeychain:self.manateeZoneID) + self.saveTLKMaterial(toKeychain: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -248,7 +250,7 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } @@ -256,7 +258,7 @@ class OctagonResetTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys") @@ -278,15 +280,10 @@ class OctagonResetTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: CuttlefishErrorCode.establishFailed.rawValue, - userInfo: nil)]) - + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .establishFailed) } - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in resetExpectation.fulfill() XCTAssertNotNil(resetError, "should error resetting and establishing") } @@ -296,6 +293,294 @@ class OctagonResetTests: OctagonTestsBase { self.verifyDatabaseMocks() } + func testResetReasonUnknown() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.unknown.rawValue, "reset reason should be unknown") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + self.cuttlefishContext.rpcResetAndEstablish(.unknown) { resetError in + establishAndResetExpectation.fulfill() + XCTAssertNil(resetError, "should not error resetting and establishing") + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonUserInitiatedReset() throws { + // Make sure if establish fail we end up in untrusted instead of error + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.userInitiatedReset.rawValue, "reset reason should be user initiated reset") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = OTDefaultContext + recoverykeyotcliqueContext.dsid = "13453464" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .userInitiatedReset) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + establishAndResetExpectation.fulfill() + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonRecoveryKey() throws { + // Make sure if establish fail we end up in untrusted instead of error + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.recoveryKey.rawValue, "reset reason should be recovery key") + return nil + } + + let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String + XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") + + let newCliqueContext = OTConfigurationContext() + newCliqueContext.context = OTDefaultContext + newCliqueContext.dsid = self.otcliqueContext.dsid + newCliqueContext.altDSID = self.mockAuthKit.altDSID! + newCliqueContext.otControl = self.otControl + + let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") + TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in + XCTAssertNil(error, "error should be nil") + joinWithRecoveryKeyExpectation.fulfill() + } + self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) + self.wait(for: [resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonNoValidBottle() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let initiatorContext = self.manager.context(forContainerName: OTCKContainerName, + contextID: "restoreContext", + sosAdapter: OTSOSMissingAdapter(), + authKitAdapter: self.mockAuthKit2, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter()) + + initiatorContext.startOctagonStateMachine() + let newOTCliqueContext = OTConfigurationContext() + newOTCliqueContext.context = OTDefaultContext + newOTCliqueContext.dsid = self.otcliqueContext.dsid + newOTCliqueContext.altDSID = self.otcliqueContext.altDSID + newOTCliqueContext.otControl = self.otcliqueContext.otControl + newOTCliqueContext.sbd = OTMockSecureBackup(bottleID: nil, entropy: nil) + + let resetExpectation = self.expectation(description: "resetExpectation callback occurs") + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.noBottleDuringEscrowRecovery.rawValue, "reset reason should be no bottle during escrow recovery") + return nil + } + + let newClique: OTClique + do { + newClique = try OTClique.performEscrowRecovery(withContextData: newOTCliqueContext, escrowArguments: [:]) + XCTAssertNotNil(newClique, "newClique should not be nil") + } catch { + XCTFail("Shouldn't have errored recovering: \(error)") + throw error + } + self.wait(for: [resetExpectation], timeout: 10) + + } + + func testResetReasonHealthCheck() throws { + + let containerName = OTCKContainerName + let contextName = OTDefaultContext + + self.cuttlefishContext.startOctagonStateMachine() + self.startCKAccountStatusMock() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let clique: OTClique + do { + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + do { + let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) + XCTAssertEqual(2, accountState.trustState.rawValue, "saved account should be trusted") + } catch { + XCTFail("error loading account state: \(error)") + } + + // Reset any CFUs we've done so far + self.otFollowUpController.postedFollowUp = false + + let resetExpectation = self.expectation(description: "resetExpectation callback occurs") + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.healthCheck.rawValue, "reset reason should be health check") + return nil + } + self.fakeCuttlefishServer.returnResetOctagonResponse = true + self.aksLockState = false + self.lockStateTracker.recheck() + + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") + self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in + XCTAssertNil(error, "error should be nil") + healthCheckCallback.fulfill() + } + self.wait(for: [healthCheckCallback, resetExpectation], timeout: 10) + + assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + let dumpCallback = self.expectation(description: "dumpCallback callback occurs") + self.tphClient.dump(withContainer: containerName, context: contextName) { + dump, _ in + XCTAssertNotNil(dump, "dump should not be nil") + let egoSelf = dump!["self"] as? Dictionary + XCTAssertNotNil(egoSelf, "egoSelf should not be nil") + dumpCallback.fulfill() + } + self.wait(for: [dumpCallback], timeout: 10) + + self.verifyDatabaseMocks() + self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testResetReasonLegacyJoinCircle() throws { + self.cuttlefishContext.startOctagonStateMachine() + self.startCKAccountStatusMock() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = OTDefaultContext + recoverykeyotcliqueContext.dsid = "13453464" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + establishAndResetExpectation.fulfill() + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + self.wait(for: [establishAndResetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + let resetExpectation = self.expectation(description: "resetExpectation callback occurs") + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.legacyJoinCircle.rawValue, "reset reason should be legacy join circle") + return nil + } + + do { + _ = try clique.requestToJoinCircle() + } catch { + XCTFail("Shouldn't have errored requesting to join circle: \(error)") + throw error + } + self.wait(for: [resetExpectation], timeout: 10) + } + + func testResetReasonTestGenerated() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.testGenerated.rawValue, "reset reason should be test generated") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in + establishAndResetExpectation.fulfill() + XCTAssertNil(resetError, "should not error resetting and establishing") + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests+SOS.swift b/keychain/ot/tests/octagon/OctagonTests+SOS.swift index c470baae..67a55f23 100644 --- a/keychain/ot/tests/octagon/OctagonTests+SOS.swift +++ b/keychain/ot/tests/octagon/OctagonTests+SOS.swift @@ -179,6 +179,118 @@ class OctagonSOSTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) } + func testSOSPerformOctagonKeyConsistencyOnCircleChange() throws { + self.startCKAccountStatusMock() + + // Octagon establishes its identity before SOS joins + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + + self.assertResetAndBecomeTrustedInDefaultContext() + + let peerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID() + XCTAssertNotNil(peerID, "Should have a peer ID") + + // Now, SOS arrives + let updateExpectation = self.expectation(description: "Octagon should inform SOS of its keys") + self.mockSOSAdapter.updateOctagonKeySetListener = { _ in + // Don't currently check the key set at all here + updateExpectation.fulfill() + } + + // CKKS will upload itself new shares (for the newly trusted SOS self peer) + self.assertAllCKKSViewsUpload(tlkShares: 1) + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) + // Note: this should probably be sendSelfPeerChangedUpdate, but we don't have great fidelity around which peer + // actually changed. So, just use this channel for now + self.mockSOSAdapter.sendTrustedPeerSetChangedUpdate() + + self.wait(for: [updateExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + } + + func testDisablingSOSFeatureFlag() throws { + self.startCKAccountStatusMock() + OctagonSetSOSFeatureEnabled(false) + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = "recoveryContext" + recoverykeyotcliqueContext.dsid = "1234" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + + var clique: OTClique + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + do{ + try clique.joinAfterRestore() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.isLastFriend() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.safariPasswordSyncingEnabled() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.waitForInitialSync() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + clique.viewSet(Set(), disabledViews: Set()) + + do{ + try clique.setUserCredentialsAndDSID("", password: Data()) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.tryUserCredentialsAndDSID("", password: Data()) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.peersHaveViewsEnabled([""]) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.requestToJoinCircle() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + clique.accountUserKeyAvailable() + + do{ + _ = try clique.copyViewUnawarePeerInfo() + }catch{ + XCTAssertNotNil(error, "error should not be nil") + } + do { + _ = try clique.copyPeerPeerInfo() + }catch{ + XCTAssertNotNil(error, "error should not be nil") + } + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift b/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift index 007a3a95..f1a10e25 100644 --- a/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift +++ b/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift @@ -96,9 +96,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) self.startCKAccountStatusMock() - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.cuttlefishContext.startOctagonStateMachine() @@ -160,7 +160,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain:CKErrorDomain, code:CKError.networkUnavailable.rawValue, userInfo:[CKErrorRetryAfterKey: 2]) + return CKPrettyError(domain: CKErrorDomain, code: CKError.networkUnavailable.rawValue, userInfo: [CKErrorRetryAfterKey: 2]) } self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -194,12 +194,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [CKErrorRetryAfterKey: 2, - NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: CuttlefishErrorCode.resultGraphNotFullyReachable.rawValue, - userInfo: nil)]) + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .resultGraphNotFullyReachable, retryAfter: 2) } self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -231,7 +226,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: peer2, state: OctagonStateReady, within: 100 * NSEC_PER_SEC) - // Now we arrive, and attempt to SOS join let sosUpgradeStateCondition = self.cuttlefishContext.stateMachine.stateConditions[OctagonStateAttemptSOSUpgrade] as! CKKSCondition self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -350,8 +344,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { // Right now, peer2 has just upgraded after peer1. It should trust peer1, and both should implictly trust each other XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") - XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -439,7 +431,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } - func testSOSJoinUponNotificationOfPreapprovalRetry() throws { // Peer 1 becomes SOS+Octagon self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) @@ -508,7 +499,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { } updateTrustExpectation1.fulfill() - return CKPrettyError(domain:CKErrorDomain, code:CKError.networkUnavailable.rawValue, userInfo:[CKErrorRetryAfterKey: 2]) + return CKPrettyError(domain: CKErrorDomain, code: CKError.networkUnavailable.rawValue, userInfo: [CKErrorRetryAfterKey: 2]) } self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer) @@ -631,7 +622,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") + "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -752,7 +743,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) let upgradeExpectation = self.expectation(description: "waitForOctagonUpgrade") - self.manager.wait(forOctagonUpgrade:OTCKContainerName, context: self.otcliqueContext.context ?? "defaultContext") { error in + self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: self.otcliqueContext.context ?? "defaultContext") { error in XCTAssertNil(error, "operation should not fail") upgradeExpectation.fulfill() } @@ -774,7 +765,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -860,14 +851,18 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") + "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), "peer 1 should not trust peer 2 (as it hasn't responded to peer2's upgradeJoin yet)") // Now, tell peer1 about the change + // The first peer will upload TLKs for the new peer + self.assertAllCKKSViewsUpload(tlkShares: 1) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() // Peer1 should trust peer2 now, since it upgraded it from implicitly explicitly trusted XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -878,7 +873,15 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { var bottleID: String = "" //now try restoring bottles - let newGuyUsingBottle = self.manager.context(forContainerName: OTCKContainerName, contextID: "NewGuyUsingBottle") + let mockNoSOS = CKKSMockSOSPresentAdapter(selfPeer: self.createSOSPeer(peerID: "peer3ID"), trustedPeers: Set(), essential: false) + mockNoSOS.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + let newGuyUsingBottle = self.manager.context(forContainerName: OTCKContainerName, + contextID: "NewGuyUsingBottle", + sosAdapter: mockNoSOS, + authKitAdapter: self.mockAuthKit3, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone-3", serialNumber: "456", osVersion: "iOS (fake version)")) let peer2AltDSID = try peer2.accountMetadataStore.loadOrCreateAccountMetadata().altDSID newGuyUsingBottle.startOctagonStateMachine() @@ -896,14 +899,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertNotNil(peer2AltDSID, "should have a dsid for peer2") - self.sendContainerChange(context: peer2) - - // The first peer will upload TLKs for the new peer - self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) - self.verifyDatabaseMocks() - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") newGuyUsingBottle.join(withBottle: bottleID, entropy: entropy, bottleSalt: peer2AltDSID!) { error in XCTAssertNil(error, "error should be nil") @@ -912,6 +907,14 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [joinWithBottleExpectation], timeout: 10) self.assertEnters(context: newGuyUsingBottle, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + let newGuyPeerID = try newGuyUsingBottle.accountMetadataStore.getEgoPeerID() + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: newGuyPeerID)), + "newPeer should trust itself after bottle restore") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: peer1ID)), + "newPeer should trust peer 1 after bottle restore") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: peer2ID)), + "newPeer should trust peer 2 after bottle restore") + let gonnaFailContext = self.manager.context(forContainerName: OTCKContainerName, contextID: "gonnaFailContext") gonnaFailContext.startOctagonStateMachine() let joinWithBottleFailExpectation = self.expectation(description: "joinWithBottleFail callback occurs") @@ -922,7 +925,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [joinWithBottleFailExpectation], timeout: 10) self.assertEnters(context: gonnaFailContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext, isLocked: false) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) } func testSOSPeerUpdatePreapprovesNewPeer() throws { @@ -1105,7 +1110,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { } let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish") - self.cuttlefishContext.rpcResetAndEstablish() { error in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { error in XCTAssertNil(error, "Should be no error performing a reset and establish") resetAndEstablishExpectation.fulfill() } @@ -1166,7 +1171,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [dumpExpectation], timeout: 10) let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish") - self.cuttlefishContext.rpcResetAndEstablish() { error in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { error in XCTAssertNil(error, "Should be no error performing a reset and establish") resetAndEstablishExpectation.fulfill() } @@ -1211,9 +1216,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(OctagonPerformSOSUpgrade(), "SOS upgrade should be on") - self.mockAuthKit.machineIDFetchErrors.append(NSError(domain:AKAppleIDAuthenticationErrorDomain, - code:AKAppleIDAuthenticationError.authenticationErrorCannotFindServer.rawValue, - userInfo:nil)) + self.mockAuthKit.machineIDFetchErrors.append(NSError(domain: AKAppleIDAuthenticationErrorDomain, + code: AKAppleIDAuthenticationError.authenticationErrorCannotFindServer.rawValue, + userInfo: nil)) // Octagon should decide it is quite sad. self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -1236,8 +1241,8 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { OctagonSetPlatformSupportsSOS(true) - var clique : OTClique? - XCTAssertNoThrow(clique = try OTClique.init(contextData: self.otcliqueContext)) + var clique: OTClique? + XCTAssertNoThrow(clique = try OTClique(contextData: self.otcliqueContext)) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNoThrow(try clique!.waitForOctagonUpgrade(), "Upgrading should pass") @@ -1255,14 +1260,123 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { OctagonSetPlatformSupportsSOS(true) - var clique : OTClique? - XCTAssertNoThrow(clique = try OTClique.init(contextData: self.otcliqueContext)) + var clique: OTClique? + XCTAssertNoThrow(clique = try OTClique(contextData: self.otcliqueContext)) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertThrowsError(try clique!.waitForOctagonUpgrade(), "Upgrading should fail") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) } + + func testSOSDoNotJoinByPreapprovalMultipleTimes() throws { + self.startCKAccountStatusMock() + + // First, peer 1 establishes, preapproving both peer2 and peer3. Then, peer2 and peer3 join and harmonize. + // Peer1 is never told about the follow-on joins. + // Then, the test can begin. + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) + + let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID") + let peer3SOSMockPeer = self.createSOSPeer(peerID: "peer3ID") + + self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer) + self.mockSOSAdapter.trustedPeers.add(peer3SOSMockPeer) + + // Due to how everything is shaking out, SOS TLKShares will be uploaded in a second transaction after Octagon uploads its TLKShares + // This isn't great: Octagon: upload SOS TLKShares alongside initial key hierarchy + self.assertAllCKKSViewsUpload(tlkShares: 3) + + self.cuttlefishContext.startOctagonStateMachine() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + let peer1ID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID() + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + // peer2 + let peer2mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer2SOSMockPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) + let peer2 = self.makeInitiatorContext(contextID: "peer2", authKitAdapter: self.mockAuthKit2, sosAdapter: peer2mockSOS) + + peer2.startOctagonStateMachine() + self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer2) + let peer2ID = try peer2.accountMetadataStore.getEgoPeerID() + + // peer3 + let peer3mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer3SOSMockPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) + let peer3 = self.makeInitiatorContext(contextID: "peer3", authKitAdapter: self.mockAuthKit3, sosAdapter: peer3mockSOS) + + peer3.startOctagonStateMachine() + self.assertEnters(context: peer3, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer3) + let peer3ID = try peer3.accountMetadataStore.getEgoPeerID() + + // Now, tell peer2 about peer3's join + self.sendContainerChangeWaitForFetch(context: peer2) + + // Peer 1 should preapprove both peers. + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), + "peer 1 should trust peer 2 by preapproval") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), + "peer 1 should trust peer 3 by preapproval") + + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), + "peer 2 should trust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer3ID)), + "peer 2 should trust peer 3") + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .trusts, target: peer1ID)), + "peer 3 should trust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .trusts, target: peer2ID)), + "peer 3 should trust peer 2") + + // Now, the test can begin. Peer2 decides it rules the world. + let removalExpectation = self.expectation(description: "removal occurs") + peer2.rpcRemoveFriends(inClique: [peer1ID, peer3ID]) { removeError in + XCTAssertNil(removeError, "Should be no error removing peer1 and peer3") + removalExpectation.fulfill() + } + self.wait(for: [removalExpectation], timeout: 5) + self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer2) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .excludes, target: peer1ID)), + "peer 2 should distrust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .excludes, target: peer3ID)), + "peer 2 should distrust peer 3") + + // And we notify peer3 about this, and it should become sad + self.sendContainerChangeWaitForFetchForStates(context: peer3, states: [OctagonStateReadyUpdated, OctagonStateUntrusted]) + self.assertEnters(context: peer3, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: peer3) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .excludes, target: peer3ID)), + "peer 3 should distrust peer 3") + + // And if peer3 decides to reupgrade, but it shouldn't: there's no potentially-trusted peer that preapproves it + let upgradeExpectation = self.expectation(description: "sosUpgrade call returns") + peer3.attemptSOSUpgrade() { error in + XCTAssertNotNil(error, "should be an error performing an SOS upgrade (the second time)") + upgradeExpectation.fulfill() + } + self.wait(for: [upgradeExpectation], timeout: 5) + + // And peer3 remains untrusted + self.assertEnters(context: peer3, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: peer3) + + // And "wait for upgrade" does something reasonable too + let upgradeWaitExpectation = self.expectation(description: "sosWaitForUpgrade call returns") + peer3.waitForOctagonUpgrade() { error in + XCTAssertNotNil(error, "should be an error waiting for an SOS upgrade (the second time)") + upgradeWaitExpectation.fulfill() + } + self.wait(for: [upgradeWaitExpectation], timeout: 5) + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h index 6c83e44d..086a45bc 100644 --- a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h +++ b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h @@ -8,7 +8,9 @@ #import #import -#import +#import "KeychainCircle/KCJoiningSession.h" +#import "KeychainCircle/KCJoiningRequestSession+Internal.h" +#import "KeychainCircle/KCJoiningAcceptSession+Internal.h" #import #import @@ -17,8 +19,8 @@ #import "utilities/SecCFError.h" -#import "securityd/SecItemServer.h" -#import "securityd/spi.h" +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/spi.h" #import #import "keychain/ckks/CKKS.h" @@ -35,6 +37,8 @@ #import "keychain/ot/OTClique.h" #import "keychain/ot/OTControl.h" #import "keychain/ot/OTControlProtocol.h" +#import "keychain/ot/OTManager.h" +#import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTSOSAdapter.h" #import "keychain/ot/OTConstants.h" @@ -45,7 +49,7 @@ #import "keychain/ot/OTDeviceInformationAdapter.h" -#import "keychain/ot/tests/OTTestsBase.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ckks/CKKSKeychainBackedKey.h" diff --git a/keychain/ot/tests/octagon/OctagonTests.swift b/keychain/ot/tests/octagon/OctagonTests.swift index 2a0b2611..0fa46d15 100644 --- a/keychain/ot/tests/octagon/OctagonTests.swift +++ b/keychain/ot/tests/octagon/OctagonTests.swift @@ -18,10 +18,10 @@ class FakeCuttlefishInvocableCreator: ContainerNameToCuttlefishInvocable { } class OTMockDeviceInfoAdapter: OTDeviceInformationAdapter { - let mockModelID: String - let mockDeviceName: String? - let mockOsVersion: String - let mockSerialNumber: String + var mockModelID: String + var mockDeviceName: String? + var mockOsVersion: String + var mockSerialNumber: String init(modelID: String, deviceName: String?, serialNumber: String, osVersion: String) { self.mockModelID = modelID @@ -45,35 +45,11 @@ class OTMockDeviceInfoAdapter: OTDeviceInformationAdapter { func serialNumber() -> String { return self.mockSerialNumber } -} - -class OTMockDeviceInfoAdapterFakeSerial: OTDeviceInformationAdapter -{ - let mockSerialNumber: String - let actualAdapter: OTDeviceInformationActualAdapter - - init() { - mockSerialNumber = NSUUID().uuidString - actualAdapter = OTDeviceInformationActualAdapter() - } - func modelID() -> String { - return self.actualAdapter.modelID() - } - - func deviceName() -> String? { - return self.actualAdapter.deviceName() - } - - func osVersion() -> String { - return self.actualAdapter.osVersion() - } - func serialNumber() -> String { - return self.mockSerialNumber + func register(forDeviceNameUpdates listener: OTDeviceInformationNameUpdateListener) { } } - class OTMockAuthKitAdapter: OTAuthKitAdapter { // A nil altDSID means 'no authkit account' var altDSID: String? @@ -219,15 +195,14 @@ class OTMockSecEscrowRequest: NSObject, SecEscrowRequestable { NotificationCenter.default.post(name: OTMockEscrowRequestNotification, object: nil) } - func fetchStatuses() throws -> [AnyHashable : Any] { + func fetchStatuses() throws -> [AnyHashable: Any] { return statuses } func pendingEscrowUpload(_ error: NSErrorPointer) -> Bool { if statuses["uuid"] == SecEscrowRequestPendingCertificate { return true - } - else { + } else { return false } } @@ -256,6 +231,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { var mockAuthKit2: OTMockAuthKitAdapter! var mockAuthKit3: OTMockAuthKitAdapter! + var mockDeviceInfo: OTMockDeviceInfoAdapter! + var otControl: OTControl! var otXPCProxy: ProxyXPCConnection! var otControlEntitlementBearer: FakeOTControlEntitlementBearer! @@ -275,10 +252,6 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { securityd_init_local_spi() } - func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapterFakeSerial() - } - override func setUp() { // Set the global bool to TRUE OctagonSetIsEnabled(true) @@ -291,6 +264,12 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { // Each test is responsible for initialization, to allow for pre-test setup OctagonSetShouldPerformInitialization(false) + let actualDeviceAdapter = OTDeviceInformationActualAdapter() + self.mockDeviceInfo = OTMockDeviceInfoAdapter(modelID: actualDeviceAdapter.modelID(), + deviceName: actualDeviceAdapter.deviceName(), + serialNumber: NSUUID().uuidString, + osVersion: actualDeviceAdapter.osVersion()) + super.setUp() // Octagon must initialize the views @@ -308,7 +287,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { #endif self.zones!.removeAllObjects() - self.zones![self.manateeZoneID] = FakeCKZone(zone: self.manateeZoneID) + self.zones![self.manateeZoneID!] = FakeCKZone(zone: self.manateeZoneID!) // Asserting a type on self.zones seems to duplicate the dictionary, but not deep-copy the contents // We'll use them as NSMutableDictionaries, I guess @@ -333,17 +312,11 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.mockSOSAdapter.essential = false let tphInterface = TrustedPeersHelperSetupProtocol(NSXPCInterface(with: TrustedPeersHelperProtocol.self)) - self.tphXPCProxy = ProxyXPCConnection(self.tphClient, interface: tphInterface) - - self.manager = OTManager(context: nil, - localStore: nil, - enroll: nil, - restore: nil, - cfu: nil, - cfuScheduler: nil, - sosAdapter: self.mockSOSAdapter, + self.tphXPCProxy = ProxyXPCConnection(self.tphClient!, interface: tphInterface) + + self.manager = OTManager(sosAdapter: self.mockSOSAdapter, authKitAdapter: self.mockAuthKit, - deviceInformationAdapter: deviceInformationAdapter(), + deviceInformationAdapter: self.mockDeviceInfo, apsConnectionClass: FakeAPSConnection.self, escrowRequestClass: OTMockSecEscrowRequest.self, loggerClass: OTMockLogger.self, @@ -359,7 +332,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.otControlEntitlementBearer = FakeOTControlEntitlementBearer() self.otControlEntitlementChecker = OctagonXPCEntitlementChecker.create(with: self.manager, entitlementBearer: self.otControlEntitlementBearer) - self.otXPCProxy = ProxyXPCConnection(self.otControlEntitlementChecker, interface: OTSetupControlProtocol(NSXPCInterface(with: OTControlProtocol.self))) + self.otXPCProxy = ProxyXPCConnection(self.otControlEntitlementChecker!, interface: OTSetupControlProtocol(NSXPCInterface(with: OTControlProtocol.self))) self.otControl = OTControl(connection: self.otXPCProxy.connection(), sync: true) self.otControlCLI = OTControlCLI(otControl: self.otControl) @@ -373,7 +346,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { override func tearDown() { let statusExpectation = self.expectation(description: "status callback occurs") - self.cuttlefishContext.rpcStatus() { _, _ in + self.cuttlefishContext.rpcStatus { _, _ in statusExpectation.fulfill() } self.wait(for: [statusExpectation], timeout: 10) @@ -388,7 +361,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { // Stop all of CKKS self.injectedManager!.haltAll() - XCTAssertTrue(self.manager.allContextsPause(10*NSEC_PER_SEC), "All cuttlefish contexts should pause") + XCTAssertTrue(self.manager.allContextsPause(10 * NSEC_PER_SEC), "All cuttlefish contexts should pause") super.tearDown() } @@ -450,8 +423,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, _ in XCTAssertEqual(egoStatus, .in, "Self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a peerID") XCTAssertEqual(isLocked, isLocked, "should be \(isLocked)") @@ -466,9 +439,9 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let cachedStatusexpectation = self.expectation(description: "(cached) trust status returns") let configuration = OTOperationConfiguration() configuration.useCachedAccountStatus = true - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ in XCTAssertEqual(egoStatus, .in, "Cached self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a (cached) peerID") cachedStatusexpectation.fulfill() @@ -482,12 +455,12 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { cliqueConfiguration.otControl = self.otControl let otclique = try! OTClique(contextData: cliqueConfiguration) - let status = otclique.cachedCliqueStatus(true, error: nil) + let status = otclique.fetchStatus(nil) XCTAssertEqual(status, .in, "OTClique API should return (trusted)") configuration.useCachedAccountStatus = false let statusexpectation = self.expectation(description: "(cached) trust status returns") - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ in XCTAssertEqual(egoStatus, .in, "Self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a peerID") statusexpectation.fulfill() @@ -499,8 +472,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { XCTAssertEqual(context.currentMemoizedTrustState(), .UNTRUSTED, "Trust state (for \(context)) should be untrusted") let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC - self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + context.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in // TODO: separate 'untrusted' and 'no trusted peers for account yet' XCTAssertTrue([.notIn, .absent].contains(egoStatus), "Self peer (for \(context)) should be distrusted or absent") statusexpectation.fulfill() @@ -508,13 +481,17 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.wait(for: [statusexpectation], timeout: 10) } + func assertAccountAvailable(context: OTCuttlefishContext) { + XCTAssertEqual(context.currentMemoizedAccountState(), .ACCOUNT_AVAILABLE, "Account state (for \(context)) should be 'available''") + } + func assertNoAccount(context: OTCuttlefishContext) { XCTAssertEqual(context.currentMemoizedAccountState(), .NO_ACCOUNT, "Account state (for \(context)) should be no account") } func assertTrusts(context: OTCuttlefishContext, includedPeerIDCount: Int, excludedPeerIDCount: Int) { let dumpCallback = self.expectation(description: "dump callback occurs") - self.tphClient.dumpEgoPeer(withContainer: context.containerName, context: context.contextID) { peerID, permanentInfo, stableInfo, dynamicInfo, error in + self.tphClient.dumpEgoPeer(withContainer: context.containerName, context: context.contextID) { _, _, _, dynamicInfo, error in XCTAssertNil(error, "should be no error") XCTAssertNotNil(dynamicInfo, "Should be a dynamic info") XCTAssertEqual(dynamicInfo!.includedPeerIDs.count, includedPeerIDCount, "should be \(includedPeerIDCount) included peer ids") @@ -563,7 +540,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { func resetAllCKKSViews() { let resetExpectation = self.expectation(description: "rpcResetCloudKit callback occurs") - self.injectedManager!.rpcResetCloudKit(nil, reason:"octagon=unit-test") { error in + self.injectedManager!.rpcResetCloudKit(nil, reason: "octagon=unit-test") { error in XCTAssertNil(error, "Error should be nil?") resetExpectation.fulfill() } @@ -638,7 +615,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { kSecAttrDescription: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitOne, ] @@ -688,7 +665,6 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { ]) } - func sendContainerChangeWaitForFetch(context: OTCuttlefishContext) { self.sendContainerChangeWaitForFetchForStates(context: context, states: [OctagonStateReadyUpdated, OctagonStateReady]) } @@ -697,12 +673,14 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.sendContainerChangeWaitForFetchForStates(context: context, states: [OctagonStateUntrustedUpdated, OctagonStateUntrusted]) } - func sendContainerChangeWaitForFetchForState(context: OTCuttlefishContext, state: String) { - return self.sendContainerChangeWaitForFetchForStates(context: context, states: [state]) - } - + // Please ensure that the first state in this list is not the state that the context is currently in func sendContainerChangeWaitForFetchForStates(context: OTCuttlefishContext, states: [String]) { + // Pull the first state out before sending the notification + let firstState = states.first! + let firstCondition = (context.stateMachine.stateConditions[firstState] as! CKKSCondition) + let updateTrustExpectation = self.expectation(description: "fetchChanges") + self.fakeCuttlefishServer.fetchChangesListener = { request in self.fakeCuttlefishServer.fetchChangesListener = nil updateTrustExpectation.fulfill() @@ -710,7 +688,10 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { } context.notifyContainerChange(nil) self.wait(for: [updateTrustExpectation], timeout: 10) - for state in states { + + // Wait for the previously acquired first state, then wait for each in turn + XCTAssertEqual(0, firstCondition.wait(10 * NSEC_PER_SEC), "State machine should enter '\(String(describing: firstState))'") + for state in states.dropFirst() { self.assertEnters(context: context, state: state, within: 10 * NSEC_PER_SEC) } } @@ -729,7 +710,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { func makeInitiatorDeviceInfoAdapter() -> OTMockDeviceInfoAdapter { // Note that the type of your initiator changes based on the platform you're currently on - return OTMockDeviceInfoAdapter(modelID: self.deviceInformationAdapter().modelID(), + return OTMockDeviceInfoAdapter(modelID: self.mockDeviceInfo.modelID(), deviceName: "test-device-2", serialNumber: "456", osVersion: "iSomething (fake version)") @@ -740,22 +721,26 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { } func makeInitiatorContext(contextID: String, authKitAdapter: OTAuthKitAdapter) -> OTCuttlefishContext { + return self.makeInitiatorContext(contextID: contextID, authKitAdapter: authKitAdapter, sosAdapter: self.mockSOSAdapter) + } + + func makeInitiatorContext(contextID: String, authKitAdapter: OTAuthKitAdapter, sosAdapter: OTSOSAdapter) -> OTCuttlefishContext { // Note that the type of your initiator changes based on the platform you're currently on return self.manager.context(forContainerName: OTCKContainerName, contextID: contextID, - sosAdapter: self.mockSOSAdapter, + sosAdapter: sosAdapter, authKitAdapter: authKitAdapter, lockStateTracker: self.lockStateTracker, accountStateTracker: self.accountStateTracker, deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter()) } - func assertResetAndBecomeTrustedInDefaultContext() -> String { + @discardableResult func assertResetAndBecomeTrustedInDefaultContext() -> String { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -802,6 +787,18 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { return "failed" } } + + func assertSelfOSVersion(_ osVersion: String) { + + let statusExpectation = self.expectation(description: "status callback occurs") + self.tphClient.dumpEgoPeer(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID, reply: { _, _, stableInfo, _, error in + XCTAssertNil(error, "should be no error dumping ego peer") + XCTAssertEqual(stableInfo?.osVersion, osVersion, "os version should be as required") + statusExpectation.fulfill() + }) + + self.wait(for: [statusExpectation], timeout: 2) + } } class OctagonTests: OctagonTestsBase { @@ -913,7 +910,8 @@ class OctagonTests: OctagonTestsBase { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -934,7 +932,7 @@ class OctagonTests: OctagonTestsBase { func testLoadToNoAccount() throws { // No CloudKit account, either - self.accountStatus = .noAccount; + self.accountStatus = .noAccount self.startCKAccountStatusMock() // With no identity and AuthKit reporting no iCloud account, Octagon should go directly into 'no account' @@ -1105,7 +1103,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1125,6 +1123,41 @@ class OctagonTests: OctagonTestsBase { // TODO: add a CKKS item } + func testNewFriendsWithResetReasonForEmptyAccount() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.testGenerated.rawValue, "reset reason should be unknown") + return nil + } + + do { + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + } + + self.wait(for: [resetExpectation], timeout: 10) + + // Now, we should be in 'ready' + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext) + + // and all subCKKSes should enter ready... + assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) + } + func testCliqueStatusWhileLocked() throws { self.startCKAccountStatusMock() @@ -1132,7 +1165,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1154,20 +1187,18 @@ class OctagonTests: OctagonTestsBase { self.assertConsidersSelfTrusted(context: self.cuttlefishContext, isLocked: false) } - func testDeviceFetchRetry() throws { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.sendContainerChange(context: self.cuttlefishContext) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1187,29 +1218,28 @@ class OctagonTests: OctagonTestsBase { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.cuttlefishContext.notifyContainerChange(nil) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") } // Now, we should be in 'ready' - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 20 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) self.cuttlefishContext.notifyContainerChange(nil) - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 20 * NSEC_PER_SEC) } func testNewFriendsForEmptyAccountReturnsMoreChanges() throws { @@ -1221,7 +1251,7 @@ class OctagonTests: OctagonTestsBase { self.fakeCuttlefishServer.nextEstablishReturnsMoreChanges = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1240,7 +1270,7 @@ class OctagonTests: OctagonTestsBase { } func testNewFriendsForEmptyAccountWithoutTLKsResetsZones() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) // But do NOT add them to the keychain // CKKS+Octagon should reset the zones and be ready @@ -1254,7 +1284,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1270,7 +1300,7 @@ class OctagonTests: OctagonTestsBase { } func testUploadTLKsRetry() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) // But do NOT add them to the keychain // CKKS+Octagon should reset the zones and be ready @@ -1284,7 +1314,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1294,8 +1324,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) // and all subCKKSes should enter ready (eventually) @@ -1314,9 +1343,8 @@ class OctagonTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1333,8 +1361,7 @@ class OctagonTests: OctagonTestsBase { self.resetAllCKKSViews() - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) @@ -1344,17 +1371,16 @@ class OctagonTests: OctagonTestsBase { // these should be failures assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKUpload, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcStatus() { _, _ in - return - } + self.cuttlefishContext.rpcStatus { _, _ in + } self.verifyDatabaseMocks() XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(60 * NSEC_PER_SEC), "Main cuttlefish context should quiesce before the test ends") } func testNewFriendsForEmptyAccountWithTLKs() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - self.saveTLKMaterial(toKeychain: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) + self.saveTLKMaterial(toKeychain: self.manateeZoneID!) self.startCKAccountStatusMock() @@ -1370,7 +1396,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1394,7 +1420,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1440,7 +1466,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1458,7 +1484,7 @@ class OctagonTests: OctagonTestsBase { let query: [CFString: Any] = [ kSecClass: kSecClassKey, kSecAttrAccessGroup: "com.apple.security.egoIdentities", - kSecUseDataProtectionKeychain: kCFBooleanTrue, + kSecUseDataProtectionKeychain: true, ] let status = SecItemDelete(query as CFDictionary) @@ -1479,7 +1505,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1518,7 +1544,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1554,7 +1580,7 @@ class OctagonTests: OctagonTestsBase { // If CloudKit isn't returning our calls, we should still return something reasonable... let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in XCTAssertTrue([.absent].contains(egoStatus), "Self peer should be in the 'absent' state") statusexpectation.fulfill() @@ -1584,7 +1610,7 @@ class OctagonTests: OctagonTestsBase { // Now become ready do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1630,7 +1656,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique? do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1669,7 +1695,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1699,7 +1725,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1785,7 +1811,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1807,6 +1833,13 @@ class OctagonTests: OctagonTestsBase { XCTFail("Error thrown: \(error)") } + let peer2DeviceName = "peer2-asdf" + + let peer2DeviceAdapter = OTMockDeviceInfoAdapter(modelID: "AppleTV5,3", + deviceName: peer2DeviceName, + serialNumber: "peer2-asdf", + osVersion: "tvOS (fake version)") + // Now, fake up a voucher for the second peer using TPH let peer2ContextID = "asdf" let peer2 = self.manager.context(forContainerName: OTCKContainerName, @@ -1815,12 +1848,11 @@ class OctagonTests: OctagonTestsBase { authKitAdapter: self.mockAuthKit2, lockStateTracker: self.lockStateTracker, accountStateTracker: self.accountStateTracker, - deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + deviceInformationAdapter: peer2DeviceAdapter) self.setAllowListToCurrentAuthKit(container: OTCKContainerName, context: peer2ContextID) var peer2ID: String! - let peer2DeviceName = "peer2-asdf" let joinExpectation = self.expectation(description: "join callback occurs") self.tphClient.prepare(withContainer: OTCKContainerName, context: peer2ContextID, @@ -1828,10 +1860,10 @@ class OctagonTests: OctagonTestsBase { machineID: self.mockAuthKit2.currentMachineID, bottleSalt: "123456789", bottleID: UUID().uuidString, - modelID: "AppleTV5,3", - deviceName: peer2DeviceName, - serialNumber: "1234", - osVersion: "something", + modelID: peer2DeviceAdapter.modelID(), + deviceName: peer2DeviceAdapter.deviceName(), + serialNumber: peer2DeviceAdapter.serialNumber(), + osVersion: peer2DeviceAdapter.osVersion(), policyVersion: nil, policySecrets: nil, signingPrivKeyPersistentRef: nil, @@ -1929,7 +1961,7 @@ class OctagonTests: OctagonTestsBase { self.mockAuthKit.altDSID = "1234" let signinExpectation = self.expectation(description: "sign in returns") - self.otControl.sign(in: "1234", container: nil, context:OTDefaultContext) { error in + self.otControl.sign(in: "1234", container: nil, context: OTDefaultContext) { error in XCTAssertNil(error, "error should be nil") signinExpectation.fulfill() } @@ -1945,7 +1977,7 @@ class OctagonTests: OctagonTestsBase { do { let absentClique = try OTClique(contextData: self.otcliqueContext) - let absentStatus = absentClique.cachedCliqueStatus(true, error: nil) + let absentStatus = absentClique.fetchStatus(nil) XCTAssertEqual(absentStatus, CliqueStatus.absent, "clique should return Absent") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1957,10 +1989,10 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") - let status = clique.cachedCliqueStatus(true, error: nil) + let status = clique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.in, "clique should return In") } catch { @@ -1975,7 +2007,7 @@ class OctagonTests: OctagonTestsBase { // Technically, it's a server-side cuttlefish error for the last signed-in peer to leave. But, for now, just go for it. XCTAssertNoThrow(try clique.leave(), "Should be no error departing clique") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - let status = clique.cachedCliqueStatus(true, error: nil) + let status = clique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.notIn, "clique should return Not In") let newOTCliqueContext = OTConfigurationContext() @@ -1986,11 +2018,11 @@ class OctagonTests: OctagonTestsBase { let newClique: OTClique do { - newClique = try OTClique.newFriends(withContextData: newOTCliqueContext) + newClique = try OTClique.newFriends(withContextData: newOTCliqueContext, resetReason: .testGenerated) XCTAssertNotNil(newClique, "newClique should not be nil") OctagonSetPlatformSupportsSOS(true) - let status = newClique.cachedCliqueStatus(true, error: nil) + let status = newClique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.in, "clique should return In") } catch { @@ -2010,7 +2042,7 @@ class OctagonTests: OctagonTestsBase { json: false) do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } catch { XCTFail("failed to make new friends: \(error)") @@ -2030,7 +2062,7 @@ class OctagonTests: OctagonTestsBase { // Run initialization, like the real secd will do OctagonInitialize() - self.cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + self.cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) XCTAssertTrue(self.cuttlefishContext.stateMachine.isPaused(), "State machine should be stopped") @@ -2075,7 +2107,7 @@ class OctagonTests: OctagonTestsBase { // and now cause the watcher to fail... let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -2089,14 +2121,14 @@ class OctagonTests: OctagonTestsBase { func testLeaveCliqueAndPostCFU() throws { self.startCKAccountStatusMock() - + OctagonAuthoritativeTrustSetIsEnabled(true) self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2116,7 +2148,7 @@ class OctagonTests: OctagonTestsBase { let cfuExpectation = self.expectation(description: "cfu callback occurs") self.cuttlefishContext.setPostedBool(false) - self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary() { status, posted, egoPeerID, error in + self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary { _, posted, _, error in #if !os(tvOS) XCTAssertTrue(posted, "posted should be true") #else @@ -2127,7 +2159,7 @@ class OctagonTests: OctagonTestsBase { } self.wait(for: [cfuExpectation], timeout: 10) } - + func testDeviceLockedDuringAccountRetrieval() throws { self.startCKAccountStatusMock() @@ -2163,7 +2195,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2182,7 +2214,6 @@ class OctagonTests: OctagonTestsBase { self.fakeCuttlefishServer.deleteAllPeers() self.sendContainerChange(context: self.cuttlefishContext) - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) } @@ -2192,7 +2223,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2238,7 +2269,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2265,7 +2296,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2321,7 +2352,8 @@ class OctagonTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -2334,6 +2366,138 @@ class OctagonTests: OctagonTestsBase { self.wait(for: [trustedNotification], timeout: 2) } + func testDeviceNameNotifications() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let newDeviceName = "new-name-testDeviceNameNotifications" + self.mockDeviceInfo.mockDeviceName = newDeviceName + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.deviceName, newDeviceName, "name should be updated") + updateTrustExpectation.fulfill() + + return nil + } + + self.cuttlefishContext.deviceNameUpdated() + self.wait(for: [updateTrustExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + let statusExpectation = self.expectation(description: "status callback occurs") + self.tphClient.dumpEgoPeer(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID, reply: { _, _, stableInfo, _, error in + XCTAssertNil(error, "should be no error dumping ego peer") + XCTAssertEqual(stableInfo?.deviceName, newDeviceName, "device name should be updated") + statusExpectation.fulfill() + }) + self.wait(for: [statusExpectation], timeout: 2) + + // Receiving a push shouldn't cause another update to be sent + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testUpdateDeviceOSVersionOnRestart() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let differentVersion = "iOS (different version)" + self.mockDeviceInfo.mockOsVersion = differentVersion + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.osVersion, differentVersion, "version should be updated") + + updateTrustExpectation.fulfill() + return nil + } + + self.aksLockState = true + self.lockStateTracker.recheck() + + // re-start + self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC) + + self.aksLockState = false + self.lockStateTracker.recheck() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + + self.wait(for: [updateTrustExpectation], timeout: 10) + + // Double check that version + self.assertSelfOSVersion(differentVersion) + + // Second restart should not trigger an update + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + // re-start + self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testUpdateDeviceOSVersionOnContainerUpdate() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let differentVersion = "iOS (different version)" + self.mockDeviceInfo.mockOsVersion = differentVersion + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.osVersion, differentVersion, "version should be updated") + + updateTrustExpectation.fulfill() + return nil + } + self.cuttlefishContext.notifyContainerChange(nil) + self.wait(for: [updateTrustExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + self.assertSelfOSVersion(differentVersion) + + // Receiving a push shouldn't cause another update to be sent + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + func testAPSRateLimiter() throws { let untrustedNotification = XCTDarwinNotificationExpectation(notificationName: octagonNotificationName) @@ -2392,7 +2556,8 @@ class OctagonTests: OctagonTestsBase { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.manager.resetAndEstablish(OTCKContainerName, context: OTDefaultContext, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -2432,7 +2597,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2472,7 +2637,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2571,7 +2736,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2672,14 +2837,14 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { self.fakeCuttlefishServer.updateListener = nil self.sendAllCKKSTrustedPeersChanged() - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() } } } } -class OctagonTestsOverrideModelTV: OctagonTestsOverrideModelBase { +class OctagonTestsOverrideModletV: OctagonTestsOverrideModelBase { // If this test is running on a TV, we will send TLKs, since we're using the LimitedPeersAllowed view #if !os(tvOS) let sendTLKsToAllPeers = false @@ -2687,20 +2852,25 @@ class OctagonTestsOverrideModelTV: OctagonTestsOverrideModelBase { let sendTLKsToAllPeers = true #endif - override func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapter(modelID: "AppleTV5,3", deviceName: "intro-TV", serialNumber: "456", osVersion: "iOS (whatever TV version)") + override func setUp() { + super.setUp() + + self.mockDeviceInfo.mockModelID = "AppleTV5,3" + self.mockDeviceInfo.mockDeviceName = "intro-TV" + self.mockDeviceInfo.mockSerialNumber = "456" + self.mockDeviceInfo.mockOsVersion = "iOS (whatever TV version)" } func testVoucherFromTV() throws { try self._testVouchers(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: false, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers), ]) } func testJoinFromTV() throws { try self._testJoin(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: false, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers), ]) } } @@ -2711,20 +2881,25 @@ class OctagonTestsOverrideModelMac: OctagonTestsOverrideModelBase { let sendTLKsToAllPeers = true #endif - override func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapter(modelID: "Mac17", deviceName: "macbook", serialNumber: "456", osVersion: "OSX 11") + override func setUp() { + super.setUp() + + self.mockDeviceInfo.mockModelID = "Mac17" + self.mockDeviceInfo.mockDeviceName = "macbook" + self.mockDeviceInfo.mockSerialNumber = "456" + self.mockDeviceInfo.mockOsVersion = "OSX 11" } func testVoucherFromMac() throws { try self._testVouchers(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: true, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: true, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: true, sendTLKs: sendTLKsToAllPeers), ]) } func testJoinFromMac() throws { try self._testJoin(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: true, sendTLKs: true), - TestCase(model: "Watch17", success: true, sendTLKs: true)]) + TestCase(model: "Watch17", success: true, sendTLKs: true), ]) } } diff --git a/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift b/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift index 364e8117..a972b584 100644 --- a/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift +++ b/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift @@ -13,7 +13,7 @@ class ProxyXPCConnection: NSObject, NSXPCListenerDelegate { self.listener = NSXPCListener.anonymous() super.init() - self.listener.delegate = self; + self.listener.delegate = self self.listener.resume() } diff --git a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift index 3e4d1147..1103b6a9 100644 --- a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift +++ b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift @@ -3,9 +3,9 @@ extension OctagonPairingTests { func assertSOSSuccess() { - XCTAssertNotNil(self.fcInitiator?.accountPrivateKey ?? nil, "no accountPrivateKey in fcInitiator"); - XCTAssertNotNil(self.fcAcceptor?.accountPrivateKey ?? nil, "no accountPrivateKey in fcAcceptor"); - XCTAssert(CFEqualSafe(self.fcInitiator.accountPrivateKey, self.fcAcceptor.accountPrivateKey), "no accountPrivateKey not same in both"); + XCTAssertNotNil(self.fcInitiator?.accountPrivateKey, "no accountPrivateKey in fcInitiator") + XCTAssertNotNil(self.fcAcceptor?.accountPrivateKey, "no accountPrivateKey in fcAcceptor") + XCTAssert(CFEqualSafe(self.fcInitiator.accountPrivateKey, self.fcAcceptor.accountPrivateKey), "no accountPrivateKey not same in both") XCTAssert(SOSCircleHasPeer(self.circle, self.fcInitiator.peerInfo(), nil), "HasPeer 1") // XCTAssert(SOSCircleHasPeer(self.circle, self.fcAcceptor.peerInfo(), nil), "HasPeer 2") @@ -205,8 +205,7 @@ extension OctagonPairingTests { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) /* calling Join */ - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) @@ -321,8 +320,10 @@ extension OctagonPairingTests { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) /* calling Join */ - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) @@ -336,7 +337,7 @@ extension OctagonPairingTests { XCTAssertNotNil(error, "error should be set") rpcJoinCallbackOccurs.fulfill() } - self.wait(for: [rpcJoinCallbackOccurs], timeout: 64) + self.wait(for: [rpcJoinCallbackOccurs], timeout: 35) } func testJoinWithCKKSConflict() { @@ -639,7 +640,7 @@ extension OctagonPairingTests { self.startCKAccountStatusMock() let rpcCallbackOccurs = self.expectation(description: "rpcPrepare callback occurs") - self.initiatorPairingConfig.timeout = Int64(2*NSEC_PER_SEC) + self.initiatorPairingConfig.timeout = Int64(2 * NSEC_PER_SEC) self.cuttlefishContext.rpcPrepareIdentityAsApplicant(with: self.initiatorPairingConfig, epoch: 1) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in XCTAssertNotNil(error, "Should be an error calling 'prepare'") @@ -714,7 +715,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -729,7 +729,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -858,7 +857,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -873,7 +871,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1000,7 +997,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1015,7 +1011,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1106,7 +1101,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1121,7 +1115,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1349,7 +1342,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1421,7 +1413,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1436,7 +1427,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1506,7 +1496,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1521,7 +1510,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1574,7 +1562,7 @@ extension OctagonPairingTests { acceptor.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") - acceptor.rpcResetAndEstablish() { resetError in + acceptor.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -1585,145 +1573,7 @@ extension OctagonPairingTests { self.assertConsidersSelfTrusted(context: acceptor) XCTAssertEqual(self.fakeCuttlefishServer.state.bottles.count, 1, "should be 1 bottles") } - /* TODO: FIX ME!!!! - func testOctagonUpgradeAfterReceivingSOSCCCircleChangedNotification() throws { - OctagonSetPlatformSupportsSOS(true) - OctagonSetIsEnabled(false) - OctagonAuthoritativeTrustSetIsEnabled(true) - OctagonSetSOSUpgrade(true) - self.startCKAccountStatusMock() - - self.manager.initializeOctagon() - - let (acceptor, initiator) = self.setupPairingEndpoints(withPairNumber: "1", initiatorContextID: OTDefaultContext, acceptorContextID: self.contextForAcceptor, initiatorUniqueID: self.initiatorName, acceptorUniqueID: "acceptor-2") - - XCTAssertNotNil(acceptor, "acceptor should not be nil") - XCTAssertNotNil(initiator, "initiator should not be nil") - - /* INITIATOR FIRST RTT JOINING MESSAGE*/ - var initiatorFirstPacket = Data() - let firstInitiatorCallback = self.expectation(description: "firstInitiatorCallback callback occurs") - - initiator.exchangePacket(nil) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorFirstPacket = packet! - firstInitiatorCallback.fulfill() - } - - self.wait(for: [firstInitiatorCallback], timeout: 10) - - /* ACCEPTOR FIRST RTT EPOCH*/ - var acceptorFirstPacket = Data() - let firstAcceptorCallback = self.expectation(description: "firstAcceptorCallback callback occurs") - - acceptor.exchangePacket(initiatorFirstPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorFirstPacket = packet! - firstAcceptorCallback.fulfill() - } - self.wait(for: [firstAcceptorCallback], timeout: 10) - - - /* INITIATOR SECOND RTT PREPARE*/ - var initiatorSecondPacket = Data() - let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorFirstPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorSecondPacket = packet! - secondInitiatorCallback.fulfill() - } - - self.wait(for: [secondInitiatorCallback], timeout: 10) - - - try self.circleAndSOS() - - /* ACCEPTOR SECOND RTT */ - var acceptorSecondPacket = Data() - let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") - acceptor.exchangePacket(initiatorSecondPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorSecondPacket = packet! - SecondAcceptorCallback.fulfill() - } - self.wait(for: [SecondAcceptorCallback], timeout: 10) - XCTAssertNotNil(acceptorSecondPacket, "acceptor second packet should not be nil") - - /* INITIATOR THIRD STEP*/ - var initiatorThirdPacket: Data? - let thirdInitiatorCallback = self.expectation(description: "thirdInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorSecondPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorThirdPacket = packet! - thirdInitiatorCallback.fulfill() - } - self.wait(for: [thirdInitiatorCallback], timeout: 10) - XCTAssertNotNil(initiatorThirdPacket, "acceptor second packet should not be nil") - - /* ACCEPTOR THIRD RTT */ - var acceptorThirdPacket = Data() - let ThirdAcceptorCallback = self.expectation(description: "ThirdAcceptorCallback callback occurs") - - acceptor.exchangePacket(initiatorSecondPacket) { complete, packet, error in - XCTAssertTrue(complete, "should be true") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorThirdPacket = packet! - ThirdAcceptorCallback.fulfill() - } - self.wait(for: [ThirdAcceptorCallback], timeout: 10) - XCTAssertNotNil(acceptorThirdPacket, "acceptor third packet should not be nil") - - /* INITIATOR Fourth STEP*/ - let fourthInitiatorCallback = self.expectation(description: "fourthInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorThirdPacket) { complete, packet, error in - XCTAssertTrue(complete, "should be true") - XCTAssertNil(packet, "packet should be nil") - XCTAssertNil(error, "error should be nil") - fourthInitiatorCallback.fulfill() - } - self.wait(for: [fourthInitiatorCallback], timeout: 10) - - let peerInfo: SOSPeerInfoRef = SOSFullPeerInfoGetPeerInfo(self.fcInitiator.fullPeerInfo) - let encryptionKey = _SFECKeyPair.init(secKey: self.fcInitiator.octagonEncryptionKey) - let signingKey = _SFECKeyPair.init(secKey: self.fcInitiator.octagonSigningKey) - let peerID: NSString = (SOSPeerInfoGetPeerID(peerInfo) .takeUnretainedValue() as NSString) - let initiatorSOSPeer = CKKSSOSSelfPeer(sosPeerID: peerID as String, - encryptionKey: encryptionKey, - signingKey: signingKey) - self.mockSOSAdapter.trustedPeers.add(initiatorSOSPeer) - - let mockSOS = CKKSMockSOSPresentAdapter(selfPeer: initiatorSOSPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) - mockSOS.circleStatus = SOSCCStatus(kSOSCCInCircle) - let initiatorContext = self.manager.context(forContainerName: OTCKContainerName, - contextID: OTDefaultContext, - sosAdapter: mockSOS, - authKitAdapter: self.mockAuthKit2, - lockStateTracker: self.lockStateTracker, - accountStateTracker: self.accountStateTracker, - deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) - - self.manager.moveToCheckTrustedState(forContainer: OTCKContainerName, context: OTDefaultContext) - - //test circle changed notification fired - self.assertEnters(context: initiatorContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) - self.verifyDatabaseMocks() - } -*/ func testProximitySetupUsingCliqueAcceptorResolvesVersionToSOSOnly() { self.startCKAccountStatusMock() @@ -1787,7 +1637,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - initiator.setSessionSupportsOctagonForTesting(false) /* INITIATOR SECOND RTT PREPARE*/ diff --git a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift index deb56286..ea84fc76 100644 --- a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift +++ b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift @@ -78,6 +78,7 @@ class KCJoiningRequestTestDelegate: NSObject, KCJoiningRequestSecretDelegate, KC } class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate { + var secrets: Array = [] var currentSecret: Int = 0 var retriesLeft: Int = 0 @@ -157,7 +158,7 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo } } - func circleGetInitialSyncViews(_ error: NSErrorPointer) -> Data { + func circleGetInitialSyncViews(_ flags: SOSInitialSyncFlags, error: NSErrorPointer) -> Data { return Data() } } @@ -206,7 +207,7 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo func getAcceptorInCircle() { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.cuttlefishContextForAcceptor.startOctagonStateMachine() - self.cuttlefishContextForAcceptor.rpcResetAndEstablish() { resetError in + self.cuttlefishContextForAcceptor.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } diff --git a/keychain/otctl/OTControlCLI.m b/keychain/otctl/OTControlCLI.m index ac949dff..5fa418c4 100644 --- a/keychain/otctl/OTControlCLI.m +++ b/keychain/otctl/OTControlCLI.m @@ -184,6 +184,7 @@ static void print_json(NSDictionary* dict) [self.control resetAndEstablish:container context:contextID altDSID:altDSID + resetReason:CuttlefishResetReasonUserInitiatedReset reply:^(NSError* _Nullable error) { if(error) { printf("Error resetting: %s\n", [[error description] UTF8String]); diff --git a/keychain/otpaird/OTPairingConstants.h b/keychain/otpaird/OTPairingConstants.h index e5de4f7f..309ee32a 100644 --- a/keychain/otpaird/OTPairingConstants.h +++ b/keychain/otpaird/OTPairingConstants.h @@ -38,3 +38,5 @@ enum { #define OTPairingXPCActivityInterval XPC_ACTIVITY_INTERVAL_1_HOUR #define OTPairingXPCActivityPoke "com.apple.security.otpaird.poke" + +#define OTPairingXPCEventIDSDeviceState "ids-device-state" diff --git a/keychain/otpaird/OTPairingService.h b/keychain/otpaird/OTPairingService.h index 61c41c56..0cd8b1d7 100644 --- a/keychain/otpaird/OTPairingService.h +++ b/keychain/otpaird/OTPairingService.h @@ -5,6 +5,8 @@ typedef void (^OTPairingCompletionHandler)(bool success, NSError *error); @interface OTPairingService : NSObject +@property (readonly) NSString *pairedDeviceNotificationName; + + (instancetype)sharedService; #if TARGET_OS_WATCH diff --git a/keychain/otpaird/OTPairingService.m b/keychain/otpaird/OTPairingService.m index 22f1bbeb..c1b70852 100644 --- a/keychain/otpaird/OTPairingService.m +++ b/keychain/otpaird/OTPairingService.m @@ -60,6 +60,18 @@ return self; } +- (NSString *)pairedDeviceNotificationName +{ + NSString *result = nil; + for (IDSDevice *device in self.service.devices) { + if (device.isDefaultPairedDevice) { + result = [NSString stringWithFormat:@"ids-device-state-%@", device.uniqueIDOverride]; + break; + } + } + return result; +} + #if TARGET_OS_WATCH - (void)initiatePairingWithCompletion:(OTPairingCompletionHandler)completionHandler { @@ -174,6 +186,12 @@ NSString *responseIdentifier; os_log(OS_LOG_DEFAULT, "exchangePacket: complete=%d responsePacket=%@ channelError=%@", complete, responsePacket, channelError); + + if (self.session == nil) { + os_log(OS_LOG_DEFAULT, "pairing session went away, dropping exchangePacket response"); + return; + } + if (channelError != nil) { #if TARGET_OS_IOS NSError *cleansedError = [SecXPCHelper cleanseErrorForXPC:channelError]; diff --git a/keychain/otpaird/main.m b/keychain/otpaird/main.m index ec1ed214..02246c11 100644 --- a/keychain/otpaird/main.m +++ b/keychain/otpaird/main.m @@ -3,7 +3,6 @@ #import #import #if TARGET_OS_WATCH -#import #import #endif /* TARGET_OS_WATCH */ @@ -12,9 +11,11 @@ #if TARGET_OS_WATCH static void create_xpc_listener(xpc_handler_t handler); -static bool should_retry(NSError *error); +static void handle_pairing_result(bool success, NSError *error); static void pairing_retry_register(bool checkin); static void pairing_retry_unregister(void); +static void ids_retry_init(void); +static void ids_retry_enable(bool); #endif /* TARGET_OS_WATCH */ int @@ -30,6 +31,8 @@ main() /* Check in; handle a possibly-pending retry. */ pairing_retry_register(true); + ids_retry_init(); + create_xpc_listener(^(xpc_object_t message) { xpc_object_t reply; @@ -55,10 +58,7 @@ main() connection = xpc_dictionary_get_remote_connection(reply); xpc_connection_send_message(connection, reply); - // Retry on failure - unless we were already in - if (!success && should_retry(error)) { - pairing_retry_register(false); - } + handle_pairing_result(success, error); }]; }); #endif /* TARGET_OS_WATCH */ @@ -98,26 +98,51 @@ create_xpc_listener(xpc_handler_t handler) xpc_connection_activate(listener); } -static bool -should_retry(NSError *error) +static void +handle_pairing_result(bool success, NSError *error) { - bool retry; - - if ([error.domain isEqualToString:OTPairingErrorDomain]) { - switch (error.code) { - case OTPairingErrorTypeAlreadyIn: - case OTPairingErrorTypeBusy: - retry = false; - break; - default: - retry = true; - break; - } + bool actual_success = false; + bool standard_retry = false; + bool ids_retry = false; + + if (success) { + actual_success = true; } else { - retry = true; + if ([error.domain isEqualToString:OTPairingErrorDomain]) { + switch (error.code) { + /* AlreadyIn: Treat like success; unregister all retries. */ + case OTPairingErrorTypeAlreadyIn: + actual_success = true; + break; + /* Busy: In progress. Do nothing, leave any configured retries. */ + case OTPairingErrorTypeBusy: + break; + /* IDS error. Set up IDS retry _and_ standard retry. */ + case OTPairingErrorTypeIDS: + standard_retry = true; + ids_retry = true; + break; + /* Other error, standard retry. */ + default: + standard_retry = true; + break; + } + } else { + standard_retry = true; + } } - return retry; + if (actual_success) { + pairing_retry_unregister(); + ids_retry_enable(false); + } else { + if (standard_retry) { + pairing_retry_register(false); + } + if (ids_retry) { + ids_retry_enable(true); + } + } } static void @@ -164,4 +189,53 @@ pairing_retry_unregister(void) { xpc_activity_unregister(OTPairingXPCActivityIdentifier); } + +static void +ids_retry_init(void) +{ + xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t event) { + const char *name; + uint64_t state; + + name = xpc_dictionary_get_string(event, XPC_EVENT_KEY_NAME); + if (strcmp(name, OTPairingXPCEventIDSDeviceState) != 0) { + return; + } + + state = xpc_dictionary_get_uint64(event, "_State"); + if ((state & kIDSDeviceStatePropertiesIsNearby) && (state & kIDSDeviceStatePropertiesIsConnected)) { + OTPairingService *service = [OTPairingService sharedService]; + os_log(OS_LOG_DEFAULT, "IDS paired device is connected, retrying"); + [service initiatePairingWithCompletion:^(bool success, NSError *error) { + if (success) { + os_log(OS_LOG_DEFAULT, "IDS notification retry succeeded"); + } else { + os_log(OS_LOG_DEFAULT, "IDS notification retry failed: %@", error); + } + handle_pairing_result(success, error); + }]; + } + }); +} + +static void +ids_retry_enable(bool enable) +{ + const char *notification; + xpc_object_t dict; + + @autoreleasepool { + if (enable) { + notification = [OTPairingService sharedService].pairedDeviceNotificationName.UTF8String; + if (notification != NULL) { + dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(dict, "Notification", notification); + } + } else { + dict = NULL; + } + + xpc_set_event("com.apple.notifyd.matching", OTPairingXPCEventIDSDeviceState, dict); + } +} #endif /* TARGET_OS_WATCH */ diff --git a/keychain/securityd/CheckV12DevEnabled.h b/keychain/securityd/CheckV12DevEnabled.h new file mode 100644 index 00000000..34c930d5 --- /dev/null +++ b/keychain/securityd/CheckV12DevEnabled.h @@ -0,0 +1,14 @@ +// +// CheckV12DevEnabled.h +// Security_ios +// +// Created by Wouter de Groot on 2018-10-20. +// + +#ifndef CHECKV12DEVENABLED_H_ +#define CHECKV12DEVENABLED_H_ + +void resetCheckV12DevEnabled(void); +extern int (*checkV12DevEnabled)(void); + +#endif diff --git a/keychain/securityd/CheckV12DevEnabled.m b/keychain/securityd/CheckV12DevEnabled.m new file mode 100644 index 00000000..b211e141 --- /dev/null +++ b/keychain/securityd/CheckV12DevEnabled.m @@ -0,0 +1,33 @@ +// +// CheckV12DevEnabled.m +// Security_ios +// +// Created by Wouter de Groot on 2018-10-20. +// + +// TODO: remove me when keychain backup is enabled for all + +#include "CheckV12DevEnabled.h" + +#if __OBJC2__ + +#import +#import + +static int realCheckV12DevEnabled() { + static bool enabled = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + enabled = [defaults boolForKey:@"enableKeychainBackupDevelopment"]; + }); + return enabled ? 1 : 0; +} + +int (*checkV12DevEnabled)(void) = realCheckV12DevEnabled; + +void resetCheckV12DevEnabled(void) { + checkV12DevEnabled = realCheckV12DevEnabled; +} + +#endif diff --git a/keychain/securityd/Info-macOS.plist b/keychain/securityd/Info-macOS.plist new file mode 100644 index 00000000..db4a61ea --- /dev/null +++ b/keychain/securityd/Info-macOS.plist @@ -0,0 +1,26 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + English + CFBundleExecutable + secd + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + securityd + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/keychain/securityd/PolicyReporter.h b/keychain/securityd/PolicyReporter.h new file mode 100644 index 00000000..bc9a3c15 --- /dev/null +++ b/keychain/securityd/PolicyReporter.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _SECURITY_POLICY_REPORTER_H +#define _SECURITY_POLICY_REPORTER_H + +#include + +__BEGIN_DECLS +void InitPolicyReporter(void); +__END_DECLS + +#endif diff --git a/keychain/securityd/PolicyReporter.m b/keychain/securityd/PolicyReporter.m new file mode 100644 index 00000000..c5b42c66 --- /dev/null +++ b/keychain/securityd/PolicyReporter.m @@ -0,0 +1,339 @@ +#include "PolicyReporter.h" + +#import +#import +#import +#import +#import +#import +#import +#import + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#import "utilities/debugging.h" +#import "TrustedPeers/TrustedPeers.h" + +// Stolen from keychain/SecureObjectSync/SOSEngine.c + +static NSString* getSOSView(id object, NSString* itemClass) { + if (![object isKindOfClass:[NSDictionary class]]) { + return nil; + } + + NSString *viewHint = object[(NSString*)kSecAttrSyncViewHint]; + if (viewHint != nil) { + return viewHint; + } else { + NSString *ag = object[(NSString*)kSecAttrAccessGroup]; + if ([itemClass isEqualToString: (NSString*)kSecClassKey] && [ag isEqualToString: @"com.apple.security.sos"]) { + return (NSString*)kSOSViewiCloudIdentity; + } else if ([ag isEqualToString: @"com.apple.cfnetwork"]) { + return (NSString*)kSOSViewAutofillPasswords; + } else if ([ag isEqualToString: @"com.apple.safari.credit-cards"]) { + return (NSString*)kSOSViewSafariCreditCards; + } else if ([itemClass isEqualToString: (NSString*)kSecClassGenericPassword]) { + if ([ag isEqualToString: @"apple"] && + [object[(NSString*)kSecAttrService] isEqualToString: @"AirPort"]) { + return (NSString*)kSOSViewWiFi; + } else if ([ag isEqualToString: @"com.apple.sbd"]) { + return (NSString*)kSOSViewBackupBagV0; + } else { + return (NSString*)kSOSViewOtherSyncable; // (genp) + } + } else { + return (NSString*)kSOSViewOtherSyncable; // (inet || keys) + } + } +} + +static inline NSNumber *now_msecs() { + return @(((long)[[NSDate date] timeIntervalSince1970] * 1000)); +} + +static NSString* cloudKitDeviceID() { + __block NSString* ret = nil; + + if (!os_variant_has_internal_diagnostics("com.apple.security")) { + return nil; + } + CKContainer *container = [CKContainer containerWithIdentifier:@"com.apple.security.keychain"]; + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + [container fetchCurrentDeviceIDWithCompletionHandler:^(NSString* deviceID, NSError* error) { + if (error != nil) { + NSLog(@"failed to fetch CK deviceID: %@", error); + } else { + ret = deviceID; + } + dispatch_semaphore_signal(sem); + }]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + return ret; +} + +static void reportStats(unsigned expected_mismatches, unsigned real_mismatches, NSArray* reportedMismatches) { + NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfiguration]; + NSURL *endpoint = [NSURL URLWithString:@"https://xp.apple.com/report/2/xp_sear_keysync"]; + NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init]; + req.URL = endpoint; + req.HTTPMethod = @"POST"; + NSMutableDictionary *dict = [@{ + @"expectedMismatches": @(expected_mismatches), + @"realMismatches": @(real_mismatches), + @"eventTime": now_msecs(), + @"topic": @"xp_sear_keysync", + @"eventType": @"policy-dryrun", + } mutableCopy]; + NSDictionary *version = CFBridgingRelease(_CFCopySystemVersionDictionary()); + NSString *build = version[(__bridge NSString *)_kCFSystemVersionBuildVersionKey]; + if (build != nil) { + dict[@"build"] = build; + } else { + NSLog(@"Unable to find out build version"); + } + NSString *product = version[(__bridge NSString *)_kCFSystemVersionProductNameKey]; + if (product != nil) { + dict[@"product"] = product; + } else { + NSLog(@"Unable to find out build product"); + } + NSString* ckDeviceID = cloudKitDeviceID(); + if (ckDeviceID) { + dict[@"SFAnalyticsDeviceID"] = ckDeviceID; + dict[@"ckdeviceID"] = ckDeviceID; + } else { + NSLog(@"Unable to fetch CK device ID"); + } + + dict[@"mismatches"] = reportedMismatches; + + NSArray* events = @[dict]; + NSDictionary *wrapper = @{ + @"postTime": @([[NSDate date] timeIntervalSince1970] * 1000), + @"events": events, + }; + NSError *encodeError = nil; + NSData* post_data = [NSJSONSerialization dataWithJSONObject:wrapper options:0 error:&encodeError]; + if (post_data == nil || encodeError != nil) { + NSLog(@"failed to encode data: %@", encodeError); + return; + } + NSLog(@"logging %@, %@", wrapper, post_data); + req.HTTPBody = post_data; + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + NSURLSessionDataTask *task = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (error != nil) { + NSLog(@"splunk upload failed: %@", error); + return; + } + NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*)response; + if (httpResp.statusCode != 200) { + NSLog(@"HTTP Post error: %@", httpResp); + } + NSLog(@"%@", httpResp); + if (data != nil) { + size_t length = [data length]; + char *buf = malloc(length); + [data getBytes:buf length:length]; + NSLog(@"%.*s", (int)length, buf); + free(buf); + } + dispatch_semaphore_signal(sem); + }]; + [task resume]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); +} + +static void oneReport(void) { + NSError* error = nil; + + // From Swift.policy, policy v5 + TPPolicyDocument *tpd = [TPPolicyDocument policyDocWithHash:@"SHA256:O/ECQlWhvNlLmlDNh2+nal/yekUC87bXpV3k+6kznSo=" + data:[[NSData alloc] initWithBase64EncodedString: + @"CAUSDgoGaVBob25lEgRmdWxsEgwKBGlQYWQSBGZ1bGwSDAoEaVBvZBIEZnVsbBILCgNNYWMSBGZ1bGwSDAoEaU1hYxIEZnVsbBINCgdBcHBsZVRWEgJ0dhIOCgVXYXRjaBIFd2F0Y2gSFwoOQXVkaW9BY2Nlc3NvcnkSBWF1ZGlvGhsKDEFwcGxpY2F0aW9ucxIEZnVsbBIFd2F0Y2gaHwoQU2VjdXJlT2JqZWN0U3luYxIEZnVsbBIFd2F0Y2gaHAoNRGV2aWNlUGFpcmluZxIEZnVsbBIFd2F0Y2gaGgoLQ3JlZGl0Q2FyZHMSBGZ1bGwSBXdhdGNoGhUKBkhlYWx0aBIEZnVsbBIFd2F0Y2gaLQoTTGltaXRlZFBlZXJzQWxsb3dlZBIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxokChVQcm90ZWN0ZWRDbG91ZFN0b3JhZ2USBGZ1bGwSBXdhdGNoGhcKCEFwcGxlUGF5EgRmdWxsEgV3YXRjaBoZCgpBdXRvVW5sb2NrEgRmdWxsEgV3YXRjaBoWCgdNYW5hdGVlEgRmdWxsEgV3YXRjaBoYCglQYXNzd29yZHMSBGZ1bGwSBXdhdGNoGhUKBkVuZ3JhbRIEZnVsbBIFd2F0Y2gaHgoEV2lGaRIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxoTCgRIb21lEgRmdWxsEgV3YXRjaCIbCgVhdWRpbxIEZnVsbBIFd2F0Y2gSBWF1ZGlvIhMKBGZ1bGwSBGZ1bGwSBXdhdGNoIhUKAnR2EgRmdWxsEgV3YXRjaBICdHYiFAoFd2F0Y2gSBGZ1bGwSBXdhdGNoMiIKFgAEIhICBHZ3aHQKCl5BcHBsZVBheSQSCEFwcGxlUGF5MiYKGAAEIhQCBHZ3aHQKDF5BdXRvVW5sb2NrJBIKQXV0b1VubG9jazIeChQABCIQAgR2d2h0CgheRW5ncmFtJBIGRW5ncmFtMh4KFAAEIhACBHZ3aHQKCF5IZWFsdGgkEgZIZWFsdGgyGgoSAAQiDgIEdndodAoGXkhvbWUkEgRIb21lMiAKFQAEIhECBHZ3aHQKCV5NYW5hdGVlJBIHTWFuYXRlZTI4CiEABCIdAgR2d2h0ChVeTGltaXRlZFBlZXJzQWxsb3dlZCQSE0xpbWl0ZWRQZWVyc0FsbG93ZWQyXQpQAAISHgAEIhoCBHZ3aHQKEl5Db250aW51aXR5VW5sb2NrJBIVAAQiEQIEdndodAoJXkhvbWVLaXQkEhUABCIRAgR2d2h0CgleQXBwbGVUViQSCU5vdFN5bmNlZDIrChsABCIXAgRhZ3JwCg9eWzAtOUEtWl17MTB9XC4SDEFwcGxpY2F0aW9uczLFAQqwAQACEjQAAQoTAAQiDwIFY2xhc3MKBl5nZW5wJAobAAQiFwIEYWdycAoPXmNvbS5hcHBsZS5zYmQkEj0AAQoTAAQiDwIFY2xhc3MKBl5rZXlzJAokAAQiIAIEYWdycAoYXmNvbS5hcHBsZS5zZWN1cml0eS5zb3MkEhkABCIVAgR2d2h0Cg1eQmFja3VwQmFnVjAkEhwABCIYAgR2d2h0ChBeaUNsb3VkSWRlbnRpdHkkEhBTZWN1cmVPYmplY3RTeW5jMmMKWwACEhIABCIOAgR2d2h0CgZeV2lGaSQSQwABChMABCIPAgVjbGFzcwoGXmdlbnAkChMABCIPAgRhZ3JwCgdeYXBwbGUkChUABCIRAgRzdmNlCgleQWlyUG9ydCQSBFdpRmkynQMKgwMAAhIYAAQiFAIEdndodAoMXlBDUy1CYWNrdXAkEhoABCIWAgR2d2h0Cg5eUENTLUNsb3VkS2l0JBIYAAQiFAIEdndodAoMXlBDUy1Fc2Nyb3ckEhUABCIRAgR2d2h0CgleUENTLUZERSQSGgAEIhYCBHZ3aHQKDl5QQ1MtRmVsZHNwYXIkEhoABCIWAgR2d2h0Cg5eUENTLU1haWxEcm9wJBIaAAQiFgIEdndodAoOXlBDUy1NYWlsZHJvcCQSGwAEIhcCBHZ3aHQKD15QQ1MtTWFzdGVyS2V5JBIXAAQiEwIEdndodAoLXlBDUy1Ob3RlcyQSGAAEIhQCBHZ3aHQKDF5QQ1MtUGhvdG9zJBIZAAQiFQIEdndodAoNXlBDUy1TaGFyaW5nJBIeAAQiGgIEdndodAoSXlBDUy1pQ2xvdWRCYWNrdXAkEh0ABCIZAgR2d2h0ChFeUENTLWlDbG91ZERyaXZlJBIaAAQiFgIEdndodAoOXlBDUy1pTWVzc2FnZSQSFVByb3RlY3RlZENsb3VkU3RvcmFnZTI6CisABCInAgRhZ3JwCh9eY29tLmFwcGxlLnNhZmFyaS5jcmVkaXQtY2FyZHMkEgtDcmVkaXRDYXJkczIuCiEABCIdAgRhZ3JwChVeY29tLmFwcGxlLmNmbmV0d29yayQSCVBhc3N3b3JkczJtClwAAhIeAAQiGgIEdndodAoSXkFjY2Vzc29yeVBhaXJpbmckEhoABCIWAgR2d2h0Cg5eTmFub1JlZ2lzdHJ5JBIcAAQiGAIEdndodAoQXldhdGNoTWlncmF0aW9uJBINRGV2aWNlUGFpcmluZzIOCgIABhIIQmFja3N0b3A=" options:0]]; + + TPPolicy *policy = [tpd policyWithSecrets:@{} decrypter:nil error:&error]; + if (error != nil) { + NSLog(@"policy error: %@", error); + return; + } + if (policy == nil) { + NSLog(@"policy is nil"); + return; + } + + unsigned real_mismatches = 0; + unsigned expected_mismatches = 0; + NSMutableArray* reportedMismatches = [[NSMutableArray alloc] init]; + + NSArray* keychainClasses = @[(id)kSecClassInternetPassword, + (id)kSecClassGenericPassword, + (id)kSecClassKey, + (id)kSecClassCertificate]; + + for(NSString* itemClass in keychainClasses) { + NSDictionary *query = @{ (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecClass : (id)itemClass, + (id)kSecReturnAttributes : @YES, + (id)kSecAttrSynchronizable: @YES, + (id)kSecUseDataProtectionKeychain: @YES, + (id)kSecUseAuthenticationUI : (id)kSecUseAuthenticationUISkip, + }; + + NSArray *result; + + OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (void*)&result); + if (status) { + if (status == errSecItemNotFound) { + NSLog(@"no items found matching: %@", query); + continue; + } else { + NSLog(@"SecItemCopyMatching(%@) failed: %d", query, (int)status); + return; + } + } + + if (![result isKindOfClass:[NSArray class]]) { + NSLog(@"expected NSArray result from SecItemCopyMatching"); + return; + } + + for (id a in result) { + NSLog(@"%@", a); + NSString *oldView = getSOSView(a, itemClass); + if (oldView != nil) { + NSLog(@"old: %@", oldView); + } + + NSMutableDictionary* mutA = [a mutableCopy]; + mutA[(id)kSecClass] = (id)itemClass; + + NSString* newView = [policy mapKeyToView:mutA]; + if (newView != nil) { + NSLog(@"new: %@", newView); + } + if(oldView == nil ^ newView == nil) { + NSLog(@"real mismatch: old view (%@) != new view (%@)", oldView, newView); + ++real_mismatches; + [reportedMismatches addObject: a]; + + } else if (oldView && newView && ![oldView isEqualToString: newView]) { + if ([oldView hasPrefix:@"PCS-"] && [newView isEqualToString: @"ProtectedCloudStorage"]) { + NSLog(@"(expected PCS mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else if([oldView isEqualToString:@"OtherSyncable"] && [newView isEqualToString: @"Applications"]) { + NSLog(@"(expected 3rd party mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else if([oldView isEqualToString:@"OtherSyncable"] && [newView isEqualToString: @"Backstop"]) { + NSLog(@"(expected backstop mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else if([newView isEqualToString:@"NotSynced"]) { + NSLog(@"(expected NotSynced mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else if(([oldView isEqualToString:@"BackupBagV0"] || [oldView isEqualToString:@"iCloudIdentity"]) && [newView isEqualToString:@"SecureObjectSync"]) { + NSLog(@"(expected BackupBag - SecureObjectSync mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else if(([oldView isEqualToString:@"AccessoryPairing"] + || [oldView isEqualToString:@"NanoRegistry"] + || [oldView isEqualToString:@"WatchMigration"]) && [newView isEqualToString:@"DevicePairing"]) { + NSLog(@"(expected DevicePairing mismatch): old view (%@) != new view (%@)", oldView, newView); + ++expected_mismatches; + + } else { + NSLog(@"real mismatch: old view (%@) != new view (%@)", oldView, newView); + ++real_mismatches; + [reportedMismatches addObject: a]; + } + } + } + } + + NSLog(@"%d expected_mismatches", expected_mismatches); + NSLog(@"%d real_mismatches", real_mismatches); + reportStats(expected_mismatches, real_mismatches, reportedMismatches); +} + +static dispatch_queue_t queue; + +static void report(void); + +static void maybeReport(void) { + CFErrorRef error = NULL; + bool locked = true; + if (!SecAKSGetIsLocked(&locked, &error)) { + secerror("PolicyReporter: %@", error); + CFReleaseNull(error); + xpc_object_t options = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(options, XPC_ACTIVITY_DELAY, random() % 60); + xpc_dictionary_set_uint64(options, XPC_ACTIVITY_GRACE_PERIOD, 30); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REPEATING, false); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_ALLOW_BATTERY, true); + xpc_dictionary_set_string(options, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_UTILITY); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRE_NETWORK_CONNECTIVITY, true); +#if TARGET_OS_IPHONE + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRES_CLASS_A, true); +#endif + xpc_activity_register("com.apple.security.securityd.policy-reporting2", + options, ^(xpc_activity_t activity) { + report(); + }); + return; + } + + if (locked) { + int token = 0; + notify_register_dispatch(kUserKeybagStateChangeNotification, &token, queue, ^(int t) { + report(); + }); + return; + } + oneReport(); +} + +static void report() { + @autoreleasepool { + maybeReport(); + } +} + +void InitPolicyReporter(void) { + if (!os_feature_enabled(Security, securitydReportPolicy)) { + secnotice("securityd-PolicyReporter", "not enabled by feature flag"); + return; + } + + srandom(getpid() ^ (int)time(NULL)); + queue = dispatch_queue_create("com.apple.security.securityd_reporting", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + xpc_object_t options = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(options, XPC_ACTIVITY_DELAY, random() % 3600); + xpc_dictionary_set_uint64(options, XPC_ACTIVITY_GRACE_PERIOD, 1800); + xpc_dictionary_set_uint64(options, XPC_ACTIVITY_INTERVAL, 3600); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REPEATING, true); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_ALLOW_BATTERY, true); + xpc_dictionary_set_string(options, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_UTILITY); + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRE_NETWORK_CONNECTIVITY, true); +#if TARGET_OS_IPHONE + xpc_dictionary_set_bool(options, XPC_ACTIVITY_REQUIRES_CLASS_A, true); +#endif + + xpc_activity_register("com.apple.security.securityd.policy-reporting", + options, ^(xpc_activity_t activity) { + report(); + }); +} diff --git a/keychain/securityd/Regressions/SOSAccountTesting.h b/keychain/securityd/Regressions/SOSAccountTesting.h new file mode 100644 index 00000000..37565454 --- /dev/null +++ b/keychain/securityd/Regressions/SOSAccountTesting.h @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef SEC_SOSAccountTesting_h +#define SEC_SOSAccountTesting_h + +#include +#include "keychain/SecureObjectSync/SOSAccountPriv.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" +#include +#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" + +#include "SOSTestDataSource.h" +#include "SOSRegressionUtilities.h" + +#include "SOSTransportTestTransports.h" +#include "testmore.h" +#include +// +// Implicit transaction helpers +// + +static inline bool SOSAccountResetToOffering_wTxn(SOSAccount* acct, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); + if (!user_key) + return; + result = [acct.trust resetToOffering:txn key:user_key err:error]; + }]; + return result; +} + +static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccount* acct, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountJoinCirclesAfterRestore(txn, error); + }]; + return result; +} + +static inline bool SOSAccountJoinCircles_wTxn(SOSAccount* acct, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountJoinCircles(txn, error); + }]; + return result; +} + +static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccount* account) +{ + return SOSAccountHasCompletedInitialSync(account); +} + +static inline void SOSAccountPeerGotInSync_wTxn(SOSAccount* acct, SOSPeerInfoRef peer) +{ + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + CFMutableSetRef views = SOSPeerInfoCopyEnabledViews(peer); + SOSAccountPeerGotInSync(txn, SOSPeerInfoGetPeerID(peer), views); + CFReleaseNull(views); + }]; +} + +static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccount* acct, CFDataRef backupKey, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountSetBackupPublicKey(txn, backupKey, error); + }]; + return result; +} + +static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccount* acct, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountRemoveBackupPublickey(txn, error); + }]; + return result; +} + +static inline SOSViewResultCode SOSAccountUpdateView_wTxn(SOSAccount* acct, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error) { + __block SOSViewResultCode result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = [acct.trust updateView:acct name:viewname code:actionCode err:error]; + }]; + return result; +} + +// +// Account comparison +// + +#define kAccountsAgreeTestMin 9 +#define kAccountsAgreeTestPerPeer 1 +#define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x)) + +static void SOSAccountResetToTest(SOSAccount* a, CFStringRef accountName) { + SOSUnregisterTransportKeyParameter(a.key_transport); + SOSUnregisterTransportCircle((SOSCircleStorageTransport*)a.circle_transport); + SOSUnregisterTransportMessage((SOSMessage*)a.kvs_message_transport); + + if(key_transports) + CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(a.key_transport)); + if(message_transports){ + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)a.kvs_message_transport); + } + if(circle_transports) + CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)a.circle_transport); + + a.circle_transport = nil; + a.key_transport = nil; + a.kvs_message_transport = nil; + + SOSAccountEnsureFactoryCirclesTest(a, accountName); +} + + +static SOSAccount* SOSAccountCreateBasicTest(CFAllocatorRef allocator, + CFStringRef accountName, + CFDictionaryRef gestalt, + SOSDataSourceFactoryRef factory) { + SOSAccount* a; + a = SOSAccountCreate(kCFAllocatorDefault, gestalt, factory); + + return a; +} + +static SOSAccount* SOSAccountCreateTest(CFAllocatorRef allocator, + CFStringRef accountName, + CFDictionaryRef gestalt, + SOSDataSourceFactoryRef factory) { + SOSAccount* a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory); + + SOSAccountResetToTest(a, accountName); + if(a) + SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); + return a; +} + +static SOSAccount* SOSAccountCreateTestFromData(CFAllocatorRef allocator, + CFDataRef data, + CFStringRef accountName, + SOSDataSourceFactoryRef factory) { + SOSAccount* a = [SOSAccount accountFromData:(__bridge NSData*) data + factory:factory + error:nil]; + if (!a) { + CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(accountName); + a = SOSAccountCreate(allocator, gestalt, factory); + CFReleaseNull(gestalt); + } + + SOSAccountResetToTest(a, accountName); + if(a) + SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); + + return a; +} + + +static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccount* account, + CFStringRef user_account, CFDataRef user_password, + CFErrorRef *error) +{ + bool success = false; + success = SOSAccountAssertUserCredentials(account, user_account, user_password, error); + require_quiet(success, done); + + success = SOSAccountGenerationSignatureUpdate(account, error); + +done: + return success; +} + + + +static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFSetRef allowed_peers) +{ + CFArrayForEach(peers, ^(const void *value) { + SOSPeerInfoRef pi = (SOSPeerInfoRef) value; + + CFErrorRef leftError = NULL; + CFErrorRef rightError = NULL; + + ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFSetContainsValue(allowed_peers, pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers); + + CFReleaseNull(leftError); + CFReleaseNull(rightError); + }); +} + +static void accounts_agree_internal(char *label, SOSAccount* left, SOSAccount* right, bool check_peers) +{ + CFErrorRef error = NULL; + { + CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error); + ok(leftPeers, "Left peers (%@) - %s", error, label); + CFReleaseNull(error); + + CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error); + ok(rightPeers, "Right peers (%@) - %s", error, label); + CFReleaseNull(error); + + ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers); + + if (check_peers) { + CFMutableSetRef allowed_identities = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + + SOSFullPeerInfoRef leftFullPeer = [left.trust CopyAccountIdentityPeerInfo]; + + if (leftFullPeer) + CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(leftFullPeer)); + CFReleaseNull(leftFullPeer); + + SOSFullPeerInfoRef rightFullPeer = [right.trust CopyAccountIdentityPeerInfo]; + + if (rightFullPeer) + CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(rightFullPeer)); + CFReleaseNull(rightFullPeer); + + unretired_peers_is_subset(label, leftPeers, allowed_identities); + + CFReleaseNull(allowed_identities); + } + + CFReleaseNull(leftPeers); + CFReleaseNull(rightPeers); + } + { + CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error); + ok(leftConcurringPeers, "Left peers (%@) - %s", error, label); + + CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error); + ok(rightConcurringPeers, "Right peers (%@) - %s", error, label); + + ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers); + + CFReleaseNull(leftConcurringPeers); + CFReleaseNull(rightConcurringPeers); + } + { + CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error); + ok(leftApplicants, "Left Applicants (%@) - %s", error, label); + + CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error); + ok(rightApplicants, "Left Applicants (%@) - %s", error, label); + + ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants); + + CFReleaseNull(leftApplicants); + CFReleaseNull(rightApplicants); + } +} + +static inline void accounts_agree(char *label, SOSAccount* left, SOSAccount* right) +{ + accounts_agree_internal(label, left, right, true); +} + + +// +// Change handling +// + +static inline CFStringRef CFArrayCopyCompactDescription(CFArrayRef array) { + if (!isArray(array)) + return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), array); + + CFMutableStringRef result = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + + __block CFStringRef separator = CFSTR(""); + CFArrayForEach(array, ^(const void *value) { + CFStringAppendFormat(result, NULL, CFSTR("%@%@"), separator, value); + separator = CFSTR(","); + }); + + CFStringAppend(result, CFSTR("]")); + + CFReleaseSafe(separator); + + return result; +} + +static inline CFStringRef SOSAccountCopyName(SOSAccount* account) { + SOSPeerInfoRef pi = account.peerInfo; + + return pi ? CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerName(pi)) : CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%@"), account); +} + +static inline CFStringRef CopyChangesDescription(CFDictionaryRef changes) { + + CFStringRef pendingChanges = CFDictionaryCopyCompactDescription((CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull)); + + CFMutableStringRef peerTable = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + + __block CFStringRef separator = CFSTR(""); + + CFDictionaryForEach(changes, ^(const void *key, const void *value) { + if (CFGetTypeID(key) == SOSAccountGetTypeID()) { + CFStringRef accountName = SOSAccountCopyName((__bridge SOSAccount*)key); + CFStringRef arrayDescription = CFArrayCopyCompactDescription(value); + + CFStringAppendFormat(peerTable, NULL, CFSTR("%@%@:%@"), separator, accountName, arrayDescription); + separator = CFSTR(", "); + + CFReleaseSafe(accountName); + CFReleaseSafe(arrayDescription); + } + }); + + CFStringAppend(peerTable, CFSTR("]")); + + CFStringRef result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), pendingChanges, peerTable); + CFReleaseNull(pendingChanges); + CFReleaseNull(peerTable); + + return result; +}; + +static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFMutableDictionaryRef overlay) { + CFMutableSetRef keysToRemove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryForEach(overlay, ^(const void *key, const void *value) { + const void *current_value = CFDictionaryGetValue(target, key); + if (CFEqualSafe(current_value, value) || (isNull(value) && current_value == NULL)) { + CFSetAddValue(keysToRemove, key); + } else { + CFDictionarySetValue(target, key, value); + } + }); + + CFSetForEach(keysToRemove, ^(const void *value) { + CFDictionaryRemoveValue(overlay, value); + }); + + CFReleaseNull(keysToRemove); +} + +static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) { + CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) { + CFArrayAppendValue(keys, key); + }); +} + +static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccount* sender) +{ + __block bool changes_added = false; + CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary); + CFReleaseNull(emptyDictionary); + + CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues); + + CFDictionaryForEach(changesRecord, ^(const void *key, const void *value) { + if (isArray(value) && (sender == NULL || sender != key)) { + CFArrayAppendKeys((CFMutableArrayRef) value, newKeysAndValues); + if (CFDictionaryGetCount(newKeysAndValues)) + changes_added = true; + } + }); + + if (changes_added) + secnotice("changes", "Changes from %@: %@", sender, newKeysAndValues); + + CFDictionaryRemoveAllValues(newKeysAndValues); + + return changes_added; +} + +static bool FillAllChanges(CFMutableDictionaryRef changes) { + __block bool changed = false; + + CFMutableSetRef changedAccounts = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); + + CFArrayForEach(key_transports, ^(const void *value) { + CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; + if (AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt))) { + changed |= true; + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt))); + } + SOSTransportKeyParameterTestClearChanges(tpt); + }); + CFArrayForEach(circle_transports, ^(const void *value) { + SOSCircleStorageTransportTest *tpt = (__bridge SOSCircleStorageTransportTest *) value; + if (AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], [tpt getAccount])) { + changed |= true; + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)SOSTransportCircleTestGetAccount(tpt)); + } + SOSTransportCircleTestClearChanges(tpt); + }); + CFArrayForEach(message_transports, ^(const void *value) { + if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ + SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; + CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); + if (AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt))) { + changed |= true; + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt))); + } + SOSTransportMessageTestClearChanges(tpt); + } + }); + + secnotice("process-changes", "Accounts with change (%@): %@", changed ? CFSTR("YES") : CFSTR("NO"), changedAccounts); + + CFReleaseNull(changedAccounts); + + return changed; +} + +static void FillChanges(CFMutableDictionaryRef changes, SOSAccount* forAccount) +{ + CFArrayForEach(key_transports, ^(const void *value) { + CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; + if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt)))){ + AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt)); + SOSTransportKeyParameterTestClearChanges(tpt); + } + }); + CFArrayForEach(circle_transports, ^(const void *value) { + SOSCircleStorageTransportTest* tpt = (__bridge SOSCircleStorageTransportTest*) value; + if([forAccount isEqual: SOSTransportCircleTestGetAccount(tpt)]){ + AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], SOSTransportCircleTestGetAccount(tpt)); + SOSTransportCircleTestClearChanges(tpt); + } + }); + CFArrayForEach(message_transports, ^(const void *value) { + if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ + SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; + if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt)))){ + CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); + AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt)); + SOSTransportMessageTestClearChanges(tpt); + } + } + }); + +} + +static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccount* account, ...) +{ + SOSAccount* next_account = account; + va_list argp; + va_start(argp, account); + while(next_account != NULL) { + FillChanges(changes, next_account); + next_account = va_arg(argp, SOSAccount*); + } +} + +static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary) +{ + CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + CFArrayAppendKeys(result, dictionary); + + return result; +} + +#define kFeedChangesToTestCount 1 +static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccount* acct) +{ + CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull); + + if (!isDictionary(full_list)) + return; // Nothing recorded to send! + + CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, (__bridge CFTypeRef)(acct)); + + if (!isArray(account_pending_keys)) { + account_pending_keys = CFDictionaryCopyKeys(full_list); + CFDictionaryAddValue(changes, (__bridge CFTypeRef)(acct), account_pending_keys); + CFReleaseSafe(account_pending_keys); // The dictionary keeps it, we don't retain it here. + } + + CFMutableDictionaryRef account_pending_messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayForEach(account_pending_keys, ^(const void *value) { + CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value)); + }); + + secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((CKKeyParameterTest*) acct.key_transport)); + + CFDictionaryForEach(account_pending_messages, ^(const void *key, const void *value) { + secnotice("changes", " %@", key); + }); + + if(CFDictionaryGetCount(account_pending_messages) == 0) { + CFReleaseNull(account_pending_messages); + return; + } + + __block CFMutableArrayRef handled = NULL; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + __block CFErrorRef error = NULL; + ok(handled = SOSTransportDispatchMessages(txn, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error); + CFReleaseNull(error); + }]; + + if (isArray(handled)) { + CFArrayForEach(handled, ^(const void *value) { + CFArrayRemoveAllValue(account_pending_keys, value); + }); + } + CFReleaseNull(account_pending_messages); + CFReleaseNull(handled); +} + +#define kFeedChangesToMultieTestCountPer 1 + +static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp) +{ + SOSAccount* account = NULL; + while((account = va_arg(argp, SOSAccount*)) != NULL) { + FeedChangesTo(changes, account); + } +} + +static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...) +{ + va_list argp; + va_start(argp, changes); + + FeedChangesToMultiV(changes, argp); + + va_end(argp); +} + +static inline void InjectChangeToMulti(CFMutableDictionaryRef changes, + CFStringRef changeKey, CFTypeRef changeValue, ...) +{ + CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + changeKey, changeValue, + NULL); + AddNewChanges(changes, changes_to_send, NULL); + CFReleaseNull(changes_to_send); + + va_list argp; + va_start(argp, changeValue); + FeedChangesToMultiV(changes, argp); + va_end(argp); +} + +static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp) +{ + bool result = FillAllChanges(changes); + + FeedChangesToMultiV(changes, argp); + + return result; +} + + +static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...) +{ + va_list argp; + va_start(argp, changes); + + bool result = ProcessChangesOnceV(changes, argp); + + va_end(argp); + + return result; +} + +static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...) +{ + va_list argp; + va_start(argp, changes); + + int result = 0; + bool new_data = false; + do { + va_list argp_copy; + va_copy(argp_copy, argp); + + new_data = ProcessChangesOnceV(changes, argp_copy); + + ++result; + + va_end(argp_copy); + } while (new_data); + + va_end(argp); + + return result; + +} + +// +// MARK: Account creation +// + +static CFStringRef modelFromType(SOSPeerInfoDeviceClass cls) { + switch(cls) { + case SOSPeerInfo_macOS: return CFSTR("Mac Pro"); + case SOSPeerInfo_iOS: return CFSTR("iPhone"); + case SOSPeerInfo_iCloud: return CFSTR("iCloud"); + case SOSPeerInfo_watchOS: return CFSTR("needWatchOSDeviceName"); + case SOSPeerInfo_tvOS: return CFSTR("needTVOSDeviceName"); + default: return CFSTR("GENERICOSTHING"); + } +} + +static inline SOSAccount* CreateAccountForLocalChangesWithStartingAttributes(CFStringRef name, CFStringRef data_source_name, SOSPeerInfoDeviceClass devclass, CFStringRef serial, CFBooleanRef preferIDS, CFBooleanRef preferIDSFragmentation, CFBooleanRef preferIDSACKModel, CFStringRef transportType, CFStringRef deviceID) { + + SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef ds = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds); + SOSEngineRef engine = SOSEngineCreate(ds, NULL); + ds->engine = engine; + + CFMutableDictionaryRef gestalt = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(gestalt, kPIUserDefinedDeviceNameKey, name); + CFDictionaryAddValue(gestalt, kPIDeviceModelNameKey, modelFromType(devclass)); + CFDictionaryAddValue(gestalt, kPIOSVersionKey, CFSTR("TESTRUN")); + + CFMutableDictionaryRef testV2dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(testV2dict, sSerialNumberKey, serial); + SOSAccount* result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory); + [result.trust updateV2Dictionary:result v2:testV2dict]; + + CFReleaseSafe(SOSAccountCopyUUID(result)); + + CFReleaseNull(gestalt); + CFReleaseNull(testV2dict); + + return result; +} + +static CFStringRef sGestaltTest = CFSTR("GestaltTest"); +static CFStringRef sV2Test = CFSTR("V2Test"); +static inline CFDictionaryRef SOSTestSaveStaticAccountState(SOSAccount* account) { + CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef gestalt = SOSAccountCopyGestalt(account); + CFDictionaryRef v2dictionary = SOSAccountCopyV2Dictionary(account); + CFDictionaryAddValue(retval, sGestaltTest, gestalt); + CFDictionaryAddValue(retval, sV2Test, v2dictionary); + CFReleaseNull(gestalt); + CFReleaseNull(v2dictionary); + return retval; +} + +static inline void SOSTestRestoreAccountState(SOSAccount* account, CFDictionaryRef saved) { + [account.trust updateGestalt:account newGestalt:CFDictionaryGetValue(saved, sGestaltTest)]; + [account.trust updateV2Dictionary:account v2:CFDictionaryGetValue(saved, sV2Test)]; +} + +static CFStringRef CFStringCreateRandomHexWithLength(size_t len) { + if(len%2) len++; + CFDataRef data = CFDataCreateWithRandomBytes(len/2); + CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, len); + CFStringAppendHexData(retval, data); + CFReleaseNull(data); + return retval; +} + +static inline SOSAccount* CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name) +{ + CFStringRef randomSerial = CFStringCreateRandomHexWithLength(8); + CFStringRef randomDevID = CFStringCreateRandomHexWithLength(16); + SOSAccount* retval = CreateAccountForLocalChangesWithStartingAttributes(name, data_source_name, SOSPeerInfo_iOS, randomSerial, + kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeKVS, randomDevID); + + CFReleaseNull(randomSerial); + CFReleaseNull(randomDevID); + return retval; +} + +static inline SOSAccount* CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name) +{ + SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef ds = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds); + SOSEngineRef engine = SOSEngineCreate(ds, NULL); + ds->engine = engine; + + SOSAccount* result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory); + + return result; +} + + + +static inline int countPeers(SOSAccount* account) { + CFErrorRef error = NULL; + CFArrayRef peers; + + peers = SOSAccountCopyPeers(account, &error); + if(!peers) + return 0; + int retval = (int) CFArrayGetCount(peers); + CFReleaseNull(error); + CFReleaseNull(peers); + return retval; +} + +static inline int countActivePeers(SOSAccount* account) { + CFErrorRef error = NULL; + CFArrayRef peers; + + peers = SOSAccountCopyActivePeers(account, &error); + if(!peers) + return 0; + int retval = (int) CFArrayGetCount(peers); + CFReleaseNull(error); + CFReleaseNull(peers); + return retval; +} + +static inline int countActiveValidPeers(SOSAccount* account) { + CFErrorRef error = NULL; + CFArrayRef peers; + + peers = SOSAccountCopyActiveValidPeers(account, &error); + if(!peers) + return 0; + int retval = (int) CFArrayGetCount(peers); + CFReleaseNull(error); + CFReleaseNull(peers); + return retval; +} + +static inline int countApplicants(SOSAccount* account) { + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + int retval = 0; + + if(applicants) retval = (int)CFArrayGetCount(applicants); + CFReleaseNull(error); + CFReleaseNull(applicants); + return retval; +} + + +static inline void showActiveValidPeers(SOSAccount* account) { + CFErrorRef error = NULL; + CFArrayRef peers; + + peers = SOSAccountCopyActiveValidPeers(account, &error); + CFArrayForEach(peers, ^(const void *value) { + SOSPeerInfoRef pi = (SOSPeerInfoRef) value; + ok(0, "Active Valid Peer %@", pi); + }); + CFReleaseNull(peers); +} + +#define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL + +static inline bool testAccountPersistence(SOSAccount* account) { + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); + NSError* error = nil; + + bool retval = false; + SOSAccount* reinflatedAccount = NULL; + NSData* accountDER = NULL; + + SOSAccountCheckHasBeenInSync_wTxn(account); + + // DER encode account to accountData - this allows checking discreet DER functions + size_t size = [account.trust getDEREncodedSize:account err:&error]; + error = nil; + uint8_t buffer[size]; + uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; + error = nil; + + ok_or_quit(start, "successful encoding", errOut); + ok_or_quit(start == buffer, "Used whole buffer", errOut); + + accountDER = [NSData dataWithBytes:buffer length:size]; + ok_or_quit(accountDER, "Made CFData for Account", errOut); + + + // Re-inflate to "inflated" + reinflatedAccount = [SOSAccount accountFromData:accountDER + factory:test_factory + error:&error]; + error = nil; + + ok(reinflatedAccount, "inflated"); + ok(CFEqualSafe((__bridge CFTypeRef)reinflatedAccount, (__bridge CFTypeRef)account), "Compares"); + + // Repeat through SOSAccountCopyEncodedData() interface - this is the normally called combined interface + accountDER = [account encodedData:&error]; + error = nil; + reinflatedAccount = [SOSAccount accountFromData:accountDER factory:test_factory error:&error]; + ok(reinflatedAccount, "inflated2: %@", error); + ok(CFEqual((__bridge CFTypeRef)account, (__bridge CFTypeRef)reinflatedAccount), "Compares"); + + error = nil; + retval = true; + +errOut: + return retval; +} + +static inline bool SOSTestStartCircleWithAccount(SOSAccount* account, CFMutableDictionaryRef changes, CFStringRef cfaccount, CFDataRef cfpassword) { + bool retval = false; + if(!SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, NULL)) + return retval; + is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); + if(!SOSAccountResetToOffering_wTxn(account, NULL)) + return retval; + is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); + retval = true; + + return retval; +} + +static inline bool SOSTestApproveRequest(SOSAccount* approver, CFIndex napplicants) { + bool retval = false; + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(approver, &error); + + ok(applicants && CFArrayGetCount(applicants) == napplicants, "See %ld applicant(s) %@ (%@)", napplicants, applicants, error); + CFStringRef approvername = SOSAccountCopyName(approver); + ok((retval = SOSAccountAcceptApplicants(approver, applicants, &error)), "%@ accepts (%@)", approvername, error); + CFReleaseNull(error); + CFReleaseNull(applicants); + CFReleaseNull(approvername); + + return retval; +} + +#define DROP_USERKEY true +#define KEEP_USERKEY false + +static inline bool SOSTestJoinWith(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* joiner) { + CFErrorRef error = NULL; + // retval will return op failures, not count failures - we'll still report those from in here. + bool retval = false; + + FeedChangesTo(changes, joiner); + + ok(SOSAccountAssertUserCredentialsAndUpdate(joiner, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ProcessChangesUntilNoChange(changes, joiner, NULL); + + ok(retval = SOSAccountJoinCircles_wTxn(joiner, &error), "Applying (%@)", error); + CFReleaseNull(error); + return retval; +} + +static inline bool SOSTestJoinWithApproval(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* approver, SOSAccount* joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { + //CFErrorRef error = NULL; + // retval will return op failures, not count failures - we'll still report those from in here. + bool retval = false; + + ok(retval = SOSTestJoinWith(cfpassword, cfaccount, changes, joiner), "Application Made"); + + ProcessChangesUntilNoChange(changes, approver, joiner, NULL); + + int nrounds = 2; + if(dropUserKey) SOSAccountPurgePrivateCredential(joiner); // lose the userKey so we don't "fix" the ghost problem yet. + else nrounds = 3; + + if(expectCleanup) nrounds++; + + ok(retval &= SOSTestApproveRequest(approver, 1), "Accepting Request to Join"); + ProcessChangesUntilNoChange(changes, approver, joiner, NULL); + + accounts_agree_internal("Successful join shows same circle view", joiner, approver, false); + is(countPeers(joiner), expectedCount, "There should be %d valid peers", expectedCount); + return retval; +} + + +static inline bool SOSTestChangeAccountDeviceName(SOSAccount* account, CFStringRef name) { + bool retval = false; + CFMutableDictionaryRef mygestalt = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerGetGestalt(account.peerInfo)); + require_quiet(mygestalt, retOut); + CFDictionarySetValue(mygestalt, kPIUserDefinedDeviceNameKey, name); + retval = [account.trust updateGestalt:account newGestalt:mygestalt]; +retOut: + CFReleaseNull(mygestalt); + return retval; +} + +/* + * this simulates a piggy-back join at the account level + */ + +static inline bool SOSTestJoinThroughPiggyBack(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* approver, SOSAccount* joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { + // retval will return op failures, not count failures - we'll still report those from in here. + bool retval = false; + CFErrorRef error = NULL; + + ok(SOSAccountAssertUserCredentialsAndUpdate(approver, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + // This makes sure the joiner sees the current key parameters + ProcessChangesUntilNoChange(changes, approver, joiner, NULL); + + SecKeyRef privKey = SOSAccountGetPrivateCredential(approver, &error); + ok(privKey, "got privkey from approver (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountTryUserPrivateKey(joiner, privKey, &error), "assert same credentials on joiner (%@)", error); + CFReleaseNull(error); + // This gives the joiner a chance to see the current circle - this is the account-level equivalent of the Flush added to stashAccountCredential + ProcessChangesUntilNoChange(changes, approver, joiner, NULL); + + SOSPeerInfoRef joinerPI = SOSAccountCopyApplication(joiner, &error); + ok(joinerPI, "Joiner peerinfo available as application %@", error); + CFReleaseNull(error); + + CFDataRef theBlob = SOSAccountCopyCircleJoiningBlob(approver, joinerPI, &error); + ok(theBlob, "Made a joining blob (%@)", error); + CFReleaseNull(error); + + + bool joined = SOSAccountJoinWithCircleJoiningBlob(joiner, theBlob, kPiggyV1, &error); + ok(joined, "Joiner posted circle with itself in it (%@)", error); + CFReleaseNull(error); + + CFReleaseNull(joinerPI); + CFReleaseNull(theBlob); + + is(ProcessChangesUntilNoChange(changes, approver, joiner, NULL), 2, "updates"); + + ok((retval = [joiner isInCircle:NULL]), "Joiner is in"); + + accounts_agree_internal("Successful join shows same circle view", joiner, approver, false); + is(countPeers(joiner), expectedCount, "There should be %d valid peers", expectedCount); + return retval; +} + + +static inline SOSAccount* SOSTestCreateAccountAsSerialClone(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID) { + return CreateAccountForLocalChangesWithStartingAttributes(name, CFSTR("TestSource"), devClass, serial, kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeKVS, idsID); +} + +static inline bool SOSTestMakeGhostInCircle(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID, + CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, + SOSAccount* approver, int expectedCount) { + bool retval = false; + SOSAccount* ghostAccount = SOSTestCreateAccountAsSerialClone(name, devClass, serial, idsID); + ok(ghostAccount, "Created Ghost Account"); + require_quiet(ghostAccount, retOut); + if(!ghostAccount) return false; + ok(retval = SOSTestJoinWithApproval(cfpassword, cfaccount, changes, approver, ghostAccount, DROP_USERKEY, expectedCount, true), "Ghost Joined Circle with expected result"); +retOut: + return retval; +} + +static inline void SOSTestCleanup() { + SOSUnregisterAllTransportMessages(); + SOSUnregisterAllTransportCircles(); + SOSUnregisterAllTransportKeyParameters(); + CFArrayRemoveAllValues(key_transports); + CFArrayRemoveAllValues(circle_transports); + CFArrayRemoveAllValues(message_transports); +} + + +#endif diff --git a/keychain/securityd/Regressions/SOSTransportTestTransports.h b/keychain/securityd/Regressions/SOSTransportTestTransports.h new file mode 100644 index 00000000..e702ad6f --- /dev/null +++ b/keychain/securityd/Regressions/SOSTransportTestTransports.h @@ -0,0 +1,69 @@ +#ifndef SEC_SOSTransportTestTransports_h +#define SEC_SOSTransportTestTransports_h + +#import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" +#import "keychain/SecureObjectSync/SOSTransportMessageKVS.h" + +extern CFMutableArrayRef key_transports; +extern CFMutableArrayRef circle_transports; +extern CFMutableArrayRef message_transports; + +void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt); + +@interface CKKeyParameterTest : CKKeyParameter + +@property (nonatomic) CFMutableDictionaryRef changes; +@property (nonatomic) CFStringRef name; +@property (nonatomic) CFStringRef circleName; +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error; +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameter*) transport data:(CFDataRef) data err:(CFErrorRef) error; + +@end + +@interface SOSMessageKVSTest : SOSMessageKVS +@property (nonatomic) CFMutableDictionaryRef changes; +@property (nonatomic) CFStringRef name; + +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; +-(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error; +-(CFIndex) SOSTransportMessageGetTransportType; +-(CFStringRef) SOSTransportMessageGetCircleName; +-(CFTypeRef) SOSTransportMessageGetEngine; +-(SOSAccount*) SOSTransportMessageGetAccount; +@end + +@interface SOSCircleStorageTransportTest : SOSKVSCircleStorageTransport +{ + NSString *accountName; +} +@property (nonatomic) NSString *accountName; + +-(id) init; +-(id) initWithAccount:(SOSAccount*)account andWithAccountName:(CFStringRef)accountName andCircleName:(CFStringRef)circleName; + +bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error); +CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport); +bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName); +SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport); +void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport); +void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef accountName); +bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error); +-(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates; +-(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef)message_data; +-(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges; +@end + +void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport); + +void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n); +CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport); +CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport); + +CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport); +CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport); +void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName); +void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport); +SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport); +SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport); +#endif diff --git a/keychain/securityd/Regressions/SOSTransportTestTransports.m b/keychain/securityd/Regressions/SOSTransportTestTransports.m new file mode 100644 index 00000000..e354c55f --- /dev/null +++ b/keychain/securityd/Regressions/SOSTransportTestTransports.m @@ -0,0 +1,587 @@ +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include "keychain/SecureObjectSync/SOSAccountPriv.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#import "keychain/SecureObjectSync/SOSTransportKeyParameter.h" +#import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" +#import "keychain/SecureObjectSync/SOSTransportMessageKVS.h" +#include "keychain/SecureObjectSync/SOSKVSKeys.h" +#include "keychain/SecureObjectSync/SOSPeerCoder.h" +#include +#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" + +#include "SOSTransportTestTransports.h" +#include "SOSAccountTesting.h" + +CFMutableArrayRef key_transports = NULL; +CFMutableArrayRef circle_transports = NULL; +CFMutableArrayRef message_transports = NULL; + +/// +//Mark Test Key Parameter Transport +/// + +@implementation CKKeyParameterTest + +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN +{ + self = [super init]; + if(self){ + self.name = CFRetainSafe(n); + self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + self.account = acct; + self.circleName = CFRetainSafe(cN); + + if(!key_transports) + key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(key_transports, (__bridge CFTypeRef)((CKKeyParameter*)self)); + + SOSRegisterTransportKeyParameter((CKKeyParameter*)self); + } + return self; +} + +-(void)dealloc { + if(self) { + CFReleaseNull(self->_changes); + CFReleaseNull(self->_circleName); + } +} + +- (void)setChanges:(CFMutableDictionaryRef)changes +{ + CFRetainAssign(self->_changes, changes); +} + +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameterTest*) transport data:(CFDataRef) data err:(CFErrorRef) error +{ + SOSAccount* acct = transport.account; + return SOSAccountHandleParametersChange(acct, data, &error); +} + + +-(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameterTest*) transport acct:(SOSAccount*) acct +{ + + if(key_transports){ + CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(acct.key_transport)); + } + if(message_transports){ + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.kvs_message_transport); + } + if(circle_transports) + CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)(acct.circle_transport)); + + SOSAccountSetToNew(acct); + SOSAccountResetToTest(acct, transport.name); +} + +CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport){ + return transport.name; +} + +void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName){ + transport.name = accountName; +} + +SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport){ + return ((CKKeyParameter*)transport).account; +} + +CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport){ + return transport.changes; +} + +void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport){ + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error +{ + if(!transport.changes) + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionarySetValue(transport.changes, kSOSKVSKeyParametersKey, newParameters); + + return true; +} +@end + + +/// +//MARK: Test Circle Transport +/// +@implementation SOSCircleStorageTransportTest +@synthesize accountName = accountName; + +-(id)init +{ + return [super init]; +} + +CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport){ + return (__bridge CFStringRef)(transport.accountName); +} +void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef name){ + transport.accountName = nil; + transport.accountName = (__bridge NSString *)(name); +} + +-(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges +{ + return (__bridge CFMutableDictionaryRef)(self.pending_changes); +} + +void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport){ + transport.pending_changes = [NSMutableDictionary dictionary]; +} + +-(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName +{ + self = [super init]; + if(self){ + self.account = acct; + self.accountName = (__bridge NSString *)(acctName); + self.circleName = (__bridge NSString*)cName; + self.pending_changes = [NSMutableDictionary dictionary]; + if(!circle_transports) + circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(circle_transports, (__bridge CFTypeRef)self); + + SOSRegisterTransportCircle((SOSCircleStorageTransportTest*)self); + } + return self; +} + +-(bool) kvsRingFlushChanges:(CFErrorRef*) error +{ + return true; +} + +-(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error +{ + CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); + CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; + CFDictionaryAddValue(changes, ringKey, ring); + CFReleaseNull(ringKey); + return true; +} + +-(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error +{ + CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; + CFDictionaryAddValue(changes, type, debugInfo); + return true; +} + +-(bool) postRetirement:(CFStringRef)cName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error +{ + CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(cName, SOSPeerInfoGetPeerID(peer)); + CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error); + + if (retirement_key) + [self testAddToChanges:retirement_key data:retirement_data]; + + CFReleaseNull(retirement_key); + CFReleaseNull(retirement_data); + return true; +} + +-(bool) flushChanges:(CFErrorRef *)error +{ + return true; +} + +-(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef) message_data +{ + if (self.pending_changes == NULL) { + self.pending_changes = [NSMutableDictionary dictionary]; + } + if (message_data == NULL) { + [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)(message_key)]; + } else { + [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key]; + } + secnotice("circle-changes", "Adding circle change %@ %@->%@", self.accountName, message_key, message_data); +} + +-(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates +{ + if (self.pending_changes == NULL) { + self.pending_changes = [[NSMutableDictionary alloc]initWithDictionary:(__bridge NSDictionary * _Nonnull)(updates)]; + + } + else{ + CFDictionaryForEach(updates, ^(const void *key, const void *value) { + [self.pending_changes setObject:(__bridge id _Nonnull)value forKey:(__bridge id _Nonnull)key]; + }); + } +} + + +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error +{ + bool success = true; + CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryForEach(retirements, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef retirees = (CFArrayRef) value; + + CFArrayForEach(retirees, ^(const void *value) { + if (isString(value)) { + CFStringRef retiree_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); + + CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); + + CFReleaseSafe(kvsKey); + } + }); + } + }); + + if(CFDictionaryGetCount(keysToWrite)) { + [self SOSTransportCircleTestAddBulkToChanges:keysToWrite]; + } + CFReleaseNull(keysToWrite); + + return success; +} + +bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error){ + CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); + if (circle_key) + [transport.pending_changes removeObjectForKey:(__bridge NSString*)circle_key]; + CFReleaseNull(circle_key); + return true; +} + +-(bool) postCircle:(CFStringRef)cName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error +{ + CFStringRef circle_key = SOSCircleKeyCreateWithName(cName, error); + if (circle_key) + [self testAddToChanges:circle_key data:circle_data]; + CFReleaseNull(circle_key); + + return true; +} + +-(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error +{ + return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error); +} + +-(CFArrayRef)CF_RETURNS_RETAINED handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error +{ +CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { + CFErrorRef circleMessageError = NULL; + if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) { + secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); + } + else{ + CFStringRef circle_id = (CFStringRef) key; + CFArrayAppendValue(handledKeys, circle_id); + } + CFReleaseNull(circleMessageError); + }); + + return handledKeys; +} + +SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport) { + return transport.account; +} + +@end + +/// +//MARK KVS Message Test Transport +/// + + + +@implementation SOSMessageKVSTest + + +-(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN +{ + self = [super init]; + if(self){ + self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL); + self.account = acct; + self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + self.name = CFRetainSafe(n); + self.circleName = (__bridge NSString*)cN; + + if(!message_transports) + message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(message_transports, (__bridge const void *)((SOSMessageKVSTest*)self)); + SOSRegisterTransportMessage((SOSMessageKVSTest*)self); + } + + return self; +} + +- (void)setChanges:(CFMutableDictionaryRef)changes +{ + CFRetainAssign(self->_changes, changes); +} + +-(CFIndex) SOSTransportMessageGetTransportType +{ + return kKVSTest; +} +-(CFStringRef) SOSTransportMessageGetCircleName +{ + return (__bridge CFStringRef)circleName; +} +-(CFTypeRef) SOSTransportMessageGetEngine +{ + return engine; +} +-(SOSAccount*) SOSTransportMessageGetAccount +{ + return self.account; +} + +void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n) +{ + transport.name = n; +} + +CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport) +{ + return transport.name; +} + +CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport) +{ + return transport.changes; +} + +void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport) +{ + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +static void SOSTransportMessageTestAddBulkToChanges(SOSMessageKVSTest* transport, CFDictionaryRef updates) +{ +#ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why. + if (transport.changes == NULL) { + transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); + } + else{ + CFDictionaryForEach(updates, ^(const void *key, const void *value) { + CFDictionarySetValue(transport.changes, key, value); + }); + } +#endif // __clang_analyzer__ +} + +static void SOSTransportMessageTestAddToChanges(SOSMessageKVSTest* transport, CFStringRef message_key, CFDataRef message_data) +{ + if (transport.changes == NULL) { + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + } + if (message_data == NULL) { + CFDictionarySetValue(transport.changes, message_key, kCFNull); + } else { + CFDictionarySetValue(transport.changes, message_key, message_data); + } +} + +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageKVSTest*) transport peers:(CFDictionaryRef)circle_to_peer_ids err:(CFErrorRef*) error +{ + if(!transport.engine) + return true; + CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)transport.engine); + + CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; + + CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { + if (isString(value)) { + CFStringRef cleanup_id = (CFStringRef) value; + // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers + if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { + if (isString(value)) { + CFStringRef in_circle_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); + SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + + kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); + SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + } + }); + + } + }); + } + }); + + return [transport SOSTransportMessageFlushChanges:transport err:error]; + return true; +} + +static bool sendToPeer(SOSMessageKVSTest* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { + bool result = true; + NSString* myID = transport.account.peerID; + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSMessage*)transport, (__bridge CFStringRef) myID, peerID); + CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); + + SOSTransportMessageTestAddBulkToChanges(transport, a_message_to_a_peer); + CFReleaseNull(a_message_to_a_peer); + CFReleaseNull(message_to_peer_key); + + return result; +} + +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessageKVSTest*) transport p:(CFSetRef) peers err:(CFErrorRef *)error +{ + // Each entry is keyed by circle name and contains a list of peerIDs + + __block bool result = true; + + CFSetForEach(peers, ^(const void *value) { + CFStringRef peerID = asString(value, NULL); + + if (peerID) { + SOSEngineWithPeerID((SOSEngineRef)transport.engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + SOSEnginePeerMessageSentCallback* sentCallback = NULL; + CFDataRef message_to_send = NULL; + bool ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peerID, false, &sentCallback, error); + if (message_to_send) { + CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL); + CFDictionarySetValue(SOSTransportMessageKVSTestGetChanges(transport), (__bridge CFStringRef)self->circleName, peer_dict); + SOSEngineMessageCallCallback(sentCallback, ok); + CFReleaseSafe(peer_dict); + } + + SOSEngineFreeMessageCallback(sentCallback); + CFReleaseSafe(message_to_send); + }); + } + }); + return result; +} + +-(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ + __block bool result = true; + + CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { + if (isString(key) && isData(value)) { + CFStringRef peerID = (CFStringRef) key; + CFDataRef message = (CFDataRef) value; + bool rx = sendToPeer(transport, (__bridge CFStringRef)transport->circleName, peerID, message, error); + result &= rx; + } + }); + + return result; +} + +-(bool) SOSTransportMessageFlushChanges:(SOSMessageKVSTest*) transport err:(CFErrorRef *)error +{ + return true; +} + +SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport) { + return transport.account; +} +@end + + +void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt){ + CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey); + + SOSTransportKeyParameterTestSetName((CKKeyParameterTest*)account.key_transport, new_name); + SOSTransportCircleTestSetName((SOSCircleStorageTransportTest*)account.circle_transport, new_name); + SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name); +} + +static CF_RETURNS_RETAINED SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName) +{ + CFErrorRef localError = NULL; + SOSAccountTrustClassic *trust = a.trust; + + SOSCircleRef circle = CFRetainSafe([a.trust getCircle:&localError]); + if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){ + secnotice("circle", "Error retrieving the circle: %@", localError); + CFReleaseNull(localError); + CFReleaseNull(circle); + + circle = SOSCircleCreate(kCFAllocatorDefault, name, &localError); + if (circle){ + [trust setTrustedCircle:circle]; + } + else{ + secnotice("circle", "Could not create circle: %@", localError); + } + CFReleaseNull(localError); + } + + if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError]) + { + secnotice("circle", "had an error building full peer: %@", localError); + CFReleaseNull(localError); + return circle; + } + + CFReleaseNull(localError); + return circle; +} + +bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName) +{ + bool result = false; + if (a) + { + if(!a.factory) + return result; + CFStringRef circle_name = SOSDataSourceFactoryCopyName(a.factory); + if(!circle_name) + return result; + CFReleaseSafe(SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName)); + + CFReleaseNull(circle_name); + result = true; + } + return result; +} + +bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){ + bool success = false; + + if(account.key_transport == nil){ + account.key_transport = (CKKeyParameter*)[[CKKeyParameterTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; + require_quiet(account.key_transport, fail); + } + + if(account.circle_transport == nil){ + account.circle_transport = (SOSKVSCircleStorageTransport*)[[SOSCircleStorageTransportTest alloc] initWithAccount:account andWithAccountName:accountName andCircleName:circleName]; + require_quiet(account.circle_transport, fail); + } + if(account.kvs_message_transport == nil){ + account.kvs_message_transport = (SOSMessageKVS*)[[SOSMessageKVSTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; + } + + success = true; +fail: + return success; +} + + diff --git a/keychain/securityd/Regressions/SecdTestKeychainUtilities.c b/keychain/securityd/Regressions/SecdTestKeychainUtilities.c new file mode 100644 index 00000000..b5700649 --- /dev/null +++ b/keychain/securityd/Regressions/SecdTestKeychainUtilities.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "SecdTestKeychainUtilities.h" + +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include + + +#include + +//#include +#include +#include +#include + +void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_in_reset) +{ + CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random()); + CFStringRef keychain_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@Library/Keychains"), tmp_dir); + + CFStringPerformWithCString(keychain_dir, ^(const char *keychain_dir_string) { + errno_t err = mkpath_np(keychain_dir_string, 0755); + ok(err == 0 || err == EEXIST, "Create temp dir %s (%d)", keychain_dir_string, err); + }); + + + /* set custom keychain dir, reset db */ + SetCustomHomeURLString(tmp_dir); + + SecKeychainDbReset(do_in_reset); + + CFReleaseNull(tmp_dir); + CFReleaseNull(keychain_dir); +} + +CFStringRef kTestView1 = CFSTR("TestView1"); +CFStringRef kTestView2 = CFSTR("TestView2"); + +void secd_test_setup_testviews(void) { + CFMutableSetRef testViews = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(testViews, kTestView1); + CFSetAddValue(testViews, kTestView2); + + SOSViewsSetTestViewsSet(testViews); + CFReleaseNull(testViews); +} + +void secd_test_clear_testviews(void) { + SOSViewsSetTestViewsSet(NULL); +} + + diff --git a/keychain/securityd/Regressions/SecdTestKeychainUtilities.h b/keychain/securityd/Regressions/SecdTestKeychainUtilities.h new file mode 100644 index 00000000..e11ed683 --- /dev/null +++ b/keychain/securityd/Regressions/SecdTestKeychainUtilities.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef _SECDTESTKEYCHAINUTILITIES_ +#define _SECDTESTKEYCHAINUTILITIES_ + +#include +#include + +#define kSecdTestSetupTestCount 1 +void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_before_reset); + +extern CFStringRef kTestView1; +extern CFStringRef kTestView2; + +void secd_test_setup_testviews(void); +void secd_test_clear_testviews(void); + +#endif diff --git a/keychain/securityd/Regressions/ios6_1_keychain_2_db.h b/keychain/securityd/Regressions/ios6_1_keychain_2_db.h new file mode 100644 index 00000000..a4eec207 --- /dev/null +++ b/keychain/securityd/Regressions/ios6_1_keychain_2_db.h @@ -0,0 +1,10586 @@ +unsigned char ios6_1_keychain_2_db[] = { + 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x20, 0x33, 0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x40, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, + 0x00, 0x2d, 0xe2, 0x25, 0x0d, 0x0f, 0xfc, 0x00, 0x17, 0x04, 0x99, 0x00, + 0x0e, 0x72, 0x0f, 0xd3, 0x0e, 0x20, 0x0b, 0xed, 0x0d, 0xf7, 0x0a, 0x89, + 0x0b, 0xc4, 0x07, 0xa8, 0x0a, 0x60, 0x07, 0x64, 0x07, 0x2d, 0x06, 0xf6, + 0x06, 0xbf, 0x06, 0x88, 0x06, 0x51, 0x06, 0x1a, 0x05, 0xe3, 0x05, 0xac, + 0x05, 0x75, 0x05, 0x3e, 0x05, 0x07, 0x04, 0xd0, 0x04, 0x99, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x35, 0x17, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x18, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, + 0x20, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, + 0x79, 0x73, 0x28, 0x75, 0x6e, 0x77, 0x70, 0x29, 0x35, 0x16, 0x06, 0x17, + 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x77, 0x72, + 0x61, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x17, 0x43, 0x52, 0x45, 0x41, 0x54, + 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x77, 0x72, 0x61, + 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x77, 0x72, + 0x61, 0x70, 0x29, 0x35, 0x15, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x69, 0x76, 0x72, 0x66, 0x79, 0x6b, 0x65, 0x79, + 0x73, 0x16, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, + 0x45, 0x58, 0x20, 0x69, 0x76, 0x72, 0x66, 0x79, 0x20, 0x4f, 0x4e, 0x20, + 0x6b, 0x65, 0x79, 0x73, 0x28, 0x76, 0x72, 0x66, 0x79, 0x29, 0x35, 0x14, + 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, + 0x73, 0x69, 0x67, 0x6e, 0x6b, 0x65, 0x79, 0x73, 0x15, 0x43, 0x52, 0x45, + 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, + 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, + 0x73, 0x69, 0x67, 0x6e, 0x29, 0x35, 0x13, 0x06, 0x17, 0x17, 0x15, 0x01, + 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, 0x72, 0x76, 0x65, 0x6b, + 0x65, 0x79, 0x73, 0x14, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, + 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x72, 0x76, 0x65, 0x20, 0x4f, + 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, 0x72, 0x76, 0x65, 0x29, + 0x35, 0x12, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x69, 0x64, 0x65, 0x63, 0x72, 0x6b, 0x65, 0x79, 0x73, 0x13, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, + 0x69, 0x64, 0x65, 0x63, 0x72, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, + 0x73, 0x28, 0x64, 0x65, 0x63, 0x72, 0x29, 0x35, 0x11, 0x06, 0x17, 0x17, + 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x65, 0x6e, 0x63, + 0x72, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x65, 0x6e, 0x63, 0x72, + 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x65, 0x6e, 0x63, + 0x72, 0x29, 0x35, 0x10, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x6b, 0x65, 0x79, 0x73, + 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, + 0x58, 0x20, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x4f, 0x4e, 0x20, 0x6b, + 0x65, 0x79, 0x73, 0x28, 0x6b, 0x6c, 0x62, 0x6c, 0x29, 0x35, 0x0f, 0x06, + 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x6b, + 0x63, 0x6c, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x10, 0x43, 0x52, 0x45, 0x41, + 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x6b, 0x63, + 0x6c, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6b, + 0x63, 0x6c, 0x73, 0x29, 0x35, 0x0e, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x70, 0x6b, 0x68, 0x68, 0x63, 0x65, + 0x72, 0x74, 0x0f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, + 0x44, 0x45, 0x58, 0x20, 0x69, 0x70, 0x6b, 0x68, 0x68, 0x20, 0x4f, 0x4e, + 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x70, 0x6b, 0x68, 0x68, 0x29, 0x35, + 0x0d, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x69, 0x73, 0x6b, 0x69, 0x64, 0x63, 0x65, 0x72, 0x74, 0x0e, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, + 0x73, 0x6b, 0x69, 0x64, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x28, 0x73, 0x6b, 0x69, 0x64, 0x29, 0x35, 0x0c, 0x06, 0x17, 0x17, 0x15, + 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x73, 0x75, 0x62, 0x6a, + 0x63, 0x65, 0x72, 0x74, 0x0d, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, + 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, 0x75, 0x62, 0x6a, 0x20, + 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x75, 0x62, 0x6a, + 0x29, 0x35, 0x0b, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x63, 0x65, 0x72, 0x74, 0x0c, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, + 0x20, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x28, 0x61, 0x6c, 0x69, 0x73, 0x29, 0x42, 0x0a, 0x06, 0x17, + 0x1d, 0x1d, 0x01, 0x59, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x0b, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, + 0x4c, 0x45, 0x20, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x28, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x29, 0x85, 0x35, 0x08, 0x07, 0x17, 0x15, 0x15, 0x01, + 0x8a, 0x4d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x6b, + 0x65, 0x79, 0x73, 0x09, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, + 0x41, 0x42, 0x4c, 0x45, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x72, 0x6f, + 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, + 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, + 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, + 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, + 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6b, 0x63, + 0x6c, 0x73, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, + 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, + 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, + 0x42, 0x2c, 0x70, 0x65, 0x72, 0x6d, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x2c, 0x70, 0x72, 0x69, 0x76, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x2c, 0x6d, 0x6f, 0x64, 0x69, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x61, + 0x74, 0x61, 0x67, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, + 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x20, 0x27, 0x27, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, + 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, + 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x62, 0x73, 0x69, + 0x7a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, + 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, + 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, + 0x2c, 0x73, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, 0x4e, + 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, + 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x20, 0x52, + 0x45, 0x41, 0x4c, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, + 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, + 0x65, 0x6e, 0x73, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x61, 0x73, 0x65, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x2c, 0x65, 0x78, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x2c, 0x6e, 0x65, 0x78, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x2c, 0x65, 0x6e, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x2c, 0x64, 0x65, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x64, 0x72, 0x76, 0x65, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x72, 0x66, 0x79, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x6e, 0x72, 0x63, + 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x79, 0x72, + 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x77, 0x72, + 0x61, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x75, + 0x6e, 0x77, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, + 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, + 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, + 0x28, 0x6b, 0x63, 0x6c, 0x73, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x2c, 0x61, + 0x74, 0x61, 0x67, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x2c, 0x74, 0x79, 0x70, + 0x65, 0x2c, 0x62, 0x73, 0x69, 0x7a, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x2c, + 0x73, 0x64, 0x61, 0x74, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x2c, 0x61, 0x67, + 0x72, 0x70, 0x29, 0x29, 0x27, 0x09, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, + 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6b, 0x65, + 0x79, 0x73, 0x5f, 0x31, 0x6b, 0x65, 0x79, 0x73, 0x0a, 0x82, 0x38, 0x06, + 0x07, 0x17, 0x15, 0x15, 0x01, 0x84, 0x53, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x63, 0x65, 0x72, 0x74, 0x63, 0x65, 0x72, 0x74, 0x07, 0x43, 0x52, 0x45, + 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, + 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, + 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, + 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, + 0x41, 0x4c, 0x2c, 0x63, 0x74, 0x79, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, + 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x63, + 0x65, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, + 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x73, 0x75, 0x62, 0x6a, + 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x73, 0x73, 0x72, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, + 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, + 0x73, 0x6c, 0x6e, 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, + 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x6b, 0x69, 0x64, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x6b, 0x68, 0x68, 0x20, 0x42, 0x4c, 0x4f, + 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, + 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, + 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, + 0x55, 0x45, 0x28, 0x63, 0x74, 0x79, 0x70, 0x2c, 0x69, 0x73, 0x73, 0x72, + 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, + 0x27, 0x07, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x31, + 0x63, 0x65, 0x72, 0x74, 0x08, 0x84, 0x07, 0x04, 0x07, 0x17, 0x15, 0x15, + 0x01, 0x87, 0x71, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x74, + 0x69, 0x6e, 0x65, 0x74, 0x05, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, + 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x28, 0x72, + 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, + 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, + 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, + 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, + 0x65, 0x73, 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, + 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, + 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, + 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, + 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, + 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, + 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, + 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, + 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, + 0x2c, 0x73, 0x64, 0x6d, 0x6e, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, + 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, + 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, + 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, + 0x2c, 0x70, 0x74, 0x63, 0x6c, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x61, 0x74, 0x79, + 0x70, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x27, 0x27, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, + 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x70, + 0x61, 0x74, 0x68, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, + 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x20, 0x27, 0x27, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, + 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, + 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, + 0x64, 0x6d, 0x6e, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x2c, 0x70, 0x74, 0x63, + 0x6c, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x2c, + 0x70, 0x61, 0x74, 0x68, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, 0x27, + 0x05, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x65, 0x74, 0x5f, 0x31, 0x69, + 0x6e, 0x65, 0x74, 0x06, 0x50, 0x03, 0x06, 0x17, 0x2b, 0x2b, 0x01, 0x59, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x71, 0x6c, 0x69, + 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x04, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, + 0x20, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x73, 0x65, + 0x71, 0x29, 0x82, 0x5e, 0x01, 0x07, 0x17, 0x15, 0x15, 0x01, 0x85, 0x1f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x67, 0x65, 0x6e, 0x70, 0x67, 0x65, 0x6e, + 0x70, 0x02, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, + 0x4c, 0x45, 0x20, 0x67, 0x65, 0x6e, 0x70, 0x28, 0x72, 0x6f, 0x77, 0x69, + 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, + 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, + 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, + 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, + 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, 0x65, 0x73, 0x63, + 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, 0x74, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, 0x70, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, 0x42, 0x4c, 0x4f, + 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x76, + 0x63, 0x65, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, + 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, + 0x20, 0x27, 0x27, 0x2c, 0x67, 0x65, 0x6e, 0x61, 0x20, 0x42, 0x4c, 0x4f, + 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, + 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, + 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x55, 0x4e, 0x49, 0x51, + 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, 0x76, 0x63, 0x65, + 0x2c, 0x61, 0x67, 0x72, 0x70, 0x29, 0x29, 0x27, 0x02, 0x06, 0x17, 0x3b, + 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, + 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x5f, 0x67, 0x65, 0x6e, 0x70, 0x5f, 0x31, 0x67, 0x65, 0x6e, 0x70, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xfb, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x0f, 0xfb, 0x0f, 0xf6, 0x04, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x55, 0x07, + 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, + 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, + 0xaa, 0x7a, 0x0b, 0x66, 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, + 0x95, 0x22, 0xa7, 0xe3, 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, + 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, + 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, + 0x7c, 0xa5, 0xb2, 0x07, 0xf2, 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, + 0xc7, 0x85, 0xd2, 0x16, 0x2f, 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, + 0xbd, 0x3d, 0xd9, 0xc4, 0x98, 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, + 0x20, 0x7b, 0x97, 0xca, 0xe6, 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, + 0xc9, 0x46, 0x27, 0xd4, 0x4f, 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, + 0x3c, 0x4e, 0x8e, 0x37, 0x6e, 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, + 0x17, 0xdb, 0xd1, 0x96, 0xb9, 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, + 0xbf, 0x42, 0x46, 0xfc, 0x1c, 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, + 0x4c, 0x84, 0xde, 0x41, 0x9f, 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, + 0x9c, 0x59, 0xd6, 0xcf, 0xcd, 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, + 0x3b, 0x02, 0xcc, 0x1a, 0xed, 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, + 0x39, 0xa5, 0x82, 0x12, 0x04, 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, + 0xc0, 0x8d, 0xdb, 0xff, 0x46, 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, + 0x5e, 0xc1, 0xa3, 0xca, 0xd4, 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, + 0x22, 0xbf, 0xf6, 0x5a, 0xe6, 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, + 0xba, 0x8b, 0xd2, 0x39, 0x49, 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, + 0xdc, 0x0d, 0x73, 0x1b, 0xe6, 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, + 0x4b, 0x79, 0x8c, 0x23, 0x8d, 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, + 0x3f, 0x09, 0xec, 0xf3, 0xa8, 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, + 0x37, 0xc0, 0x2a, 0x7d, 0x25, 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, + 0x14, 0xd0, 0xa8, 0x1e, 0x2a, 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, + 0xa3, 0xb2, 0xee, 0x83, 0x36, 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, + 0x64, 0xb4, 0x07, 0x7c, 0x3d, 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, + 0x91, 0xf4, 0x32, 0xa8, 0xf1, 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, + 0x78, 0xca, 0xa4, 0x0c, 0xf8, 0x40, 0x9f, 0x86, 0xd9, 0x16, 0x56, 0x67, + 0x74, 0xd4, 0x33, 0x9e, 0xb7, 0xef, 0xa6, 0xdf, 0x32, 0xb2, 0x24, 0x20, + 0xe7, 0xe9, 0x80, 0xdf, 0x7b, 0xa3, 0x49, 0x04, 0xd7, 0x3f, 0x9f, 0xbe, + 0xa6, 0x2d, 0xd0, 0xec, 0xed, 0x04, 0x76, 0xc9, 0x38, 0x0b, 0x2c, 0x02, + 0xcc, 0xd0, 0x98, 0x02, 0x73, 0x96, 0x6b, 0x8b, 0xcb, 0x2b, 0x57, 0x2d, + 0xab, 0x0d, 0x5e, 0x97, 0xb8, 0xd9, 0x81, 0xa6, 0x09, 0x7c, 0x6a, 0x6a, + 0xbe, 0xed, 0x44, 0xe1, 0x87, 0x2a, 0xbd, 0xad, 0x61, 0xfa, 0xdc, 0x76, + 0xaa, 0xa5, 0xfd, 0x40, 0xee, 0x9f, 0xf1, 0xc6, 0x74, 0xe9, 0xba, 0xc1, + 0xaf, 0xf1, 0x5d, 0x16, 0x06, 0x27, 0x60, 0x2b, 0x96, 0x9d, 0x0d, 0xc1, + 0x7c, 0xc3, 0x7b, 0xfd, 0x33, 0xc2, 0xa6, 0x7c, 0xbc, 0xc3, 0x1c, 0xef, + 0x9d, 0xf4, 0xe2, 0x8c, 0x2d, 0xe3, 0x01, 0xc1, 0x95, 0x24, 0x66, 0x15, + 0x1a, 0xa1, 0xa0, 0x61, 0x28, 0x8f, 0x44, 0x77, 0x80, 0xfc, 0x11, 0xce, + 0xad, 0xe1, 0xf1, 0xe9, 0x80, 0x55, 0x6d, 0x77, 0x5d, 0xf7, 0x2a, 0xf8, + 0x15, 0x42, 0xdd, 0xf6, 0x62, 0xac, 0x68, 0x8f, 0xaa, 0x85, 0xd8, 0xfa, + 0xc6, 0x21, 0xe9, 0xa8, 0xa2, 0x1e, 0xe3, 0xd4, 0x32, 0x3e, 0xee, 0xec, + 0x96, 0x54, 0xe1, 0xb1, 0x8f, 0x64, 0x59, 0xc6, 0x49, 0x01, 0x3c, 0xc0, + 0x17, 0xa9, 0xf5, 0xf2, 0x6f, 0x8a, 0xec, 0x9b, 0x66, 0xa7, 0x1d, 0x98, + 0xff, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x84, 0x07, 0x06, + 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x86, 0x46, 0x17, 0x13, 0x41, 0xb7, + 0x59, 0x5c, 0x54, 0xdd, 0xc7, 0x58, 0x41, 0xb7, 0x59, 0x5c, 0x54, 0xdd, + 0xc7, 0x58, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, + 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, 0x0e, + 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, 0x36, + 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x1c, 0x32, 0x04, 0xe7, 0x79, 0xe1, + 0xe0, 0x05, 0x0b, 0xa0, 0xe7, 0xb9, 0xe1, 0x92, 0xbb, 0xa8, 0xae, 0xca, + 0xff, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x99, 0x02, 0x2d, 0xc5, 0xee, 0x94, 0x76, 0x6c, 0x0a, 0xe2, + 0xa1, 0xb1, 0x7a, 0x6d, 0x0c, 0xbf, 0x9d, 0xa2, 0x60, 0xdc, 0xb9, 0xf4, + 0xf9, 0x4e, 0x6f, 0x61, 0x37, 0x18, 0x86, 0xbf, 0xef, 0xe9, 0x55, 0x9e, + 0x44, 0x75, 0x32, 0x4c, 0x20, 0x82, 0xb5, 0x3d, 0x42, 0x72, 0x35, 0x69, + 0xba, 0x22, 0x95, 0x0c, 0xec, 0x46, 0xe8, 0x5b, 0x62, 0xe2, 0x07, 0xd4, + 0x80, 0x99, 0xc1, 0x83, 0x12, 0x3f, 0xcc, 0xd4, 0xf6, 0xcd, 0xc2, 0xb2, + 0xcd, 0x4d, 0x94, 0x4c, 0xab, 0x05, 0x48, 0x0c, 0x09, 0xe1, 0x82, 0x1a, + 0x6c, 0x0a, 0xf5, 0x16, 0x06, 0x57, 0x23, 0x9e, 0x18, 0xe8, 0xd9, 0xbb, + 0x4a, 0x8a, 0xcd, 0x69, 0xed, 0xc3, 0xae, 0x71, 0xe8, 0x8f, 0xeb, 0xb5, + 0x76, 0x50, 0xca, 0xb5, 0x69, 0x05, 0xdc, 0x93, 0x5b, 0x49, 0xed, 0xa3, + 0xf8, 0x25, 0xfe, 0x6a, 0x83, 0x6f, 0x16, 0x1e, 0xef, 0x5b, 0xfd, 0x24, + 0x7f, 0x9f, 0x66, 0xf1, 0x65, 0x8c, 0x38, 0x43, 0xd1, 0xbc, 0x13, 0x14, + 0x45, 0x75, 0x66, 0x3b, 0xd7, 0xe1, 0x7a, 0xde, 0xb1, 0xf6, 0x27, 0xd6, + 0x3e, 0xf6, 0x44, 0x7d, 0xf3, 0x3e, 0xd2, 0x95, 0x49, 0xe5, 0x31, 0x6f, + 0x38, 0x95, 0xd0, 0x78, 0xc8, 0xca, 0x68, 0xaf, 0xec, 0xab, 0x1e, 0xcf, + 0x0c, 0xff, 0x3e, 0xc4, 0x12, 0x3e, 0x48, 0xb4, 0x7e, 0x70, 0xc6, 0xa0, + 0x9b, 0xf8, 0x80, 0x30, 0x75, 0x25, 0x1a, 0xf1, 0xdf, 0x3a, 0x37, 0xa1, + 0xac, 0x43, 0x5b, 0xa0, 0xae, 0x9b, 0x91, 0xb3, 0x4a, 0xfa, 0x5f, 0x4b, + 0xf1, 0xba, 0xcd, 0x41, 0x92, 0x38, 0x6a, 0x8d, 0x69, 0x9e, 0xd3, 0x09, + 0xaa, 0x4c, 0xb2, 0x60, 0xcf, 0xff, 0x37, 0xed, 0xa0, 0x39, 0x36, 0x03, + 0x1a, 0x6a, 0xb7, 0xed, 0xce, 0xc8, 0x4e, 0x46, 0xb1, 0x82, 0xfb, 0xe1, + 0x46, 0x2d, 0x12, 0xf4, 0x8a, 0x6c, 0x38, 0x5c, 0x6b, 0xaa, 0x05, 0xf1, + 0xc0, 0xf2, 0x14, 0x8d, 0x3e, 0xdc, 0xec, 0x04, 0x0c, 0x94, 0xe3, 0xbf, + 0x3b, 0x7b, 0x3f, 0xa2, 0x88, 0x98, 0xe6, 0x0c, 0x5f, 0x23, 0x6d, 0x0b, + 0x6f, 0x8e, 0xe9, 0xce, 0xc0, 0xe2, 0x3e, 0xc7, 0xcd, 0xa0, 0x7b, 0xda, + 0xf1, 0x26, 0xfd, 0x3d, 0xc6, 0xe7, 0xe8, 0xed, 0x9d, 0xeb, 0x74, 0xc5, + 0x14, 0x5c, 0xee, 0xcd, 0x4d, 0xc4, 0x4e, 0x1b, 0x2d, 0x09, 0xf4, 0x7b, + 0xdb, 0xf6, 0x96, 0x17, 0x17, 0xd1, 0x16, 0xd5, 0xea, 0xaf, 0x4f, 0x7b, + 0xc2, 0x1e, 0x0f, 0xe1, 0x2c, 0xd8, 0x26, 0xe1, 0xcc, 0x66, 0x64, 0xd1, + 0x3f, 0xd9, 0x16, 0x99, 0x0c, 0xb1, 0x11, 0xc2, 0x13, 0xe5, 0xab, 0x99, + 0x2a, 0x6f, 0x09, 0x37, 0xc5, 0x7c, 0x8e, 0xb8, 0x04, 0x73, 0x3b, 0x0b, + 0x58, 0x87, 0x10, 0x33, 0x1f, 0x5d, 0xea, 0xe9, 0xcd, 0x4e, 0x5b, 0x33, + 0x88, 0xc2, 0x9c, 0x01, 0x1a, 0xe6, 0x92, 0x57, 0xf9, 0xa8, 0x7d, 0x03, + 0x76, 0x79, 0x4e, 0x1e, 0x25, 0xe8, 0xae, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x64, 0x6b, 0x75, 0x83, 0x0b, 0x05, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, + 0x84, 0x3c, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, 0x6b, + 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, 0x6b, 0x65, 0x6d, 0xb0, 0x14, + 0x83, 0xdf, 0x17, 0xb6, 0x73, 0x59, 0x09, 0xd6, 0x8a, 0xed, 0x02, 0x13, + 0x5a, 0x8b, 0xd4, 0x99, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, + 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, 0x59, 0x31, 0xba, 0xaa, 0x89, + 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xdc, 0x97, 0xef, 0xa5, + 0xc0, 0xbc, 0x15, 0x38, 0x95, 0x35, 0x74, 0x61, 0x34, 0x68, 0xb9, 0x5c, + 0xef, 0x21, 0xad, 0xeb, 0xc9, 0x50, 0x73, 0xed, 0x31, 0x38, 0x33, 0x44, + 0x03, 0x44, 0x16, 0xaf, 0xa2, 0xba, 0x34, 0x58, 0x3f, 0x49, 0xaf, 0x93, + 0xf8, 0xe4, 0x6e, 0x6f, 0x7f, 0x23, 0x05, 0x46, 0x75, 0x49, 0xdf, 0x84, + 0xad, 0x64, 0x83, 0x11, 0x43, 0xd9, 0x80, 0x11, 0x93, 0x6d, 0xcf, 0xb4, + 0x72, 0x42, 0xc2, 0x5a, 0x78, 0x57, 0x37, 0x2d, 0x9e, 0x9a, 0x3e, 0x30, + 0x9b, 0x72, 0x7b, 0xfa, 0x1d, 0x9e, 0x2d, 0x53, 0x16, 0x85, 0x91, 0x3c, + 0xe9, 0xf1, 0x39, 0x60, 0x1d, 0x9e, 0xc6, 0xee, 0xb1, 0xdc, 0xb1, 0x0d, + 0xb8, 0x23, 0x68, 0xbf, 0xe5, 0x08, 0xc4, 0xac, 0x31, 0x4e, 0x2d, 0x0f, + 0x1f, 0xe1, 0xb3, 0xfe, 0xd2, 0x31, 0x4a, 0x52, 0x3e, 0x03, 0xe1, 0x1a, + 0x66, 0x58, 0x8b, 0x56, 0x99, 0x55, 0x7f, 0x6f, 0x5a, 0xa9, 0x8f, 0xcf, + 0xb3, 0x03, 0x96, 0x79, 0xb0, 0x6c, 0x67, 0x60, 0x35, 0xce, 0x8d, 0xc6, + 0x1c, 0x70, 0x05, 0xa4, 0x5e, 0x4f, 0x83, 0x4f, 0x1a, 0x98, 0x88, 0xdd, + 0x5a, 0x5d, 0xb3, 0x9b, 0xf6, 0xb2, 0xa3, 0x2e, 0x1c, 0x41, 0x81, 0x97, + 0xef, 0x16, 0xb3, 0x8e, 0xbe, 0x09, 0x08, 0x3d, 0x47, 0xaa, 0x2b, 0x90, + 0x61, 0xc7, 0x67, 0xcb, 0x0d, 0xa5, 0x7a, 0x58, 0x4d, 0xa7, 0x9f, 0xd4, + 0x21, 0xf2, 0x47, 0x65, 0x3b, 0x9e, 0x3b, 0xa4, 0xb4, 0x15, 0x05, 0x10, + 0xee, 0x90, 0xe5, 0xd9, 0x2e, 0xa0, 0xfe, 0x85, 0x9c, 0xad, 0x37, 0x71, + 0x51, 0xba, 0x0e, 0x91, 0x48, 0x3e, 0x54, 0xa0, 0x10, 0x1b, 0xc7, 0xff, + 0x4b, 0xd2, 0x24, 0xf8, 0x37, 0xd9, 0xc3, 0x17, 0x12, 0x05, 0x28, 0xbe, + 0xeb, 0xf5, 0xa3, 0x5a, 0x93, 0x7b, 0x9e, 0x59, 0xb2, 0x63, 0xbc, 0x71, + 0x61, 0x6a, 0x5a, 0x6c, 0xbd, 0xae, 0xeb, 0xff, 0x2a, 0x53, 0xf3, 0x44, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x73, 0x64, 0x64, 0x6b, 0x75, 0x00, 0x00, 0x01, 0x87, 0x00, 0x07, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, + 0x34, 0x34, 0x84, 0x40, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x51, 0x13, 0x75, + 0xf7, 0x83, 0x41, 0xb7, 0x59, 0x51, 0x13, 0x75, 0xf7, 0x83, 0x8e, 0xc3, + 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, 0x69, 0x08, 0x28, 0x2f, + 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, 0x0e, 0x4d, 0x78, 0x41, 0x89, + 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, 0x36, 0x7b, 0xf9, 0xc7, 0xb9, + 0x71, 0xe5, 0xce, 0x65, 0x7a, 0x52, 0xa0, 0x52, 0xa3, 0xaa, 0xf5, 0x34, + 0xec, 0xfb, 0xf7, 0xcb, 0xdd, 0xe4, 0xee, 0x33, 0x4c, 0x10, 0x02, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xc9, 0xa4, + 0xb0, 0xbb, 0x30, 0xa3, 0x3d, 0x27, 0x05, 0x4f, 0x4c, 0x5e, 0x1f, 0x82, + 0x66, 0x8e, 0x02, 0x48, 0x36, 0x3c, 0x6b, 0xa3, 0x16, 0x82, 0x0c, 0x12, + 0x58, 0xe2, 0xb6, 0x5f, 0xe3, 0x0a, 0x20, 0xfd, 0xad, 0xa0, 0xc7, 0x99, + 0x65, 0x78, 0xfe, 0x99, 0xa5, 0xac, 0x48, 0x47, 0x0e, 0x2d, 0xc3, 0x76, + 0x76, 0xcb, 0xca, 0x9b, 0xb7, 0xe5, 0x3b, 0x4a, 0xca, 0x8a, 0xb6, 0x6f, + 0x22, 0x08, 0xcb, 0xb4, 0xc6, 0xf6, 0xba, 0x30, 0x52, 0x57, 0x1b, 0x09, + 0xc8, 0x9a, 0x3e, 0xde, 0x73, 0x81, 0xde, 0xb7, 0xc2, 0x2d, 0x46, 0xc9, + 0x52, 0x9f, 0x4b, 0xef, 0x2c, 0x2f, 0x5c, 0xa3, 0x10, 0x98, 0x0d, 0x57, + 0x0b, 0x4c, 0xc5, 0xeb, 0x49, 0x49, 0x7f, 0xae, 0xc3, 0x45, 0xbe, 0x0a, + 0x7d, 0x37, 0x94, 0xc4, 0xfe, 0x53, 0xdf, 0x10, 0x55, 0x98, 0xf9, 0x68, + 0x2a, 0xf7, 0x42, 0x48, 0x6b, 0xa7, 0x5b, 0x3d, 0xa3, 0x9f, 0xed, 0xf2, + 0x70, 0xcb, 0x64, 0x74, 0xa8, 0xfa, 0xdc, 0xe4, 0x5e, 0x90, 0x6f, 0x79, + 0x18, 0x19, 0xc8, 0xbf, 0xf3, 0x78, 0xd9, 0x35, 0x07, 0x42, 0x5f, 0xc6, + 0x04, 0x09, 0x62, 0x1f, 0xa4, 0xe2, 0x67, 0x06, 0x46, 0x47, 0xac, 0x53, + 0x7d, 0x0e, 0xbb, 0xd7, 0xbd, 0x51, 0x00, 0x60, 0x44, 0xa9, 0x47, 0x60, + 0xd5, 0x7f, 0xc4, 0x45, 0xdb, 0xd5, 0x42, 0xbe, 0x8e, 0x5d, 0x89, 0xbd, + 0xb4, 0xe7, 0x6e, 0xdf, 0xcc, 0x21, 0x10, 0x2c, 0x8d, 0xe8, 0x6e, 0x2c, + 0xb8, 0x72, 0x0e, 0x86, 0xe9, 0xd4, 0x08, 0x93, 0xf3, 0xb3, 0x2a, 0x00, + 0xa0, 0xe2, 0x1f, 0xc4, 0x09, 0x3b, 0x75, 0x81, 0x99, 0x17, 0x5b, 0x78, + 0x27, 0x32, 0x6d, 0x0b, 0x29, 0x31, 0x51, 0x70, 0x50, 0x95, 0x0c, 0x94, + 0x90, 0xba, 0x18, 0x17, 0x44, 0x6b, 0xd8, 0x50, 0x58, 0xe8, 0xe2, 0xff, + 0x80, 0xb9, 0x44, 0xfe, 0x1b, 0x8f, 0xdf, 0xa1, 0x91, 0xeb, 0x57, 0x86, + 0xd0, 0x61, 0x1a, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, + 0x84, 0x43, 0x02, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, 0x66, 0x17, + 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x41, 0xb7, 0x59, + 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x77, 0xac, 0x86, 0x8b, 0xf9, 0xb8, 0xa0, + 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, 0xe2, 0x63, 0x81, 0xf6, 0x85, 0xbc, + 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, + 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf6, 0xbc, 0x81, + 0x5b, 0x23, 0x66, 0x44, 0x13, 0x27, 0xcf, 0x98, 0xc2, 0xc0, 0x31, 0x38, + 0x98, 0xec, 0x01, 0x84, 0xbb, 0x38, 0xb1, 0x79, 0xd7, 0x91, 0x66, 0x5a, + 0x56, 0x22, 0x62, 0x6f, 0xb8, 0xf0, 0x68, 0x00, 0xe7, 0x1a, 0x7a, 0x93, + 0xfc, 0xa8, 0xd4, 0xd9, 0xaf, 0x21, 0x17, 0x71, 0xf3, 0x0c, 0xd6, 0x22, + 0x2f, 0xb0, 0xb7, 0xc3, 0x1e, 0x07, 0xe7, 0x53, 0x34, 0xc9, 0x17, 0x9d, + 0xe8, 0xd3, 0x07, 0x78, 0xe7, 0x74, 0xcd, 0xf0, 0xdd, 0x88, 0x0d, 0x30, + 0x9b, 0x3c, 0x78, 0xfb, 0x43, 0xb7, 0x4f, 0x79, 0xd1, 0x83, 0xcd, 0x56, + 0x60, 0xe7, 0x7e, 0x8d, 0xba, 0x61, 0x9d, 0x4f, 0xf2, 0x71, 0x9b, 0xbd, + 0x11, 0xfc, 0x82, 0x8f, 0xc2, 0x9b, 0x32, 0xb7, 0x4d, 0x5d, 0x93, 0x87, + 0x11, 0x7d, 0xbf, 0x3a, 0x06, 0x11, 0x15, 0xf5, 0x97, 0xf4, 0x03, 0x24, + 0x6a, 0xfb, 0x5e, 0x27, 0x2b, 0xb5, 0xac, 0x20, 0x84, 0xe8, 0x8d, 0x67, + 0xa9, 0xf5, 0x41, 0x8a, 0xbd, 0xea, 0x51, 0x91, 0x30, 0xd7, 0xf2, 0x81, + 0x12, 0xbc, 0x24, 0x61, 0x25, 0x58, 0x9e, 0x4a, 0x4c, 0x89, 0xa4, 0x19, + 0xf1, 0x12, 0xe2, 0x33, 0xf1, 0x37, 0x1f, 0x0f, 0xa0, 0x42, 0xa1, 0x0e, + 0xa2, 0xc4, 0x06, 0xb0, 0xba, 0x61, 0xef, 0xc5, 0x6b, 0x46, 0x33, 0x62, + 0x50, 0xe0, 0xe4, 0x2e, 0x74, 0x20, 0xf4, 0x54, 0xbb, 0xed, 0xa0, 0x73, + 0x51, 0xa5, 0xc6, 0x55, 0x90, 0x61, 0xe9, 0x9c, 0x76, 0x72, 0x21, 0xa9, + 0x19, 0x1a, 0xbd, 0xcf, 0x61, 0x29, 0x8a, 0xef, 0xdd, 0xe0, 0xc6, 0x0a, + 0xf0, 0xd8, 0x50, 0xb9, 0xe9, 0x92, 0x7d, 0xf3, 0xce, 0x7e, 0x9e, 0xcf, + 0x32, 0x92, 0xc7, 0x49, 0x59, 0x23, 0xb5, 0x4e, 0xf2, 0x71, 0xf0, 0xda, + 0xb3, 0x80, 0xe3, 0xb6, 0x7a, 0xe4, 0x14, 0x80, 0x25, 0x3e, 0xd0, 0x89, + 0x13, 0xf4, 0x70, 0x96, 0xee, 0xbe, 0xef, 0x31, 0x61, 0xa1, 0x8d, 0xf7, + 0x9a, 0x5c, 0x92, 0x0a, 0x9b, 0x1f, 0x8c, 0x5e, 0x3d, 0x37, 0x24, 0xc2, + 0x8d, 0x21, 0xe9, 0x47, 0x2e, 0x03, 0xee, 0x32, 0xbf, 0x46, 0xc7, 0x2c, + 0x6e, 0x7a, 0x81, 0x9e, 0x14, 0xb8, 0xbe, 0xdb, 0x22, 0x4f, 0xf1, 0x8d, + 0x47, 0x41, 0x84, 0xc9, 0xeb, 0x4f, 0xe9, 0xf4, 0xad, 0xc4, 0xbe, 0xf8, + 0x28, 0xcb, 0xe6, 0x16, 0xa8, 0x6b, 0xaf, 0xd5, 0x0a, 0x6d, 0x06, 0x59, + 0x4f, 0x7d, 0x53, 0xa6, 0x4e, 0x90, 0xa0, 0x23, 0x1b, 0x92, 0xf0, 0xe8, + 0xef, 0xed, 0x0d, 0xa7, 0x64, 0x01, 0x83, 0x4a, 0x3b, 0x2d, 0x18, 0x90, + 0x1d, 0x19, 0x1d, 0xa2, 0x98, 0xe9, 0xb5, 0xe4, 0x4a, 0x73, 0xcf, 0xdf, + 0x0c, 0x09, 0xd5, 0xf4, 0xd3, 0xd9, 0x12, 0x7c, 0xbb, 0x81, 0x51, 0x26, + 0x2a, 0xcb, 0xa7, 0xc9, 0x6a, 0xe9, 0xfb, 0x1d, 0xca, 0x43, 0xf1, 0xbe, + 0xfb, 0xc3, 0x6f, 0xb6, 0xa1, 0x0c, 0x42, 0x32, 0x18, 0x24, 0x63, 0xf9, + 0xa0, 0x7e, 0x71, 0x8c, 0xa5, 0x16, 0x16, 0x5a, 0x5e, 0x15, 0x5d, 0x6d, + 0x4b, 0x74, 0x5b, 0xde, 0x21, 0xd5, 0xe0, 0x11, 0xa6, 0x91, 0xc3, 0xb2, + 0xd7, 0x38, 0x70, 0xa2, 0x18, 0x29, 0x1b, 0xdc, 0x83, 0x3e, 0x37, 0x45, + 0xc4, 0x1b, 0x61, 0x98, 0x06, 0x12, 0x3e, 0xc0, 0xda, 0x1a, 0xc9, 0x18, + 0x9c, 0x50, 0x0e, 0xc5, 0xe1, 0xa7, 0x4d, 0x05, 0xc6, 0x99, 0x31, 0xab, + 0x17, 0x30, 0xb9, 0xb0, 0x01, 0x1f, 0x93, 0xd9, 0x76, 0xd4, 0x67, 0x0b, + 0xea, 0x7b, 0x2b, 0x0b, 0x42, 0x97, 0x40, 0x07, 0x94, 0x08, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x84, 0x3f, 0x01, 0x16, 0x00, 0x07, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x34, 0x00, 0x87, 0x5e, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, + 0x33, 0x2b, 0x24, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x83, + 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, 0x45, 0x30, 0xb3, 0x67, 0xc8, 0x32, + 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, 0xf4, 0x06, 0x98, 0x7e, 0x8b, 0x09, + 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, + 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x99, 0xb4, 0x79, 0xc1, 0x37, 0xc1, 0xe1, 0x5c, 0x49, + 0xa0, 0xe1, 0xf3, 0x17, 0xb8, 0x9c, 0x69, 0xe6, 0xba, 0xdc, 0xe7, 0x78, + 0xb2, 0x5d, 0xd6, 0x95, 0xbe, 0xb2, 0xda, 0x91, 0xd3, 0x9b, 0xf2, 0xd4, + 0xe3, 0x95, 0x3c, 0x53, 0x8d, 0x0e, 0x68, 0xe9, 0x02, 0xb3, 0xed, 0xeb, + 0x95, 0xdd, 0x11, 0xb2, 0x64, 0x69, 0x8a, 0xfe, 0x03, 0x05, 0xd5, 0x04, + 0x9b, 0xac, 0x8a, 0xb6, 0x98, 0x29, 0x56, 0x2e, 0xd3, 0xea, 0x4e, 0x84, + 0xee, 0x23, 0x44, 0x03, 0x12, 0x9d, 0x9c, 0x9c, 0x9f, 0x11, 0x62, 0xf0, + 0x86, 0x36, 0x52, 0x15, 0x0f, 0x27, 0x93, 0xdb, 0xde, 0x13, 0xc9, 0x94, + 0x93, 0xe4, 0xa4, 0x6f, 0x58, 0x9d, 0x58, 0x9f, 0x15, 0xba, 0x5f, 0x4c, + 0xf3, 0x9a, 0x90, 0xc0, 0xcb, 0x60, 0xce, 0x9b, 0x56, 0x0c, 0xfe, 0x5b, + 0xd2, 0x4e, 0x0e, 0x82, 0xe6, 0x4c, 0x62, 0x57, 0x08, 0x6e, 0x5d, 0x54, + 0x7b, 0x28, 0xbb, 0x88, 0xdc, 0xec, 0xaa, 0xd1, 0x6e, 0xd3, 0x94, 0x20, + 0x3e, 0x35, 0x81, 0x52, 0xf6, 0xe9, 0xee, 0x42, 0x89, 0xe9, 0xea, 0x61, + 0x2c, 0xd8, 0xdc, 0xe3, 0x82, 0xf7, 0xf0, 0xc0, 0xf6, 0xf9, 0xb7, 0xef, + 0x49, 0xc7, 0x8d, 0x6c, 0x8a, 0x6d, 0x6e, 0xbc, 0x2d, 0xc0, 0xb1, 0xec, + 0x0c, 0xdd, 0xe5, 0xbe, 0x65, 0x3f, 0x69, 0x81, 0xcf, 0xe8, 0xd8, 0xf3, + 0x57, 0x8e, 0xba, 0x73, 0x7f, 0xb0, 0x4e, 0x65, 0xa2, 0xa5, 0xa5, 0xbb, + 0x7b, 0xae, 0xaa, 0x88, 0x06, 0x4f, 0x2c, 0x43, 0xb9, 0x4c, 0x17, 0xa1, + 0x24, 0xfb, 0xe1, 0x90, 0x50, 0xdb, 0xcc, 0xd9, 0xe5, 0x7b, 0x09, 0xaf, + 0x5c, 0x5a, 0x4f, 0xb2, 0x2b, 0x30, 0x53, 0x0f, 0xd3, 0xe2, 0xbd, 0xcd, + 0xf7, 0xa3, 0x19, 0xdc, 0xba, 0xee, 0xd1, 0x49, 0xbc, 0xa6, 0xde, 0x1b, + 0xe6, 0xd3, 0xaf, 0xdd, 0x61, 0xf6, 0xfd, 0xef, 0xb7, 0xda, 0x9d, 0x93, + 0x45, 0x0a, 0xa2, 0xa8, 0x1a, 0xe5, 0x16, 0xb1, 0xaf, 0x20, 0x00, 0x86, + 0x6b, 0x66, 0x42, 0x97, 0x4e, 0x3a, 0xea, 0x0d, 0x33, 0xb2, 0x93, 0x87, + 0x9c, 0xd1, 0x6a, 0x20, 0xbc, 0xc9, 0x7d, 0x46, 0xb9, 0x0a, 0x26, 0x9a, + 0x09, 0x81, 0xc8, 0x6d, 0x9b, 0x63, 0xa5, 0x1f, 0x63, 0x72, 0x6c, 0xa8, + 0x65, 0x65, 0xa2, 0x8a, 0x81, 0x4d, 0x54, 0xd4, 0xa3, 0xc4, 0x86, 0x48, + 0x31, 0x5c, 0x4e, 0x15, 0xf3, 0x48, 0x30, 0xbc, 0x17, 0xac, 0x0b, 0x85, + 0x8f, 0x44, 0x62, 0xf4, 0x57, 0xc7, 0xbd, 0x18, 0xcf, 0xf5, 0xd8, 0xa9, + 0x2d, 0xf5, 0x57, 0xaf, 0x42, 0x09, 0xf7, 0x5b, 0x25, 0x56, 0xa1, 0x04, + 0x0c, 0xf7, 0xa7, 0xc9, 0x2d, 0xd7, 0x84, 0x78, 0x86, 0x82, 0x2d, 0xd3, + 0xaa, 0xd2, 0xbf, 0x77, 0xc0, 0x34, 0x7b, 0xdb, 0x7e, 0x4d, 0xde, 0x63, + 0x8f, 0xcc, 0xb6, 0x6d, 0x01, 0x80, 0x68, 0x51, 0x3e, 0x8f, 0x2a, 0x7c, + 0x0e, 0xaa, 0xc2, 0xbf, 0x77, 0x12, 0x06, 0x88, 0xdf, 0x3f, 0x6c, 0x7d, + 0x69, 0x05, 0x57, 0x71, 0xeb, 0xe7, 0xf3, 0xcb, 0x32, 0x4d, 0x33, 0x54, + 0x8a, 0x2a, 0x1b, 0xb5, 0x6e, 0xb6, 0xa4, 0x64, 0xcd, 0x34, 0x5c, 0xa9, + 0x3d, 0x92, 0xc8, 0x38, 0xbb, 0x84, 0xed, 0xde, 0xe4, 0xa2, 0xe1, 0x68, + 0x2f, 0xcb, 0x4b, 0x3c, 0x76, 0xb2, 0x3b, 0x84, 0x5f, 0x6b, 0x46, 0x72, + 0x2f, 0x7f, 0xf0, 0x6f, 0x6b, 0x7b, 0xd3, 0xc5, 0x4b, 0x20, 0x2b, 0xae, + 0x48, 0x7e, 0xcb, 0x22, 0x38, 0x44, 0x1f, 0x43, 0x1c, 0x55, 0x00, 0x00, + 0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x19, 0x07, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x0d, 0xf1, 0x00, 0x0e, 0x8c, 0x0e, 0xf4, 0x0e, 0xc0, 0x0e, 0x24, + 0x0f, 0x99, 0x0e, 0x58, 0x0f, 0xcd, 0x0f, 0x65, 0x0d, 0xf1, 0x0f, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x32, 0x05, 0x34, 0x34, 0x15, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0xa9, 0x4a, 0x8f, 0xe5, 0xcc, 0xb1, 0x9b, 0xa6, 0x1c, + 0x4c, 0x08, 0x73, 0xd3, 0x91, 0xe9, 0x87, 0x98, 0x2f, 0xbb, 0xd3, 0x74, + 0x65, 0x73, 0x74, 0x11, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x59, 0x27, + 0x33, 0x2f, 0x22, 0x90, 0x8f, 0xdf, 0x8f, 0x07, 0xfa, 0xa9, 0xeb, 0x8d, + 0x26, 0x20, 0xc7, 0xc6, 0x2a, 0x20, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, + 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, + 0xa1, 0xb8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x0d, 0x33, 0x05, 0x34, 0x34, + 0x17, 0x01, 0x7f, 0xda, 0x6a, 0xa0, 0x63, 0xf3, 0xfc, 0x5a, 0x86, 0x5c, + 0xa8, 0xf7, 0xa6, 0x9b, 0x5d, 0x69, 0x07, 0x3b, 0x91, 0x55, 0x72, 0x29, + 0x9c, 0x30, 0x4b, 0x50, 0xee, 0xe7, 0xb0, 0xc7, 0x1b, 0x05, 0x97, 0x70, + 0xac, 0x8e, 0x43, 0x5d, 0x69, 0x39, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x12, + 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x05, 0xc5, 0x64, 0xf0, 0xff, 0xc1, + 0x0a, 0xf4, 0x42, 0x83, 0x33, 0x33, 0x5d, 0x04, 0x75, 0x9c, 0x85, 0x9a, + 0x74, 0x0a, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, + 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x09, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x51, 0x96, + 0x74, 0xbb, 0x0c, 0xef, 0x0c, 0xf3, 0x24, 0x61, 0xd2, 0x2c, 0xba, 0x9a, + 0xa9, 0xc8, 0x0e, 0x22, 0xff, 0x0b, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, + 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, + 0xa1, 0xb8, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x08, 0x33, 0x05, 0x34, 0x34, + 0x17, 0x01, 0x0b, 0x66, 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, + 0x95, 0x22, 0xa7, 0xe3, 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, + 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, + 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x07, + 0x3c, 0x05, 0x34, 0x34, 0x29, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, + 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, + 0x07, 0x09, 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, 0x59, 0x31, 0xba, + 0xaa, 0x89, 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, 0x60, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, + 0x05, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, + 0x3a, 0x3a, 0x7e, 0x0e, 0x1e, 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, + 0x13, 0xa3, 0x59, 0xe5, 0x0e, 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, + 0x6d, 0xb9, 0x0a, 0x0b, 0x36, 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x06, 0x33, 0x05, 0x34, 0x34, 0x17, 0x01, 0x77, + 0xac, 0x86, 0x8b, 0xf9, 0xb8, 0xa0, 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, + 0xe2, 0x63, 0x81, 0xf6, 0x85, 0xbc, 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, + 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, + 0x41, 0xcb, 0x34, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x02, 0x32, 0x05, 0x34, + 0x34, 0x17, 0x09, 0x83, 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, 0x45, 0x30, + 0xb3, 0x67, 0xc8, 0x32, 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, 0xf4, 0x06, + 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, 0x5c, 0x08, + 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x0d, 0x0f, 0xe4, 0x00, 0x03, 0x0f, 0xda, 0x00, 0x0f, 0xf6, 0x0f, 0xda, + 0x0f, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x02, 0x03, 0x15, 0x01, 0x63, 0x65, 0x72, 0x74, 0x02, + 0x00, 0x00, 0x00, 0x08, 0x09, 0x6b, 0x65, 0x79, 0x08, 0x03, 0x03, 0x15, + 0x01, 0x6b, 0x65, 0x79, 0x73, 0x06, 0x08, 0x01, 0x03, 0x15, 0x01, 0x67, + 0x65, 0x6e, 0x70, 0x12, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x02, 0x03, 0xfb, 0x00, 0x09, 0xed, 0x03, 0xfb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, + 0x6f, 0x02, 0x11, 0x00, 0x07, 0x07, 0x01, 0x01, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x95, 0x12, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, + 0x9d, 0x7a, 0x35, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x9d, 0x7a, 0x35, 0x03, + 0x03, 0x37, 0xee, 0x5a, 0x85, 0xe1, 0xcb, 0xdd, 0xc8, 0xce, 0x07, 0x77, + 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, 0x30, 0x3a, 0xcd, 0x7e, 0x0b, 0xaa, + 0xec, 0xd2, 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, + 0x70, 0x20, 0x84, 0xa7, 0x17, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, 0x12, + 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, 0x0d, + 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, 0x5b, + 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0xda, 0xde, 0x08, + 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, 0xba, 0xe3, + 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, + 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, + 0x4b, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0xc4, 0xe8, 0xe5, 0xde, 0xeb, 0xd1, 0xbc, 0xae, 0x0f, 0x47, 0x6a, + 0xc0, 0xb4, 0xf8, 0x7a, 0xdc, 0xc1, 0x10, 0xb0, 0x90, 0xf2, 0x29, 0x16, + 0x8f, 0x90, 0xeb, 0x31, 0x83, 0x9b, 0x33, 0x91, 0x26, 0x16, 0x4c, 0xce, + 0xfe, 0x98, 0x25, 0x0d, 0xed, 0xe6, 0x9f, 0xc3, 0x91, 0xac, 0xbb, 0xf8, + 0xc0, 0xca, 0x25, 0x42, 0xd4, 0x5d, 0xfe, 0x1b, 0x4d, 0x60, 0x7f, 0x01, + 0xee, 0x5f, 0x16, 0xbd, 0xb8, 0xe7, 0xdc, 0xe1, 0x75, 0xf9, 0x1a, 0xc7, + 0x4f, 0xc5, 0xf1, 0x44, 0x46, 0xfe, 0xdd, 0x91, 0xf8, 0x25, 0xed, 0xbc, + 0x1a, 0xf1, 0x34, 0x71, 0x05, 0x4e, 0x13, 0xb9, 0x21, 0xbf, 0x04, 0x6d, + 0x1e, 0x0f, 0xe6, 0x63, 0x19, 0x0b, 0x77, 0xef, 0xf1, 0x24, 0xf4, 0x55, + 0xf3, 0x71, 0x53, 0x13, 0x8b, 0xbb, 0xd5, 0xdb, 0x3e, 0xcb, 0xc5, 0x3a, + 0x9a, 0xe9, 0x55, 0xa1, 0x75, 0xa1, 0x98, 0x40, 0x80, 0x3b, 0x1e, 0xe1, + 0xbc, 0x44, 0x59, 0xb9, 0xf2, 0x6b, 0xa9, 0x0d, 0x13, 0x0c, 0xd2, 0xb2, + 0x99, 0xbf, 0x1f, 0xa9, 0x86, 0x5b, 0x2b, 0x63, 0x65, 0x28, 0x2f, 0x11, + 0x96, 0x2b, 0xa1, 0x9d, 0x32, 0x5e, 0x55, 0xa1, 0xdf, 0x90, 0x3b, 0x5e, + 0x4e, 0xdd, 0x3f, 0x6f, 0x10, 0xb6, 0x7c, 0xad, 0x92, 0xeb, 0x9f, 0x72, + 0xe4, 0x37, 0x83, 0x59, 0x4b, 0x6c, 0x62, 0x2e, 0xf1, 0x11, 0x5a, 0x75, + 0x86, 0x5b, 0xe4, 0x79, 0x86, 0xca, 0xdb, 0xd8, 0x11, 0xf4, 0x5f, 0x65, + 0x8f, 0x7f, 0x66, 0xc4, 0xe0, 0x35, 0x97, 0x15, 0xe3, 0x13, 0x97, 0xa9, + 0x23, 0x20, 0xce, 0xfe, 0x1a, 0x3a, 0x3f, 0xce, 0xa3, 0x88, 0x36, 0xfa, + 0x58, 0xb2, 0x35, 0x9a, 0x07, 0x69, 0xcd, 0xc7, 0xc7, 0xf4, 0x93, 0x0d, + 0x11, 0x3f, 0xec, 0x74, 0x88, 0x55, 0xfc, 0x12, 0x08, 0x0d, 0xc1, 0xd1, + 0x1f, 0xf6, 0xdd, 0xff, 0xea, 0x75, 0x40, 0x21, 0x06, 0xf2, 0x8a, 0x6c, + 0x2e, 0xc4, 0x84, 0x5d, 0x67, 0x90, 0x29, 0x95, 0xed, 0x6e, 0x55, 0x19, + 0x12, 0xb0, 0x11, 0x41, 0x2e, 0x2b, 0xe0, 0xbb, 0xe4, 0x90, 0x8e, 0xa3, + 0x9f, 0x1c, 0x3d, 0xa0, 0xd1, 0x5c, 0xa3, 0x01, 0xf3, 0x0f, 0x09, 0x64, + 0x7c, 0x12, 0xbc, 0x43, 0x2a, 0x24, 0x32, 0x8c, 0x63, 0x6c, 0x4d, 0x91, + 0xff, 0xe8, 0x0c, 0xc3, 0x54, 0xa8, 0x9b, 0x01, 0x99, 0x56, 0xc3, 0x1c, + 0xe1, 0x8e, 0x18, 0xfb, 0xb7, 0xfe, 0x27, 0x8c, 0x83, 0x3b, 0x07, 0x5b, + 0x93, 0x35, 0xaa, 0xef, 0xda, 0xb5, 0x50, 0x29, 0x92, 0x64, 0x18, 0x5d, + 0x2d, 0x25, 0x13, 0x68, 0x11, 0x37, 0xa7, 0x9e, 0xb1, 0x82, 0xe5, 0x10, + 0x6c, 0x2e, 0x44, 0x23, 0x04, 0x88, 0x47, 0xf0, 0x8e, 0xbc, 0xb2, 0xda, + 0xe2, 0x58, 0x8e, 0x4a, 0xc9, 0x93, 0x28, 0x7a, 0x32, 0x8c, 0x3d, 0x9b, + 0x49, 0x45, 0xcd, 0x13, 0x15, 0x13, 0xef, 0xaa, 0x71, 0x76, 0x08, 0x31, + 0xdf, 0xf2, 0xce, 0xae, 0xc5, 0xf7, 0x01, 0xd4, 0x59, 0x76, 0x88, 0xa3, + 0x8b, 0xfc, 0x3a, 0x24, 0xb6, 0x98, 0x44, 0x51, 0x87, 0xff, 0x14, 0xa7, + 0xb0, 0x47, 0x15, 0xc0, 0x35, 0x9a, 0xb8, 0xf1, 0xff, 0xa8, 0x84, 0x5b, + 0x4e, 0x59, 0x02, 0x65, 0xbf, 0x6f, 0xd5, 0x4d, 0xa0, 0xdb, 0x50, 0x13, + 0x7f, 0x1f, 0x86, 0x3a, 0x7a, 0x6b, 0xfb, 0xf2, 0xb6, 0xa6, 0x3d, 0xac, + 0x97, 0x86, 0xbf, 0x29, 0xdb, 0xb6, 0x99, 0xe8, 0x22, 0xce, 0xea, 0x43, + 0x38, 0xab, 0xfa, 0x64, 0x6c, 0xcc, 0x45, 0x7a, 0xc0, 0x9f, 0x50, 0x7b, + 0x1f, 0x25, 0x33, 0xe6, 0xfc, 0x9f, 0xcc, 0xfb, 0xbb, 0x50, 0x33, 0x31, + 0xe8, 0x62, 0x33, 0x43, 0x7e, 0x8d, 0x82, 0x38, 0x0c, 0x2c, 0x6e, 0x57, + 0x5f, 0x08, 0x31, 0x96, 0x48, 0x02, 0xbb, 0x95, 0x9a, 0xea, 0xd4, 0xcd, + 0x54, 0x49, 0x65, 0x51, 0xf6, 0xc9, 0x39, 0x39, 0xab, 0xe3, 0x92, 0xc2, + 0x71, 0xbb, 0xb1, 0x25, 0x12, 0x96, 0x45, 0xb8, 0x14, 0x34, 0x82, 0x94, + 0x9f, 0xbd, 0xc7, 0xf7, 0x07, 0x4f, 0x7d, 0xb5, 0xa2, 0xe2, 0xd5, 0x91, + 0xbf, 0x9b, 0xde, 0x3d, 0xa2, 0xfe, 0x25, 0x76, 0x5e, 0xac, 0xde, 0xf1, + 0x5f, 0x00, 0xe5, 0x9f, 0x6f, 0x3d, 0xdd, 0xbc, 0x7f, 0xfd, 0x92, 0x52, + 0x56, 0x53, 0x5a, 0x04, 0xca, 0xdc, 0x23, 0x76, 0xe4, 0xc4, 0xeb, 0x00, + 0x5e, 0x3e, 0x71, 0xb9, 0x7c, 0x54, 0x81, 0x4d, 0x6e, 0xb3, 0x09, 0x39, + 0x6f, 0x67, 0x0e, 0xc6, 0x95, 0xdf, 0x03, 0xcc, 0x7e, 0x0b, 0x7c, 0x31, + 0x16, 0xbe, 0x4b, 0xfc, 0x0f, 0x17, 0xb4, 0x7a, 0x9c, 0x44, 0x36, 0x5a, + 0xaf, 0x42, 0x69, 0x40, 0x58, 0xe7, 0xa4, 0x07, 0x5b, 0xe5, 0xd6, 0x35, + 0xe5, 0x4a, 0xde, 0x35, 0x29, 0xc5, 0x69, 0x00, 0x47, 0xfa, 0x3d, 0x54, + 0xbc, 0x1f, 0xa5, 0x58, 0x86, 0xbf, 0xaa, 0x5d, 0x94, 0x60, 0x3b, 0x81, + 0x11, 0xa0, 0xa0, 0x19, 0xf3, 0x7a, 0xfd, 0x69, 0x5f, 0xac, 0xf6, 0x41, + 0xfd, 0x73, 0xff, 0x99, 0x2a, 0x41, 0xee, 0xda, 0x7f, 0xfe, 0x80, 0xcb, + 0x20, 0x9e, 0x8f, 0xdc, 0x6c, 0x3f, 0x71, 0xed, 0x07, 0xc5, 0xd9, 0x4f, + 0x32, 0x9e, 0xe5, 0x0b, 0x63, 0x70, 0x66, 0x2b, 0x42, 0x5d, 0xa3, 0xfa, + 0x81, 0x6a, 0x47, 0x40, 0xa6, 0xed, 0x8c, 0x7d, 0x71, 0x61, 0x74, 0xd3, + 0x40, 0x24, 0x1f, 0x2c, 0x4a, 0x89, 0xd3, 0xbb, 0xb8, 0x14, 0x6b, 0x8f, + 0xb2, 0x3d, 0x16, 0x99, 0xf5, 0x7f, 0x0a, 0x2e, 0x79, 0x6b, 0xb6, 0xe8, + 0x8f, 0xb3, 0x42, 0x67, 0x93, 0x59, 0xe8, 0x69, 0x66, 0x9e, 0x6d, 0x06, + 0x11, 0x5d, 0xfd, 0x0f, 0x19, 0x43, 0x9f, 0x5b, 0x82, 0xbc, 0x5f, 0x79, + 0xeb, 0x4f, 0x7f, 0xcc, 0xfa, 0x8e, 0xe5, 0xe6, 0xe4, 0x01, 0xf7, 0xa0, + 0x7a, 0xb8, 0xe6, 0xb6, 0x08, 0x19, 0x80, 0x30, 0xa4, 0x2f, 0x84, 0xd2, + 0x5e, 0xce, 0xde, 0x59, 0x26, 0xf6, 0x19, 0x19, 0x42, 0x13, 0x0e, 0xcb, + 0x3f, 0xfb, 0x22, 0xbb, 0x61, 0xc6, 0xf8, 0xc9, 0x68, 0x77, 0x60, 0x30, + 0x85, 0x34, 0x2a, 0x30, 0x3c, 0x09, 0xd9, 0x2f, 0xf7, 0x15, 0xdc, 0x50, + 0xc5, 0x05, 0x18, 0x12, 0x2c, 0x8b, 0x55, 0xad, 0x3e, 0x2a, 0xf9, 0x1f, + 0x77, 0xa3, 0xc6, 0x34, 0x47, 0x86, 0x7d, 0x85, 0x11, 0x1c, 0x04, 0x0c, + 0x4a, 0xae, 0xc0, 0x49, 0xba, 0x46, 0xa9, 0x75, 0xd5, 0x86, 0x1b, 0xa0, + 0x18, 0x63, 0xfe, 0x9c, 0x23, 0x6c, 0xb3, 0xfe, 0x06, 0x06, 0x6f, 0xdf, + 0x8b, 0x5b, 0x59, 0x2b, 0xd4, 0x97, 0x50, 0x1b, 0x79, 0x64, 0x57, 0xbe, + 0x62, 0x46, 0xda, 0x38, 0xf3, 0x06, 0x3c, 0xec, 0x3e, 0xcf, 0x14, 0x24, + 0xc6, 0x33, 0xf6, 0x08, 0x0e, 0xe9, 0xb1, 0xbc, 0x29, 0x37, 0x13, 0x96, + 0x79, 0x2a, 0x32, 0x8e, 0x93, 0xed, 0x97, 0xcf, 0x7e, 0x72, 0xb6, 0x60, + 0x6c, 0x68, 0x2a, 0xf2, 0xbf, 0xd2, 0xe0, 0x2b, 0x76, 0xd3, 0x88, 0x24, + 0xf7, 0xfc, 0xed, 0xf9, 0x59, 0xff, 0xd1, 0xd5, 0xf4, 0x69, 0x00, 0xd2, + 0xbd, 0xfc, 0xcb, 0x1e, 0x8b, 0x51, 0x7a, 0xd5, 0x46, 0x6e, 0x11, 0x33, + 0xf8, 0xee, 0xbd, 0xb5, 0x64, 0x8b, 0xf6, 0x31, 0xd4, 0x7f, 0xda, 0x2b, + 0xf0, 0x52, 0x92, 0xaa, 0xee, 0x4e, 0x2e, 0xea, 0xdd, 0x42, 0x14, 0x51, + 0xff, 0xc0, 0xb2, 0x6e, 0xc2, 0x77, 0x7a, 0x9d, 0xce, 0x74, 0xaa, 0xe9, + 0x46, 0x67, 0x40, 0x08, 0xfe, 0xf5, 0xc0, 0xd0, 0x33, 0x2b, 0x7a, 0x07, + 0xb0, 0x37, 0x22, 0x96, 0x0c, 0xe1, 0xe2, 0x97, 0x96, 0x1b, 0xcf, 0xfc, + 0xd3, 0x4a, 0x8f, 0x6e, 0x99, 0xc1, 0xb0, 0x43, 0xb7, 0x96, 0xd4, 0xab, + 0xe6, 0x8b, 0x90, 0x98, 0x8a, 0xed, 0x0f, 0xe1, 0x77, 0x20, 0x87, 0x39, + 0x66, 0x56, 0xfa, 0xa1, 0x58, 0xd1, 0x8a, 0x0e, 0x59, 0xc0, 0x21, 0xf7, + 0x14, 0x10, 0xe3, 0xbb, 0x2f, 0xcd, 0x09, 0xc2, 0x44, 0x04, 0x27, 0x3f, + 0x68, 0xec, 0xc2, 0xd0, 0x04, 0xb5, 0x0b, 0x14, 0x8f, 0xcf, 0x04, 0xc1, + 0x94, 0x65, 0xc2, 0xbc, 0x8f, 0x9c, 0x79, 0x0b, 0xe2, 0xd6, 0x5b, 0xe9, + 0x90, 0xa5, 0x0b, 0x8c, 0xa7, 0x27, 0xc5, 0x6d, 0x89, 0x62, 0x30, 0x3d, + 0x5b, 0x7a, 0xd4, 0xee, 0x33, 0x1c, 0x42, 0x09, 0x64, 0x95, 0x64, 0x25, + 0x79, 0x63, 0x5a, 0x10, 0x79, 0x5d, 0xb4, 0x86, 0x19, 0x84, 0x84, 0x61, + 0x43, 0x1d, 0x46, 0xef, 0xd5, 0x81, 0xc0, 0xe7, 0x3f, 0x64, 0xf1, 0xf0, + 0x36, 0x1b, 0x1f, 0xdf, 0xba, 0x7e, 0x6a, 0x8b, 0xdb, 0xc2, 0x48, 0xe3, + 0x07, 0x12, 0x9e, 0xc1, 0x9c, 0x85, 0xd0, 0xa5, 0x5e, 0xda, 0x88, 0x43, + 0xb3, 0xed, 0xbb, 0xd3, 0xdf, 0x8e, 0x6f, 0x13, 0x51, 0x52, 0x50, 0x73, + 0x97, 0xc1, 0xd0, 0xb7, 0xd7, 0x82, 0x31, 0xfd, 0xc2, 0x96, 0xc3, 0x37, + 0xd4, 0x1c, 0xfd, 0x90, 0x47, 0x1c, 0x7e, 0xc6, 0xb0, 0x0d, 0x6f, 0x96, + 0x65, 0x6b, 0x9d, 0xbd, 0x59, 0x13, 0xca, 0x32, 0xc3, 0x29, 0x39, 0xdc, + 0x6c, 0x26, 0x15, 0xc8, 0x83, 0xa8, 0x5d, 0x9d, 0x1d, 0x30, 0x64, 0x65, + 0x05, 0x48, 0xce, 0xaa, 0x69, 0xf7, 0x42, 0xa6, 0x1f, 0x9d, 0xcb, 0xc9, + 0x5b, 0xe7, 0x69, 0xcf, 0x29, 0xd1, 0xa5, 0xcf, 0x55, 0x79, 0xff, 0x6c, + 0xfa, 0xac, 0xb8, 0xec, 0x33, 0x61, 0xc1, 0x33, 0x5c, 0xef, 0x0f, 0x92, + 0x93, 0x4a, 0x83, 0x79, 0x48, 0x21, 0xba, 0xf7, 0xcb, 0x01, 0x63, 0x84, + 0x22, 0xc6, 0xec, 0x8c, 0x66, 0x8d, 0x97, 0x42, 0x56, 0x75, 0x73, 0x61, + 0xcb, 0xfa, 0xd4, 0x20, 0x66, 0xce, 0x6a, 0x81, 0x78, 0xa6, 0xc8, 0x72, + 0xeb, 0x15, 0x25, 0xb2, 0x06, 0xc0, 0xb2, 0xab, 0x18, 0x66, 0x4e, 0x5e, + 0x73, 0x21, 0x55, 0xd6, 0xe3, 0x60, 0x81, 0x56, 0x85, 0x1f, 0x5a, 0xce, + 0xff, 0xc0, 0x6a, 0xd3, 0x18, 0xdd, 0xfd, 0xaa, 0x73, 0x42, 0xb1, 0xd5, + 0x62, 0xda, 0x2e, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x8c, 0x10, 0x01, + 0x11, 0x00, 0x07, 0x07, 0x01, 0x01, 0x34, 0x00, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x95, 0x4a, 0x33, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x83, 0xb6, + 0x03, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x83, 0xb6, 0x03, 0x03, 0x03, 0xb1, + 0x0a, 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, 0xc7, 0x2e, 0xdb, + 0x0f, 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x7e, 0x0b, 0xaa, 0xec, 0xd2, + 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, 0x20, + 0x84, 0xa7, 0x17, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, 0x12, 0x4e, 0x73, + 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, 0x0d, 0x66, 0x6e, + 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, 0x5b, 0x9a, 0x6f, + 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0xda, 0xde, 0x08, 0x82, 0x7d, + 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, 0xba, 0xe3, 0x73, 0xe9, + 0x35, 0x6f, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, + 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x15, + 0x67, 0xb2, 0x55, 0xfa, 0x3d, 0xce, 0x31, 0x23, 0xdf, 0x93, 0xad, 0x9c, + 0x09, 0x8d, 0xbc, 0x7e, 0xb3, 0x84, 0x6c, 0x0a, 0x52, 0x6e, 0xab, 0x7d, + 0x13, 0x86, 0xcc, 0xbe, 0xf3, 0x30, 0x0b, 0x08, 0xf8, 0xa1, 0xcf, 0x62, + 0x7a, 0x7e, 0xaf, 0xd7, 0x55, 0x51, 0x92, 0x16, 0x1d, 0x3e, 0x5e, 0x37, + 0x86, 0xf2, 0xea, 0x51, 0xee, 0x6a, 0xe3, 0xa6, 0xe1, 0xc5, 0xce, 0x5f, + 0x86, 0x3e, 0x5a, 0x3d, 0x6d, 0x31, 0xf9, 0x10, 0xe3, 0xd6, 0x77, 0x76, + 0x33, 0x03, 0xfc, 0x2a, 0x0c, 0x45, 0x5c, 0x29, 0xa8, 0x9f, 0x96, 0x45, + 0xd5, 0xae, 0x9f, 0x21, 0x9a, 0x1a, 0x6d, 0x85, 0x4f, 0x3d, 0x35, 0x85, + 0xf1, 0x6a, 0x11, 0xf3, 0x54, 0x3e, 0x96, 0x4c, 0xbf, 0xa6, 0x01, 0xd4, + 0xc8, 0x67, 0xc1, 0x94, 0x16, 0x19, 0x39, 0x42, 0x28, 0xc9, 0x5b, 0x88, + 0x09, 0xbf, 0xba, 0xf2, 0x9b, 0x4f, 0x13, 0x73, 0x8b, 0x2c, 0x98, 0x07, + 0x70, 0xa7, 0x27, 0xae, 0x02, 0xa3, 0x63, 0x11, 0x5b, 0x1b, 0x8c, 0x85, + 0x8e, 0x0f, 0xde, 0xf9, 0x0b, 0x8f, 0x06, 0xfd, 0xab, 0x03, 0x34, 0x52, + 0x23, 0x52, 0x2e, 0xf1, 0xa8, 0x30, 0x89, 0xe8, 0xdc, 0x8f, 0xe4, 0x9f, + 0xd3, 0xa1, 0x09, 0x33, 0x5b, 0x07, 0xc8, 0x9c, 0x49, 0x47, 0x37, 0x53, + 0x35, 0xc5, 0x1e, 0x78, 0x9f, 0xc7, 0x65, 0x94, 0xf6, 0xb9, 0xcf, 0xcc, + 0xee, 0xfc, 0x73, 0x40, 0x42, 0xb8, 0x37, 0x12, 0xfd, 0x34, 0xea, 0xdd, + 0x89, 0x01, 0x51, 0xfe, 0xde, 0xb6, 0xb6, 0x1e, 0x40, 0x39, 0x12, 0xf8, + 0xdd, 0x5c, 0x96, 0xb6, 0x1b, 0x21, 0x08, 0xaf, 0x6e, 0x62, 0xbb, 0x3c, + 0x65, 0xd1, 0xa9, 0x15, 0xb0, 0xf6, 0x1b, 0xbb, 0xac, 0x26, 0xa5, 0x82, + 0xc6, 0x43, 0xa0, 0x88, 0xf1, 0x64, 0x64, 0x01, 0xd9, 0xa9, 0x5e, 0xf0, + 0x73, 0x52, 0xfb, 0xc9, 0x27, 0x81, 0x0e, 0xce, 0x8e, 0x4c, 0xc8, 0x3d, + 0xef, 0xe2, 0xdc, 0xe3, 0xe9, 0x23, 0x3c, 0x47, 0x93, 0xcb, 0x18, 0xe6, + 0x11, 0xe2, 0x40, 0xd7, 0x73, 0x18, 0x6b, 0xbd, 0x77, 0x56, 0x6e, 0x6c, + 0xe8, 0x25, 0xe7, 0xef, 0x12, 0xc7, 0x8f, 0x38, 0x80, 0x0e, 0xd1, 0x97, + 0x71, 0xef, 0xfa, 0x78, 0xac, 0x3d, 0x55, 0x45, 0x83, 0x45, 0x62, 0xb0, + 0x9a, 0xbf, 0x45, 0xd5, 0xbe, 0x45, 0x8a, 0xa2, 0x21, 0x88, 0xb9, 0xd0, + 0x3e, 0x59, 0xbb, 0x68, 0x77, 0xb7, 0x29, 0x65, 0x4a, 0x8d, 0xf4, 0x1d, + 0xf1, 0xd1, 0x00, 0x92, 0x2d, 0xcb, 0x6b, 0xaa, 0x9d, 0x1d, 0x0f, 0xf1, + 0x45, 0x0b, 0x13, 0x47, 0x2b, 0x47, 0x00, 0x30, 0x72, 0x0c, 0xa8, 0xb2, + 0xcb, 0x5b, 0xcd, 0xee, 0x30, 0x8d, 0xdb, 0x62, 0xd1, 0xb5, 0x5f, 0xe1, + 0x3e, 0xf8, 0x96, 0x09, 0x1e, 0x82, 0x2e, 0xf1, 0x8c, 0x20, 0x52, 0x33, + 0x2e, 0x42, 0x5c, 0x64, 0x39, 0xa2, 0x7b, 0x84, 0x2f, 0xff, 0x02, 0x24, + 0xdd, 0x40, 0x23, 0x9c, 0xec, 0xf0, 0xe9, 0x8f, 0x37, 0x15, 0xfd, 0xca, + 0xa5, 0xa6, 0x30, 0x1f, 0x4f, 0xa6, 0xf1, 0x05, 0xd8, 0x2f, 0x0b, 0xbf, + 0xa4, 0x3a, 0x9f, 0x57, 0x31, 0xb3, 0x9d, 0x64, 0xa5, 0xc9, 0x13, 0x64, + 0x7f, 0xb2, 0xe9, 0x38, 0x55, 0xe2, 0xd7, 0x6f, 0xad, 0xe5, 0x77, 0xf9, + 0xbe, 0x17, 0xcc, 0xec, 0xfb, 0xe4, 0xd1, 0x13, 0xa3, 0x20, 0x6e, 0xa6, + 0x64, 0x4e, 0xda, 0xa8, 0x86, 0xfc, 0xc8, 0x29, 0xb9, 0x47, 0xc1, 0xf0, + 0xe1, 0xc9, 0x62, 0x1d, 0x6a, 0x64, 0x8e, 0x1b, 0x76, 0x6a, 0x49, 0x22, + 0xeb, 0xfc, 0x33, 0xbc, 0x27, 0x8c, 0x84, 0x40, 0xe9, 0x3f, 0x46, 0x11, + 0x52, 0xf7, 0xe1, 0xbe, 0xbb, 0x48, 0x31, 0x28, 0x12, 0x62, 0x4a, 0x88, + 0x46, 0xf2, 0x4c, 0x1b, 0x03, 0xa6, 0x6f, 0xd3, 0x58, 0x35, 0x47, 0x24, + 0x53, 0x61, 0xc2, 0xa3, 0x6b, 0xc2, 0x6b, 0x73, 0x96, 0x2b, 0xd0, 0xd9, + 0x7d, 0x8e, 0xf1, 0x1a, 0x24, 0xfd, 0x34, 0x97, 0x02, 0xde, 0x0e, 0x79, + 0x29, 0xd2, 0x61, 0x2b, 0xca, 0x09, 0xea, 0xf2, 0xda, 0x17, 0x07, 0x8e, + 0x39, 0xc5, 0xee, 0x52, 0x76, 0x36, 0xce, 0x40, 0xee, 0xfa, 0x03, 0x40, + 0x9b, 0x91, 0xf6, 0x5e, 0x82, 0x46, 0x3e, 0x91, 0x13, 0xf2, 0x4e, 0x49, + 0x1d, 0x61, 0xf2, 0x6a, 0xcd, 0x5f, 0x06, 0xf0, 0xde, 0x9d, 0x5c, 0x8d, + 0xf5, 0xf6, 0xe5, 0x20, 0x1f, 0x1e, 0xd3, 0x37, 0x6f, 0x4a, 0xf5, 0x9e, + 0x93, 0x25, 0x27, 0xcc, 0x41, 0x53, 0x0c, 0xc7, 0x6b, 0x23, 0x42, 0xe0, + 0x3e, 0xe0, 0xb0, 0x06, 0x64, 0xc2, 0xf2, 0x6b, 0x45, 0x49, 0x25, 0x16, + 0x39, 0x9b, 0x67, 0xf8, 0xa0, 0x2f, 0x38, 0x48, 0x97, 0xd2, 0x59, 0x16, + 0x5b, 0x86, 0x10, 0xdd, 0x92, 0xa2, 0x26, 0x67, 0x46, 0xd8, 0x5f, 0x1a, + 0xe7, 0x16, 0x9f, 0x8e, 0xb5, 0x04, 0x4d, 0x1b, 0x14, 0xaf, 0x3e, 0xf6, + 0xf3, 0x2e, 0x9f, 0xb0, 0x9f, 0x93, 0x2a, 0x9e, 0xae, 0x2f, 0xeb, 0x23, + 0xf8, 0x34, 0xb4, 0x39, 0x0a, 0xbb, 0x58, 0x5a, 0x43, 0x1e, 0xf0, 0x33, + 0x2e, 0x78, 0x62, 0x69, 0xd6, 0x31, 0x01, 0xc2, 0xc9, 0x7e, 0xcd, 0x8f, + 0x2e, 0xab, 0x2d, 0x46, 0x5a, 0xfe, 0xdb, 0x44, 0x2f, 0x83, 0xbf, 0xd2, + 0x1a, 0x77, 0xd4, 0x1c, 0x9d, 0x6a, 0x72, 0xc1, 0xcd, 0x6c, 0x3a, 0x18, + 0xa7, 0x83, 0x71, 0x4a, 0x2b, 0x25, 0x79, 0xea, 0x34, 0x14, 0x7c, 0xe0, + 0xbf, 0xbc, 0x53, 0xf7, 0xa0, 0x5f, 0x70, 0xa8, 0x4e, 0x7d, 0xec, 0x82, + 0x16, 0x1d, 0xa5, 0x1f, 0x4c, 0xc6, 0xe7, 0xc3, 0x81, 0x9f, 0x1b, 0xd3, + 0x13, 0x5b, 0x22, 0x26, 0x1f, 0xc1, 0x63, 0xb0, 0xe7, 0x42, 0xc6, 0x74, + 0x3b, 0xb4, 0xbf, 0xa8, 0xb9, 0xf6, 0xaa, 0x67, 0x59, 0x96, 0x2d, 0xc1, + 0xd0, 0xf4, 0xe8, 0x84, 0xc7, 0x5e, 0xae, 0xca, 0xe8, 0x45, 0x68, 0xa8, + 0xd4, 0x87, 0x2f, 0x81, 0x08, 0x63, 0xd0, 0xb0, 0x5d, 0x04, 0x4d, 0x6a, + 0x72, 0xc4, 0x11, 0xc2, 0x05, 0x32, 0x20, 0xd6, 0x32, 0x44, 0x1d, 0xae, + 0xc9, 0x5d, 0x27, 0x67, 0xeb, 0xed, 0x63, 0xf6, 0x45, 0x25, 0xb8, 0x4c, + 0xf7, 0x63, 0xed, 0x18, 0x02, 0x0b, 0x53, 0x8d, 0x43, 0x45, 0x2f, 0x94, + 0x2f, 0x0f, 0xe9, 0x40, 0x41, 0x10, 0x57, 0x4f, 0x90, 0x29, 0x5b, 0x6e, + 0x8b, 0x72, 0x35, 0x25, 0xf9, 0x8c, 0xf1, 0x82, 0x3a, 0xa6, 0xcc, 0x8a, + 0xed, 0x3d, 0xfe, 0x85, 0xd7, 0xd9, 0x53, 0x42, 0x14, 0x34, 0x38, 0xef, + 0x1a, 0x8a, 0xbd, 0xd2, 0x17, 0x14, 0xac, 0x3e, 0xd8, 0x14, 0x26, 0xe7, + 0xc5, 0xdf, 0xd7, 0xad, 0x5c, 0xc9, 0x23, 0x46, 0x3d, 0xdb, 0xbd, 0xa0, + 0xc9, 0x12, 0x13, 0x9b, 0x45, 0x66, 0x6a, 0x96, 0xc3, 0x8b, 0xc5, 0x0a, + 0xc7, 0x38, 0x2f, 0x98, 0x4a, 0x32, 0x96, 0xbe, 0x14, 0xf7, 0x8b, 0x8d, + 0x45, 0x64, 0xf9, 0x94, 0x53, 0x1a, 0x00, 0x12, 0x9c, 0xc1, 0x0b, 0x7b, + 0x05, 0x3f, 0xaf, 0xc1, 0x79, 0x7f, 0x75, 0x54, 0xec, 0xc3, 0x1d, 0xd9, + 0xb5, 0x27, 0xed, 0xd9, 0x21, 0xfa, 0x42, 0xe5, 0x53, 0x40, 0xe5, 0x3a, + 0x51, 0x78, 0x8a, 0xe2, 0x80, 0xac, 0x5b, 0xff, 0xfd, 0x11, 0x4a, 0x58, + 0xc1, 0xb4, 0x4d, 0xdc, 0xc4, 0xa3, 0x4c, 0x57, 0x3d, 0x77, 0xb2, 0x98, + 0xdc, 0x9f, 0x7d, 0x97, 0x85, 0xd0, 0x16, 0x2a, 0x63, 0x2c, 0x79, 0x1a, + 0xce, 0xcf, 0x0c, 0x3b, 0x24, 0x2a, 0x39, 0x9f, 0x06, 0x1a, 0xc6, 0x49, + 0xf3, 0x86, 0xd4, 0x8d, 0x65, 0x77, 0x02, 0xc6, 0x35, 0x38, 0x97, 0x23, + 0x85, 0x7c, 0x6f, 0x5c, 0x0e, 0x78, 0xdd, 0xe7, 0x48, 0x40, 0xe5, 0x22, + 0xae, 0xef, 0x81, 0x02, 0xec, 0xc7, 0x0f, 0x12, 0x0f, 0x46, 0xd3, 0x7e, + 0x45, 0x17, 0xf7, 0xbe, 0x33, 0x84, 0x20, 0x08, 0xab, 0xdb, 0xa0, 0x01, + 0xcc, 0x8a, 0x0e, 0xfb, 0x81, 0x53, 0x44, 0x48, 0x07, 0xd5, 0x3e, 0xd2, + 0xcd, 0x3e, 0x6d, 0x00, 0x5d, 0x59, 0xeb, 0x15, 0x38, 0xb2, 0x49, 0x0e, + 0x85, 0x52, 0x93, 0x92, 0xd6, 0x27, 0x1f, 0x8f, 0x58, 0x54, 0x08, 0xc1, + 0x15, 0x66, 0x0a, 0x71, 0x6f, 0xe9, 0xf1, 0x5c, 0x3e, 0xcf, 0x9e, 0xde, + 0x1f, 0xdc, 0x79, 0xe9, 0xc1, 0x38, 0xa5, 0x3f, 0xe3, 0x60, 0x53, 0x0f, + 0xe6, 0xb3, 0x18, 0x67, 0x92, 0xff, 0x02, 0xa3, 0x20, 0x99, 0xda, 0xb2, + 0xa3, 0xa5, 0x72, 0x48, 0x1f, 0x76, 0x3e, 0xa2, 0x78, 0x37, 0xc2, 0xbf, + 0x00, 0x93, 0xdc, 0xa4, 0x96, 0xd1, 0xc8, 0xe9, 0xf1, 0xd2, 0xc7, 0x68, + 0x47, 0xdc, 0x36, 0x1c, 0x13, 0x34, 0xbd, 0xd9, 0x36, 0x9b, 0x70, 0x1a, + 0x56, 0x27, 0xd2, 0x7e, 0xe6, 0xd3, 0x74, 0x84, 0x24, 0x78, 0x68, 0xad, + 0x4c, 0x5e, 0xb9, 0xf2, 0x63, 0x80, 0x58, 0xc2, 0x93, 0xef, 0x7e, 0xf1, + 0xf7, 0x46, 0x4f, 0x89, 0xd3, 0x09, 0x07, 0x2c, 0x83, 0x44, 0x57, 0x7c, + 0x6d, 0x38, 0x27, 0x63, 0x22, 0x28, 0x55, 0xf5, 0x3e, 0xcb, 0x4d, 0x4f, + 0x4d, 0x82, 0x27, 0x96, 0x2d, 0xe9, 0x72, 0xeb, 0x86, 0x3a, 0x90, 0xa6, + 0xc4, 0x09, 0x6d, 0xbc, 0x13, 0x64, 0x58, 0x1e, 0xfc, 0xee, 0xee, 0x00, + 0x25, 0x92, 0x8d, 0x0b, 0x16, 0xf2, 0xd1, 0xd3, 0x2a, 0xb6, 0x00, 0xa3, + 0x4c, 0x58, 0xf9, 0x0b, 0x78, 0x9b, 0xc5, 0x11, 0xba, 0xa9, 0x36, 0xd7, + 0x74, 0xdd, 0x49, 0x30, 0x6d, 0x54, 0x6f, 0xb2, 0x0f, 0xf3, 0x7c, 0xc8, + 0x57, 0x55, 0x8e, 0x19, 0x09, 0x62, 0xaf, 0x34, 0x2e, 0x01, 0x65, 0xe3, + 0x15, 0x2c, 0xd6, 0x5f, 0x62, 0x50, 0xbf, 0xe9, 0xf6, 0x4a, 0xa8, 0x14, + 0x15, 0xe1, 0x22, 0xdc, 0x6d, 0x5e, 0x8b, 0x02, 0x86, 0x3d, 0xea, 0xcf, + 0x62, 0x9c, 0x70, 0xb1, 0x9e, 0x2e, 0x40, 0x62, 0x2d, 0x0d, 0x91, 0xac, + 0xaf, 0xcd, 0x3b, 0xa1, 0xf1, 0xfe, 0xaf, 0x16, 0xd4, 0xa3, 0xe5, 0x76, + 0xd9, 0x0e, 0x3e, 0x15, 0x59, 0x5d, 0x01, 0xc7, 0xf7, 0x57, 0xdb, 0x29, + 0x18, 0x03, 0x61, 0x00, 0xc5, 0x4b, 0xb1, 0x16, 0x3a, 0x9e, 0xa5, 0xc5, + 0x87, 0x88, 0x42, 0xda, 0xcd, 0x87, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, + 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x64, 0x6b, 0x75, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x7e, 0x00, + 0x0f, 0x7e, 0x0f, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x06, + 0x01, 0x34, 0x34, 0x29, 0x01, 0x03, 0x2c, 0xf0, 0xfa, 0xf2, 0x6b, 0xa9, + 0x12, 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, 0x72, 0xa1, 0x3b, + 0x0d, 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, 0x18, 0x44, 0x35, + 0x5b, 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, 0x4c, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, + 0x02, 0x42, 0x06, 0x01, 0x34, 0x34, 0x33, 0x09, 0x03, 0x2c, 0xf0, 0xfa, + 0xf2, 0x6b, 0xa9, 0x12, 0x4e, 0x73, 0x93, 0x45, 0x6c, 0x2f, 0x97, 0x33, + 0x72, 0xa1, 0x3b, 0x0d, 0x66, 0x6e, 0x37, 0x4b, 0xba, 0xaa, 0x65, 0x68, + 0x18, 0x44, 0x35, 0x5b, 0x9a, 0x6f, 0xf1, 0x3c, 0x2b, 0x18, 0x1f, 0xda, + 0x4c, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0f, 0xfb, 0x00, 0x51, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x61, 0x04, 0x23, 0x00, 0x07, 0x07, + 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, + 0x08, 0x08, 0x09, 0x89, 0x56, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, + 0x2b, 0xa8, 0x0d, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0xdf, + 0xb4, 0xb1, 0x32, 0xb5, 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, + 0x28, 0x81, 0xd3, 0x73, 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, + 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, + 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, + 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, + 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x4e, 0x6b, 0x19, 0x54, 0xf5, 0xf0, 0xaf, 0x61, + 0xfa, 0x1e, 0x1f, 0x1f, 0x5e, 0x17, 0xd3, 0x8e, 0x04, 0x4b, 0xfa, 0x8d, + 0x34, 0x55, 0x45, 0x92, 0xd5, 0xd0, 0xb8, 0x8e, 0x56, 0xe9, 0x39, 0x37, + 0x8e, 0x7d, 0x7e, 0x88, 0x56, 0x30, 0x48, 0x61, 0xb4, 0xed, 0x1e, 0x15, + 0x64, 0xfc, 0xa8, 0xb1, 0x02, 0xbb, 0x9c, 0x14, 0xe9, 0xd1, 0xe0, 0xcf, + 0x40, 0x41, 0x46, 0x5d, 0xb0, 0xda, 0xba, 0x8c, 0x3a, 0x41, 0x12, 0x91, + 0xeb, 0x13, 0xdf, 0x2c, 0x6e, 0x25, 0x75, 0xb3, 0x92, 0xff, 0xb0, 0xa9, + 0xa5, 0xef, 0x3a, 0x4c, 0x6b, 0x54, 0x55, 0x0e, 0x7e, 0x93, 0x16, 0x7f, + 0xe6, 0x22, 0x22, 0x51, 0xe2, 0x22, 0xa4, 0x35, 0x33, 0xec, 0xdc, 0xa8, + 0x73, 0x64, 0x59, 0xc1, 0x4d, 0xad, 0xa0, 0x56, 0xbf, 0xad, 0x45, 0x64, + 0xda, 0xb0, 0x08, 0x4a, 0x82, 0xfc, 0x0d, 0x21, 0xb7, 0x8b, 0x59, 0x90, + 0xac, 0xb2, 0x08, 0x1b, 0x50, 0x82, 0x0c, 0x87, 0xd6, 0x48, 0x5c, 0xdd, + 0x6b, 0x02, 0x7f, 0xab, 0x3e, 0xdc, 0x25, 0x1f, 0x53, 0x49, 0xb5, 0x6d, + 0x0f, 0x0c, 0xbe, 0xae, 0x1d, 0xab, 0x8b, 0x13, 0x9d, 0xd7, 0x6c, 0x91, + 0xaa, 0x90, 0xe8, 0x63, 0x06, 0x6d, 0xa8, 0xf0, 0xea, 0x21, 0xf6, 0xa8, + 0xfd, 0x15, 0x6d, 0x78, 0x66, 0x42, 0xae, 0x4c, 0xa7, 0x7a, 0x85, 0x15, + 0x7d, 0xf9, 0xed, 0x92, 0x1c, 0xde, 0x7c, 0x71, 0xd0, 0x6b, 0x25, 0x24, + 0x22, 0x6b, 0xe4, 0x5e, 0x60, 0xda, 0xbd, 0x95, 0x32, 0x21, 0xe8, 0xb1, + 0xcb, 0x07, 0x1b, 0x08, 0xf5, 0x49, 0x4f, 0x60, 0x8c, 0xe8, 0xb0, 0x71, + 0x2a, 0x8b, 0x91, 0x17, 0x16, 0x93, 0x39, 0x49, 0x8d, 0x47, 0x1f, 0xe8, + 0x2b, 0x12, 0xa6, 0x4f, 0xa1, 0x77, 0x37, 0xe7, 0x39, 0x68, 0x5c, 0x68, + 0x2b, 0xad, 0xa8, 0x3c, 0xa0, 0x8a, 0xf5, 0xb7, 0x51, 0x9f, 0x2d, 0x85, + 0x1a, 0x99, 0x02, 0x4c, 0x84, 0x5f, 0x4d, 0xe6, 0x55, 0x64, 0xd7, 0x5b, + 0x00, 0x48, 0xde, 0xf2, 0x77, 0x39, 0x6e, 0x7b, 0x0e, 0x97, 0x81, 0xd2, + 0x8a, 0x1b, 0x20, 0x30, 0x60, 0xbe, 0x94, 0xf0, 0x09, 0x34, 0xfe, 0x64, + 0xbb, 0xbb, 0xcb, 0x97, 0x91, 0x43, 0x6d, 0x57, 0x45, 0x7d, 0xc5, 0x43, + 0x5a, 0x78, 0x0d, 0xd8, 0xb9, 0xf5, 0x43, 0x13, 0x21, 0xd6, 0x31, 0x6e, + 0x21, 0x9a, 0x3f, 0x8f, 0xe2, 0x57, 0x32, 0xdb, 0x50, 0x61, 0x45, 0x9f, + 0xb9, 0x7b, 0x73, 0x10, 0xb9, 0xd0, 0x66, 0xaf, 0xa0, 0x3a, 0x77, 0x93, + 0x9b, 0xd3, 0x32, 0xb0, 0xda, 0x01, 0x17, 0x90, 0x1a, 0xa5, 0x9f, 0x2b, + 0x9f, 0x8f, 0x93, 0x6e, 0x4d, 0x69, 0x40, 0xec, 0x56, 0x76, 0x61, 0x2d, + 0xcd, 0xdf, 0xc5, 0xfe, 0x9e, 0x26, 0x2f, 0x78, 0x78, 0xab, 0x5a, 0x32, + 0xa6, 0xe9, 0x7a, 0x85, 0x15, 0xc6, 0x2f, 0x10, 0x37, 0x35, 0xf6, 0xfa, + 0xc0, 0xdd, 0xb0, 0xa9, 0xa1, 0x0d, 0x22, 0xc1, 0xab, 0xc8, 0x8c, 0x2a, + 0x77, 0x0b, 0xd3, 0x52, 0xdb, 0x53, 0x33, 0x78, 0xf3, 0xf6, 0x33, 0x5d, + 0x9f, 0xb7, 0xb6, 0x46, 0xf6, 0x79, 0x9e, 0x08, 0x16, 0xd8, 0x48, 0xcf, + 0x70, 0x4d, 0x00, 0x36, 0x30, 0xdb, 0xb3, 0x76, 0xa5, 0x16, 0x78, 0xf8, + 0xaf, 0x71, 0x6b, 0x50, 0x92, 0xfc, 0x52, 0xd6, 0x2c, 0xee, 0xa8, 0xb0, + 0xbe, 0x89, 0x18, 0xc0, 0x7a, 0x72, 0xa5, 0x36, 0x31, 0x7b, 0x86, 0xca, + 0xc0, 0xe4, 0x08, 0x17, 0x1d, 0x6e, 0xe5, 0x4c, 0x82, 0x86, 0x3e, 0x8c, + 0x60, 0xf7, 0x04, 0x8f, 0x2c, 0x64, 0x3d, 0x2e, 0x23, 0x22, 0x10, 0x8e, + 0x88, 0x45, 0xcd, 0x18, 0xd6, 0xba, 0x4c, 0x40, 0x1e, 0x31, 0xfb, 0xbf, + 0xda, 0xe7, 0xae, 0x87, 0x72, 0x81, 0xb2, 0x69, 0x97, 0xe3, 0x2c, 0x5e, + 0xbb, 0x26, 0x1b, 0xe2, 0x83, 0xf3, 0x90, 0x37, 0x0d, 0xb1, 0xa2, 0x58, + 0x88, 0x63, 0xe7, 0x6e, 0x4a, 0xbd, 0x76, 0x90, 0x73, 0x65, 0x85, 0x96, + 0xcc, 0x2d, 0xb7, 0x51, 0x0d, 0xa7, 0x8a, 0xe2, 0x8c, 0x47, 0xb9, 0x44, + 0x09, 0xc3, 0x8f, 0x24, 0x65, 0x79, 0xf0, 0xd0, 0xc3, 0xa5, 0x1f, 0xc3, + 0xca, 0xd7, 0x57, 0xac, 0x1c, 0xcf, 0xa9, 0xfc, 0x81, 0x12, 0x53, 0x0b, + 0xe5, 0x9d, 0x38, 0x29, 0x14, 0xd6, 0xf5, 0x17, 0x06, 0xfb, 0xc2, 0x9d, + 0x25, 0x10, 0xf9, 0xde, 0x4b, 0x33, 0x0d, 0xf1, 0xdd, 0xf5, 0xbc, 0xa8, + 0x2b, 0xdc, 0xdb, 0x51, 0x7d, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, + 0x75, 0x85, 0x41, 0x03, 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, + 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, + 0x16, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0x41, + 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, + 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, + 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, + 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, + 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, + 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0xe3, 0xb5, 0xfb, 0x0d, 0xa0, 0x75, 0xd1, 0xa9, 0x33, 0x31, 0xc6, 0x84, + 0xba, 0x58, 0x50, 0xb0, 0x71, 0x32, 0x4f, 0x72, 0x88, 0x46, 0x71, 0x06, + 0xb3, 0x82, 0x5e, 0x30, 0xfd, 0xc8, 0x5b, 0xc8, 0xf3, 0x24, 0x92, 0xe0, + 0xce, 0x8b, 0xf7, 0x50, 0x20, 0xc3, 0xeb, 0x1b, 0xf4, 0xef, 0x4f, 0xfa, + 0x28, 0x4d, 0x02, 0x4d, 0x7c, 0x46, 0xf1, 0x91, 0x89, 0xde, 0xc6, 0xfa, + 0x79, 0xc5, 0xbd, 0x17, 0xa1, 0xc6, 0x1d, 0x8c, 0xd4, 0x57, 0xa6, 0x58, + 0x66, 0xce, 0xe5, 0xb0, 0x8b, 0x54, 0xef, 0x3b, 0x24, 0x9b, 0xa4, 0xc4, + 0x6a, 0xa9, 0xf3, 0x1b, 0x73, 0x37, 0x10, 0xc0, 0xe1, 0xcb, 0xc8, 0x90, + 0x14, 0x88, 0x97, 0x25, 0x8b, 0x7c, 0xa2, 0x66, 0x36, 0x89, 0x55, 0x8d, + 0x68, 0xe7, 0x55, 0x20, 0x10, 0x68, 0x14, 0x2f, 0x05, 0x3b, 0xe3, 0x81, + 0x08, 0xfe, 0x54, 0x7d, 0xa5, 0x51, 0x2a, 0x39, 0x86, 0x11, 0xce, 0x26, + 0x8d, 0xe1, 0xec, 0x30, 0x3f, 0xf9, 0xa3, 0x3d, 0x43, 0x6c, 0xad, 0x23, + 0x54, 0x20, 0x7d, 0x60, 0xa5, 0x42, 0xbd, 0x3d, 0x22, 0xc8, 0x95, 0x9b, + 0xab, 0x5b, 0xf7, 0xc1, 0x11, 0xfb, 0xf1, 0x70, 0xa2, 0x43, 0xcb, 0x53, + 0x8c, 0x18, 0x0d, 0x8a, 0xb2, 0xa5, 0xbd, 0x87, 0x2b, 0x8b, 0xdf, 0x79, + 0x96, 0x29, 0x20, 0x8e, 0x34, 0x4a, 0x45, 0x96, 0x33, 0x8d, 0xa8, 0xb0, + 0x47, 0x26, 0x4f, 0x8b, 0xad, 0xb5, 0xa7, 0x2d, 0x15, 0x58, 0x92, 0x7b, + 0x4b, 0x53, 0xa9, 0x5e, 0x51, 0x39, 0x9c, 0xbd, 0x7e, 0x8f, 0x7f, 0x9f, + 0xb7, 0x38, 0xcd, 0x7e, 0xff, 0x7d, 0x73, 0x1f, 0xab, 0x3a, 0x61, 0xaa, + 0xde, 0x73, 0x28, 0xb2, 0x6f, 0x1e, 0xc9, 0x5e, 0x59, 0x71, 0x6b, 0xe8, + 0x6d, 0x63, 0xf3, 0x9e, 0xdf, 0x52, 0x86, 0x60, 0x1c, 0xbd, 0xc7, 0xeb, + 0xaf, 0x82, 0x83, 0xaa, 0x68, 0xa6, 0x71, 0x7a, 0xe8, 0xd3, 0xd4, 0xc8, + 0xe7, 0x9a, 0xcc, 0x3c, 0xc2, 0xdf, 0x0c, 0x42, 0xe8, 0xae, 0xc7, 0xd8, + 0x1f, 0x66, 0x0a, 0x57, 0x09, 0x14, 0x02, 0x74, 0x9a, 0x7a, 0x07, 0xb3, + 0x19, 0x87, 0x8d, 0xa9, 0x45, 0x25, 0x26, 0x48, 0xb3, 0x20, 0x3c, 0xf7, + 0x5a, 0x1c, 0xae, 0xc7, 0x06, 0x9e, 0x1a, 0x0a, 0x23, 0xf3, 0x39, 0x25, + 0x2c, 0x91, 0x7c, 0x5e, 0x87, 0xe7, 0x55, 0xc4, 0x69, 0xf3, 0x3e, 0xeb, + 0xc5, 0x44, 0xa8, 0xe3, 0xec, 0xc1, 0xfe, 0x70, 0xbf, 0xdd, 0xbb, 0xf0, + 0x22, 0xe1, 0x19, 0xa1, 0x6d, 0x7a, 0x9a, 0xa3, 0x36, 0x90, 0xbc, 0x1a, + 0xa7, 0x37, 0xf8, 0xcf, 0xdc, 0x9e, 0x23, 0x17, 0x42, 0xd5, 0xa0, 0xd3, + 0x36, 0xb0, 0xb1, 0xf5, 0x1a, 0x95, 0xbc, 0xe8, 0x0f, 0xb4, 0x58, 0x76, + 0x40, 0x74, 0xd0, 0x21, 0xaf, 0xae, 0xc6, 0xb4, 0x84, 0xd7, 0xfc, 0x70, + 0x6a, 0x8f, 0x41, 0x57, 0x2b, 0x8e, 0xbc, 0x6b, 0x21, 0x65, 0xcc, 0xa0, + 0x8e, 0xb9, 0x0b, 0x46, 0xef, 0xb3, 0x56, 0xec, 0x8a, 0xd6, 0x4d, 0xdd, + 0x97, 0xbd, 0xdd, 0x65, 0xbf, 0x26, 0xab, 0xba, 0x0d, 0xd1, 0x22, 0x7e, + 0xb6, 0x8a, 0xb4, 0x92, 0xc9, 0xa6, 0x48, 0xd4, 0x64, 0x17, 0xc6, 0xb5, + 0xb9, 0xce, 0x45, 0x6d, 0xf4, 0xd9, 0x3d, 0xa0, 0xb3, 0x86, 0x67, 0x19, + 0xad, 0xd8, 0x32, 0x2b, 0xf7, 0xab, 0x90, 0xee, 0x91, 0x8f, 0x73, 0xe4, + 0xc0, 0x29, 0xde, 0x45, 0x8a, 0xfb, 0xca, 0x74, 0x3b, 0x50, 0xf1, 0x34, + 0x40, 0x36, 0x25, 0x8a, 0xe0, 0xf9, 0x7f, 0x55, 0xc5, 0x59, 0x89, 0xbb, + 0x43, 0x03, 0xa3, 0xdd, 0x8c, 0x83, 0x03, 0xc6, 0xef, 0x60, 0x02, 0xc5, + 0xd8, 0x29, 0x3f, 0x2f, 0x56, 0xba, 0x8b, 0x97, 0x0a, 0xc4, 0xf3, 0x07, + 0x3f, 0xca, 0x0f, 0xdf, 0xb9, 0x5d, 0x59, 0x42, 0x36, 0x02, 0xf7, 0x0f, + 0x03, 0xc8, 0xf2, 0xb7, 0xd8, 0x64, 0xcd, 0x1e, 0xe4, 0xe1, 0xa0, 0xbd, + 0x0f, 0x70, 0xfb, 0xcf, 0x77, 0x77, 0xef, 0x9d, 0xdd, 0xc1, 0x61, 0xab, + 0x3c, 0xdb, 0xe4, 0x35, 0x11, 0xab, 0xde, 0x40, 0x7d, 0x51, 0xba, 0xb1, + 0x7d, 0x13, 0xf1, 0x58, 0x03, 0xca, 0xae, 0x12, 0x4a, 0xa3, 0xb6, 0xed, + 0xd7, 0x18, 0x1c, 0xb6, 0xd8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, + 0x75, 0x89, 0x70, 0x02, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, + 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x91, + 0x62, 0x29, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x41, + 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x37, 0xee, 0x5a, 0x85, 0xe1, + 0xcb, 0xdd, 0xc8, 0xce, 0x07, 0x77, 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, + 0x30, 0x3a, 0xcd, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, + 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, + 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, + 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0xfa, 0x4b, 0x92, 0xea, 0x4b, 0xef, 0xde, 0x03, 0xd5, 0xe2, 0xee, 0xe5, + 0x67, 0xd4, 0x99, 0x63, 0x37, 0x68, 0x91, 0xbc, 0x4f, 0xbc, 0x41, 0xe9, + 0x01, 0xc5, 0x4d, 0x59, 0x2a, 0x9b, 0x42, 0x60, 0x07, 0x7e, 0xc2, 0xbc, + 0x62, 0xcc, 0xbc, 0xa7, 0xf1, 0xe4, 0x20, 0x5f, 0xe3, 0xe8, 0x9f, 0x16, + 0x7a, 0x77, 0xd2, 0xb7, 0xad, 0x98, 0xc3, 0xb4, 0x99, 0xdb, 0x36, 0x1a, + 0xe4, 0xf0, 0xfc, 0xe1, 0xc8, 0x2f, 0x8c, 0xcf, 0x6f, 0x97, 0x48, 0x09, + 0x4a, 0xae, 0xc7, 0xf9, 0xfb, 0xb7, 0x5f, 0x64, 0x6a, 0x79, 0xa1, 0x27, + 0xeb, 0x59, 0x7d, 0x0a, 0xd3, 0x56, 0x27, 0x1d, 0x56, 0xd3, 0x62, 0x1e, + 0x7f, 0xb5, 0x0f, 0x50, 0x9c, 0x4d, 0x1d, 0xd5, 0x53, 0xcb, 0x08, 0x07, + 0x56, 0x93, 0x9e, 0x4f, 0xb2, 0xd0, 0x12, 0xc7, 0x50, 0xcf, 0x99, 0xac, + 0x24, 0xdb, 0x94, 0xab, 0x08, 0x89, 0x60, 0x2f, 0x6c, 0xd0, 0xc2, 0x2e, + 0x6d, 0x08, 0xe0, 0xf9, 0xfc, 0x7e, 0x5b, 0x54, 0x92, 0xaa, 0x01, 0xfd, + 0xf6, 0x49, 0xb1, 0xfc, 0xd4, 0x51, 0x83, 0x73, 0xaf, 0xac, 0x38, 0x78, + 0x8e, 0x9b, 0x42, 0x4e, 0x83, 0xbb, 0x9d, 0xd7, 0x5c, 0xdb, 0x73, 0xd3, + 0x3d, 0x2c, 0xe2, 0x4c, 0x57, 0xa4, 0xfa, 0xdf, 0x53, 0x44, 0x29, 0x71, + 0x22, 0xb6, 0x89, 0x84, 0x80, 0xca, 0xcb, 0x7c, 0x5f, 0x15, 0x19, 0x4b, + 0x06, 0x28, 0x5d, 0x4a, 0x9b, 0xc8, 0x59, 0xa7, 0x9e, 0xa2, 0xba, 0x32, + 0x5d, 0xf2, 0xcb, 0xa9, 0xc6, 0xba, 0x09, 0xee, 0xd2, 0x00, 0x32, 0x53, + 0x8b, 0x39, 0xff, 0xc4, 0x63, 0xac, 0xbc, 0x1c, 0x15, 0xb8, 0x79, 0xc2, + 0xe3, 0xda, 0x8d, 0xb2, 0x95, 0x8d, 0x3c, 0x10, 0xec, 0x93, 0x03, 0xc1, + 0x07, 0x84, 0x47, 0xf3, 0xeb, 0xe3, 0x10, 0x33, 0xa1, 0x2e, 0xc6, 0x48, + 0x44, 0x2c, 0x38, 0x36, 0xe1, 0x68, 0x3c, 0xe8, 0x0d, 0x5c, 0x8a, 0xdc, + 0x1f, 0xe8, 0x3b, 0xb2, 0x0f, 0xea, 0x27, 0x18, 0x7a, 0x7f, 0x82, 0x6a, + 0x96, 0xfa, 0x63, 0xd3, 0x5c, 0xbf, 0xf6, 0x1d, 0x9e, 0xf2, 0xd9, 0x83, + 0x3b, 0xf0, 0x1b, 0x29, 0x49, 0x8d, 0xb3, 0xdc, 0x60, 0x47, 0x9d, 0x2b, + 0xac, 0xd6, 0x6e, 0x59, 0xb3, 0x09, 0x0d, 0xa7, 0xfb, 0x0e, 0x43, 0x56, + 0xa3, 0x80, 0x2c, 0x9f, 0xc1, 0xe8, 0xd2, 0xef, 0x05, 0xc5, 0x25, 0x4c, + 0x5b, 0x67, 0x1a, 0x54, 0x0b, 0x55, 0x83, 0x3d, 0xfb, 0x38, 0x0e, 0xd2, + 0xc0, 0x1a, 0xcd, 0x9f, 0x81, 0x3e, 0x6d, 0x7f, 0xe4, 0x3f, 0x34, 0x0c, + 0xdc, 0x99, 0x5a, 0x77, 0xd4, 0xe4, 0xff, 0x4a, 0x7b, 0x8a, 0x95, 0xe4, + 0x46, 0x3d, 0x7b, 0xc4, 0x0e, 0xdd, 0xc7, 0x2d, 0xf4, 0xfa, 0x5e, 0x50, + 0xae, 0x9c, 0xca, 0x64, 0x97, 0xad, 0x03, 0x30, 0x3e, 0x05, 0xc4, 0x33, + 0x1e, 0x2c, 0x03, 0x2b, 0x06, 0x2c, 0x79, 0x13, 0xae, 0x1b, 0x65, 0xf1, + 0x1f, 0xb9, 0xe4, 0x8a, 0x06, 0x96, 0xea, 0xc4, 0x6e, 0x17, 0x19, 0x03, + 0x54, 0xe8, 0x39, 0xe7, 0xeb, 0x7b, 0xbc, 0x25, 0xd6, 0x55, 0x6c, 0x76, + 0x5f, 0xf7, 0xd2, 0x0e, 0x54, 0x46, 0x9f, 0x5d, 0xa4, 0x3d, 0xac, 0xa1, + 0x19, 0x7b, 0x7c, 0x5a, 0x44, 0x54, 0x65, 0x5d, 0x43, 0x26, 0x5f, 0x47, + 0x63, 0x2b, 0x00, 0xe3, 0xb4, 0xe9, 0x70, 0x8c, 0x31, 0x50, 0x7c, 0x37, + 0x01, 0x43, 0x6c, 0x29, 0xc3, 0xae, 0x59, 0xb7, 0x0b, 0xb9, 0x9a, 0x72, + 0x69, 0xe0, 0xd1, 0xb0, 0x47, 0x53, 0xf0, 0xb8, 0x8b, 0xc8, 0x80, 0x3c, + 0x58, 0xfa, 0x34, 0xf2, 0x44, 0x27, 0xb7, 0xfc, 0x44, 0x73, 0xfb, 0xe5, + 0xe1, 0x8b, 0xdb, 0x2b, 0xc5, 0x73, 0x97, 0x25, 0xb3, 0xef, 0x16, 0xfd, + 0xba, 0x08, 0x3d, 0x15, 0x2a, 0x03, 0xb5, 0x4d, 0x2a, 0x8c, 0xf5, 0x53, + 0x11, 0x97, 0x3c, 0x35, 0x66, 0x1d, 0x59, 0xc8, 0xc9, 0x79, 0x48, 0x6d, + 0x19, 0x4f, 0xa7, 0x07, 0x25, 0x4d, 0xb2, 0xfc, 0x1e, 0xbc, 0x9a, 0x0c, + 0x6e, 0x46, 0x2b, 0x58, 0x45, 0xbe, 0xe7, 0x8e, 0x09, 0xa5, 0xa0, 0xd3, + 0x5a, 0xf5, 0x6e, 0x92, 0x7b, 0x5b, 0x21, 0x07, 0xab, 0xf3, 0x57, 0xd6, + 0x93, 0x4b, 0x56, 0x3b, 0x9c, 0x3c, 0x4b, 0x85, 0xb0, 0x62, 0x18, 0x3e, + 0x7c, 0xc5, 0x25, 0xe2, 0xf2, 0xfc, 0xa3, 0xca, 0x88, 0xd6, 0xb2, 0x01, + 0x11, 0xcd, 0x93, 0x9a, 0x76, 0x84, 0xc2, 0x2d, 0x07, 0xd3, 0xbb, 0xac, + 0x99, 0xde, 0x29, 0x00, 0xf7, 0x3d, 0x06, 0xea, 0xdc, 0x88, 0xfd, 0xc6, + 0x6e, 0xf5, 0x55, 0x64, 0x73, 0x4e, 0x3b, 0xa9, 0x24, 0x44, 0x63, 0x1c, + 0x50, 0x29, 0x66, 0xc4, 0x74, 0x70, 0xcb, 0xd8, 0x57, 0x0c, 0x60, 0x50, + 0x6d, 0x64, 0x64, 0xd1, 0x53, 0xef, 0x62, 0xef, 0x61, 0xf4, 0xe2, 0xfe, + 0x4c, 0xaa, 0x9f, 0xe9, 0x81, 0x01, 0xe1, 0x97, 0xaa, 0xc0, 0x06, 0xbf, + 0x40, 0x19, 0x64, 0x24, 0x6e, 0x80, 0x73, 0x00, 0x5c, 0x86, 0x3e, 0xc2, + 0xcf, 0x8c, 0x09, 0xc0, 0xfa, 0x4a, 0xb3, 0x3a, 0x0d, 0x81, 0x1d, 0x49, + 0x58, 0x09, 0xe8, 0x31, 0x0e, 0xd7, 0x60, 0x8d, 0x9d, 0xfe, 0x9f, 0x35, + 0xf7, 0x8d, 0xa1, 0x12, 0x04, 0xb2, 0x47, 0xac, 0x31, 0x92, 0x03, 0x0a, + 0x10, 0x50, 0xb7, 0x86, 0x3d, 0xcd, 0x15, 0x8f, 0x25, 0x93, 0x24, 0x7a, + 0x5f, 0xa0, 0x3c, 0x41, 0xaa, 0xb2, 0x96, 0xce, 0xd3, 0x0c, 0xe9, 0x55, + 0x66, 0x37, 0x5c, 0xf3, 0x02, 0x3c, 0xa1, 0x09, 0xa4, 0x9e, 0x90, 0xc9, + 0x82, 0xab, 0xd4, 0x04, 0x2e, 0x8b, 0xb4, 0x8d, 0x5b, 0xcc, 0x19, 0x5a, + 0xfe, 0x86, 0x9c, 0x6c, 0x56, 0x09, 0x86, 0x36, 0xef, 0xe8, 0x1f, 0x3a, + 0xbc, 0xda, 0x4c, 0x68, 0xac, 0xa2, 0x1b, 0xd1, 0x23, 0x75, 0x28, 0xed, + 0x9f, 0x84, 0x2e, 0x40, 0x57, 0x5f, 0x0a, 0x85, 0xe4, 0x77, 0x59, 0x53, + 0x12, 0x32, 0xd6, 0x3c, 0x1b, 0xaf, 0x95, 0xa1, 0x1c, 0x14, 0x1a, 0x42, + 0x7d, 0xc7, 0x7b, 0x21, 0xd1, 0x4e, 0xb9, 0x29, 0x85, 0xef, 0xa2, 0x61, + 0x1c, 0xe5, 0x16, 0x44, 0xbe, 0xfb, 0xa3, 0x21, 0x4f, 0x94, 0x70, 0xff, + 0x5c, 0xc2, 0x1d, 0x0b, 0x39, 0x36, 0x84, 0x0e, 0x61, 0xe2, 0x1c, 0x63, + 0x74, 0xe0, 0x30, 0x01, 0xbe, 0x39, 0x0f, 0x6f, 0xe6, 0x29, 0xad, 0xd8, + 0x8c, 0xdd, 0x8b, 0x24, 0x38, 0x6f, 0x67, 0x8a, 0x2d, 0x82, 0x1e, 0x8e, + 0x45, 0xcb, 0xec, 0x2d, 0xe3, 0xb4, 0x03, 0x8e, 0x46, 0x2e, 0x01, 0xb0, + 0xca, 0x4f, 0xe0, 0x2c, 0x52, 0xd3, 0x4c, 0xdd, 0xd6, 0x62, 0xf3, 0x38, + 0x3f, 0x3c, 0xc1, 0x58, 0xaa, 0x87, 0x3d, 0x4f, 0xb2, 0xb1, 0x54, 0x65, + 0xdc, 0x1c, 0xc8, 0x16, 0x88, 0x15, 0x53, 0xb0, 0x4e, 0x77, 0xae, 0xe0, + 0x34, 0x18, 0x36, 0x34, 0x31, 0x74, 0x4c, 0x79, 0x0f, 0x2b, 0x1a, 0x11, + 0x06, 0x06, 0xaa, 0x60, 0x31, 0x6e, 0x65, 0x9e, 0x1b, 0xb0, 0x61, 0xd6, + 0x90, 0xd1, 0x1d, 0x4c, 0x36, 0xfe, 0xec, 0x26, 0xcc, 0xba, 0xce, 0xd7, + 0xe7, 0x0c, 0x53, 0x90, 0xe8, 0xce, 0xce, 0xed, 0x58, 0x37, 0x37, 0x3f, + 0x40, 0x39, 0xeb, 0x8c, 0xfb, 0x7d, 0x93, 0xa2, 0x26, 0x4e, 0xbf, 0x49, + 0xe7, 0x95, 0xc0, 0x12, 0x6a, 0xec, 0xfb, 0xbe, 0x00, 0x62, 0xb9, 0xc9, + 0x0d, 0x5a, 0x37, 0xf9, 0xae, 0x84, 0x95, 0x89, 0x20, 0x47, 0x48, 0xf6, + 0xf8, 0x73, 0x92, 0x5f, 0xe1, 0x4a, 0xb4, 0x9e, 0xd8, 0x75, 0xf3, 0x38, + 0x48, 0xe1, 0x29, 0x95, 0x0d, 0x74, 0x6b, 0x98, 0x96, 0x6e, 0xc9, 0x3f, + 0xfc, 0x44, 0x91, 0x4d, 0xf4, 0x4c, 0xb7, 0x38, 0xd7, 0xec, 0xbf, 0xf6, + 0x78, 0x05, 0x7d, 0x1b, 0xe5, 0x68, 0x8a, 0xbc, 0x6a, 0x6a, 0x29, 0xb6, + 0xc6, 0x9a, 0x8d, 0x7a, 0x0e, 0x00, 0x80, 0x73, 0xf5, 0x88, 0x5d, 0x2a, + 0xa2, 0x60, 0x98, 0x1e, 0xf5, 0x06, 0x3b, 0xef, 0xa9, 0x46, 0x6b, 0x89, + 0x24, 0xb0, 0xf4, 0x34, 0x42, 0x15, 0x87, 0xd3, 0xc9, 0x36, 0xe0, 0x52, + 0x5f, 0x57, 0x8e, 0x65, 0x5c, 0x7f, 0x7c, 0xf2, 0x66, 0xd8, 0xd1, 0xbf, + 0x13, 0x95, 0x65, 0xb0, 0x7a, 0xa0, 0xbb, 0xee, 0xc9, 0x20, 0xff, 0x26, + 0xda, 0xa0, 0x61, 0x65, 0xd5, 0x3c, 0xdf, 0xb5, 0xf0, 0xd2, 0x02, 0x4f, + 0x97, 0x65, 0x48, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x8a, 0x11, 0x01, 0x23, + 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, + 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x92, 0x1a, 0x33, 0x13, 0x41, 0xb7, + 0x59, 0x5c, 0x4b, 0x89, 0xf6, 0xba, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, + 0xf6, 0xba, 0xb1, 0x0a, 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, + 0xc7, 0x2e, 0xdb, 0x0f, 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x64, 0x14, + 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, + 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, + 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, + 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x12, 0x83, 0x28, 0x8c, 0xcd, + 0x78, 0x8c, 0x1b, 0x02, 0xa2, 0x38, 0xa7, 0x25, 0xc1, 0x25, 0x59, 0xcd, + 0x36, 0xb2, 0x21, 0xa1, 0x91, 0xd0, 0xc3, 0x54, 0x89, 0x64, 0xa8, 0x3d, + 0x07, 0xcb, 0x8f, 0xf7, 0xa6, 0x55, 0xc2, 0x96, 0xf6, 0x35, 0xc1, 0x67, + 0xdf, 0x2f, 0x1f, 0xda, 0xa8, 0xf8, 0x8c, 0xc9, 0xa7, 0x5e, 0x7f, 0x1f, + 0xa8, 0xd3, 0x38, 0x57, 0xa2, 0xf4, 0x57, 0x32, 0x17, 0xe3, 0x06, 0xe3, + 0xb6, 0x56, 0x60, 0x6e, 0xbe, 0x12, 0x60, 0x00, 0xfd, 0xa8, 0x4c, 0x3f, + 0x2b, 0x54, 0x9c, 0xfb, 0x87, 0x8b, 0xfa, 0x9e, 0xb8, 0xb2, 0x80, 0x36, + 0xf1, 0x5b, 0xcd, 0x9d, 0x74, 0xa1, 0x7b, 0xbf, 0xf6, 0x4c, 0x64, 0x58, + 0x67, 0x8b, 0x68, 0x05, 0x15, 0x7e, 0x4b, 0x54, 0xe9, 0x84, 0x59, 0x70, + 0x42, 0x80, 0x67, 0x6c, 0x45, 0x62, 0x12, 0x03, 0x27, 0x2b, 0x32, 0xdc, + 0x78, 0x85, 0x3d, 0x74, 0x28, 0x89, 0x5c, 0x33, 0x15, 0x79, 0x63, 0x1f, + 0xd7, 0x26, 0xbf, 0x5d, 0xf6, 0xb1, 0xb7, 0x9e, 0x37, 0x86, 0xd8, 0xf6, + 0xf9, 0xc3, 0x66, 0x90, 0x50, 0x5a, 0x0e, 0xeb, 0xcc, 0xe0, 0xf2, 0x19, + 0xbb, 0xd7, 0x6a, 0xe4, 0xea, 0x87, 0xf9, 0x17, 0x20, 0x88, 0xf6, 0xc0, + 0xc7, 0xb7, 0x55, 0x25, 0xef, 0x15, 0xec, 0xc5, 0x80, 0x52, 0x9a, 0x92, + 0xdb, 0x32, 0xf3, 0xc2, 0xa2, 0x55, 0xd6, 0xd9, 0x5b, 0xe6, 0xb1, 0x95, + 0x18, 0x2b, 0xf8, 0x94, 0x21, 0x56, 0x29, 0x30, 0xf3, 0x61, 0x39, 0x22, + 0x03, 0x86, 0xce, 0x81, 0x6d, 0x9e, 0xdb, 0x5b, 0x49, 0xdb, 0x2c, 0x1d, + 0x0d, 0x45, 0xa9, 0xb3, 0x1c, 0x1a, 0x43, 0x36, 0x1d, 0xd2, 0x76, 0x28, + 0x27, 0xe0, 0xd3, 0x19, 0x56, 0xd3, 0x52, 0xb2, 0xa0, 0x9c, 0xda, 0xb7, + 0xac, 0x4d, 0xb1, 0x98, 0x22, 0xa5, 0x86, 0x5d, 0x79, 0x6a, 0x69, 0x06, + 0xd7, 0x07, 0xe7, 0x44, 0x55, 0x6c, 0xc7, 0xd0, 0x8a, 0x2b, 0xa1, 0x45, + 0xc6, 0xbf, 0xf3, 0x21, 0x2e, 0x41, 0x5c, 0x84, 0xa2, 0x77, 0x46, 0x65, + 0x80, 0x75, 0xba, 0x49, 0xd6, 0xd7, 0x73, 0xeb, 0x35, 0x2c, 0x46, 0x58, + 0xc4, 0x1d, 0x2f, 0x6b, 0xe6, 0x6c, 0xa7, 0x5f, 0x95, 0x0c, 0xbc, 0x60, + 0x00, 0x3d, 0xa9, 0x0a, 0xd6, 0x0a, 0x66, 0x59, 0xc0, 0x9b, 0x49, 0x5b, + 0x4c, 0x73, 0xf5, 0x9e, 0x6d, 0x38, 0xdd, 0x0f, 0x25, 0xe4, 0x35, 0x84, + 0x34, 0x25, 0xfe, 0x71, 0x35, 0x78, 0xa7, 0x5b, 0xc1, 0x7a, 0xab, 0xd7, + 0xeb, 0x2f, 0x54, 0x93, 0x94, 0x49, 0x8a, 0x1e, 0x04, 0xe6, 0xfc, 0xd7, + 0xe3, 0xa2, 0x41, 0x25, 0x5a, 0xa5, 0x46, 0x59, 0x85, 0xfb, 0x21, 0xc7, + 0x02, 0x48, 0x79, 0xd4, 0xef, 0xc4, 0x03, 0xc2, 0x0a, 0x4b, 0x42, 0x1c, + 0x73, 0x35, 0xcd, 0x21, 0x8b, 0xd5, 0xfc, 0xa3, 0xdc, 0xbb, 0x4b, 0xa3, + 0x45, 0x04, 0x73, 0xa1, 0xdb, 0x3a, 0x97, 0x0e, 0xc7, 0x1c, 0xe2, 0x67, + 0x04, 0xd4, 0x49, 0x68, 0x0e, 0x05, 0xcb, 0x52, 0xd4, 0x37, 0x75, 0xd8, + 0x2a, 0x17, 0xd3, 0x7a, 0x93, 0x96, 0x46, 0xfb, 0x07, 0x6d, 0x3b, 0x92, + 0x60, 0xf4, 0x35, 0x94, 0x3b, 0xbd, 0x2e, 0xf6, 0x0b, 0x18, 0xd5, 0x0d, + 0x1b, 0xe1, 0xd3, 0x14, 0xc1, 0x84, 0xd7, 0x67, 0xd7, 0x96, 0x2d, 0xa9, + 0xab, 0x59, 0x70, 0x43, 0x7b, 0xea, 0x25, 0xa3, 0x05, 0x1c, 0x45, 0xf6, + 0x34, 0x51, 0x8e, 0xaf, 0x46, 0x33, 0x90, 0x68, 0x28, 0x4f, 0x38, 0x5b, + 0xbb, 0x69, 0xee, 0xbb, 0x0a, 0x4c, 0x76, 0x1c, 0x3d, 0xfd, 0xea, 0x1f, + 0x77, 0x9e, 0xd4, 0xa1, 0xeb, 0x74, 0x16, 0x60, 0x20, 0xe9, 0x44, 0xc1, + 0x90, 0x2c, 0x7b, 0x77, 0x6f, 0x70, 0xe3, 0x62, 0x0f, 0xc3, 0x20, 0xf6, + 0xce, 0xc3, 0xa6, 0x0e, 0x9c, 0x6d, 0xa3, 0xa0, 0x21, 0x1c, 0x28, 0x7f, + 0x44, 0xd7, 0xa9, 0x87, 0x62, 0x91, 0x4d, 0x2a, 0x93, 0xe2, 0xc7, 0x94, + 0x0c, 0x75, 0x1d, 0xf6, 0xc7, 0xf8, 0x36, 0x09, 0xa8, 0x23, 0xa3, 0x80, + 0x52, 0x2d, 0xe7, 0x0b, 0x44, 0x5d, 0x4b, 0xf5, 0xdc, 0x57, 0xa3, 0x02, + 0x40, 0x89, 0xdc, 0x40, 0xf7, 0x5c, 0xad, 0xea, 0x5c, 0x1a, 0x59, 0xfc, + 0xb8, 0xaf, 0xcb, 0x71, 0xe0, 0x08, 0xdc, 0x80, 0x08, 0x8a, 0x32, 0x85, + 0x46, 0xa9, 0x9a, 0x17, 0x6b, 0x25, 0x9c, 0xfe, 0x7d, 0x90, 0x22, 0x6e, + 0x7b, 0x01, 0x24, 0x17, 0xf6, 0xa7, 0x70, 0x93, 0x03, 0x60, 0xc2, 0x0d, + 0x7b, 0x3b, 0xe8, 0x5b, 0x02, 0xb0, 0x6d, 0x00, 0x62, 0x97, 0x1b, 0x84, + 0x86, 0x27, 0x72, 0x2d, 0x90, 0xee, 0xdc, 0xb6, 0xb8, 0xa5, 0x58, 0x73, + 0x29, 0x9b, 0x06, 0x99, 0xda, 0x4f, 0x12, 0x0c, 0x74, 0x0a, 0xc1, 0x1b, + 0x34, 0x20, 0xfa, 0x6d, 0x01, 0xd2, 0x1b, 0xf2, 0x0f, 0xe3, 0xfe, 0x34, + 0x2d, 0x44, 0x4f, 0xa3, 0x6a, 0xab, 0xaa, 0x7e, 0x1c, 0x35, 0xef, 0xfe, + 0xa0, 0xc1, 0x8a, 0xeb, 0x77, 0x80, 0xd6, 0x57, 0x20, 0x2e, 0x2b, 0xeb, + 0x67, 0xa0, 0x82, 0x86, 0xc8, 0x0e, 0x70, 0x76, 0x74, 0x52, 0x3e, 0x67, + 0x96, 0xf0, 0x48, 0x3f, 0x9b, 0xdc, 0x5f, 0x36, 0xd9, 0xae, 0x3a, 0xcb, + 0x57, 0x5d, 0xe0, 0x7c, 0x03, 0xa9, 0xe8, 0x88, 0x13, 0x6a, 0x70, 0x94, + 0x4b, 0xf5, 0x92, 0x8f, 0xc0, 0x34, 0x49, 0x3f, 0xf7, 0xe1, 0x59, 0xc4, + 0xf2, 0xae, 0x7a, 0x88, 0x58, 0x39, 0x74, 0x39, 0x6d, 0xaf, 0x7a, 0xec, + 0xaf, 0x44, 0x0e, 0x11, 0x7d, 0xa8, 0x3c, 0x50, 0x5b, 0x64, 0x8d, 0x8a, + 0x21, 0x59, 0xc6, 0x8c, 0x6c, 0xce, 0x05, 0xad, 0x1c, 0x2f, 0x5e, 0x4a, + 0xa3, 0x2a, 0x46, 0x3a, 0xaa, 0x12, 0x7e, 0xcc, 0x82, 0xb6, 0x62, 0xba, + 0xe6, 0x1a, 0x52, 0xc6, 0xe3, 0x96, 0x71, 0xf6, 0x81, 0x21, 0x46, 0xd0, + 0x3f, 0x5d, 0xa1, 0x37, 0x8b, 0xf5, 0xc7, 0x8c, 0x28, 0xf0, 0x2e, 0xe8, + 0x44, 0x25, 0x48, 0x27, 0x8e, 0x2f, 0x65, 0x83, 0xed, 0xf5, 0xb6, 0x9f, + 0x02, 0xa7, 0x1b, 0x1e, 0x90, 0x01, 0x55, 0x88, 0xe5, 0xdf, 0x0e, 0x7e, + 0x16, 0x66, 0xa1, 0xc6, 0x07, 0xf6, 0xb5, 0x84, 0x8d, 0x60, 0x6b, 0xe2, + 0xad, 0xbd, 0x18, 0x39, 0xe5, 0xd2, 0xd9, 0xe0, 0xab, 0xc2, 0xac, 0x2f, + 0x36, 0x24, 0x03, 0x69, 0x4c, 0xf9, 0xf3, 0x67, 0x8f, 0xf6, 0x8b, 0xde, + 0xf9, 0x7c, 0x14, 0xfa, 0x97, 0xc3, 0xe5, 0xc1, 0x7d, 0xcf, 0x16, 0x24, + 0x26, 0xda, 0xde, 0x5c, 0x70, 0x96, 0x90, 0xd9, 0x06, 0x2f, 0xf9, 0x61, + 0xa3, 0x47, 0x19, 0x50, 0x5e, 0xe2, 0xb6, 0x74, 0x5e, 0x55, 0xe6, 0x89, + 0xaa, 0xde, 0x19, 0x27, 0x26, 0x47, 0x95, 0x7b, 0xf0, 0x09, 0x21, 0xa9, + 0xf3, 0xf2, 0xf0, 0xbc, 0x1a, 0xa2, 0x25, 0x77, 0x3f, 0x8a, 0x57, 0x20, + 0xfc, 0x48, 0x45, 0xd8, 0x8b, 0xcb, 0x33, 0x04, 0x10, 0x1d, 0xc6, 0x4b, + 0x4c, 0xe4, 0x92, 0x1f, 0xef, 0x27, 0x5e, 0xd5, 0xac, 0xab, 0xcc, 0x69, + 0xbe, 0xd6, 0x35, 0x0e, 0x0d, 0x96, 0x99, 0x3b, 0x67, 0x8d, 0x33, 0xa0, + 0xe3, 0x16, 0xcc, 0x4a, 0x29, 0x80, 0xc8, 0x47, 0xd1, 0x0c, 0xb1, 0xa0, + 0xc1, 0xbe, 0xcc, 0x16, 0xab, 0xf7, 0xee, 0x8a, 0x77, 0xef, 0xca, 0x08, + 0x82, 0x0a, 0x9e, 0x11, 0xcf, 0x3c, 0xbb, 0x1b, 0x44, 0x96, 0xd1, 0x5e, + 0x65, 0xf9, 0xe7, 0xc7, 0xa1, 0x94, 0x42, 0xa9, 0x0e, 0x36, 0x9a, 0x5b, + 0x7f, 0xf0, 0x91, 0x95, 0xeb, 0xd1, 0xb6, 0x1d, 0x18, 0x44, 0x93, 0xa4, + 0xc1, 0x31, 0x97, 0x07, 0x09, 0x9b, 0x50, 0xae, 0xf3, 0x74, 0x7f, 0xbe, + 0x0d, 0xc2, 0xc3, 0x11, 0x8f, 0xa1, 0xea, 0x1f, 0x4e, 0x84, 0x94, 0x18, + 0x7e, 0x7c, 0xbd, 0xe6, 0xc9, 0x78, 0x0e, 0x39, 0x1e, 0x1a, 0x71, 0xc4, + 0xbc, 0x5c, 0x99, 0x76, 0xf7, 0x26, 0x66, 0x9c, 0x8f, 0xd4, 0xad, 0xa9, + 0x6e, 0x96, 0xb9, 0x54, 0x5b, 0xae, 0xa2, 0x0d, 0x94, 0xa8, 0x5a, 0x34, + 0xc3, 0xdb, 0x52, 0x59, 0x3f, 0xdd, 0x53, 0x72, 0xfc, 0xf6, 0x1d, 0x3c, + 0xe0, 0x1f, 0x4a, 0xee, 0xf5, 0x74, 0xa5, 0x95, 0x7a, 0x5d, 0x75, 0xbd, + 0x27, 0x4a, 0x49, 0x18, 0xcf, 0xf0, 0xe5, 0x32, 0x4f, 0x1b, 0xa0, 0xeb, + 0x00, 0x19, 0x21, 0xbd, 0xf7, 0xf5, 0x4b, 0x47, 0x1d, 0x3b, 0x8b, 0xe6, + 0xca, 0xdc, 0xb6, 0x52, 0x41, 0xa7, 0xab, 0x68, 0xb3, 0xfb, 0x8f, 0x40, + 0xc3, 0x59, 0xd9, 0x2d, 0x13, 0x3a, 0x99, 0x93, 0x9f, 0xa6, 0x90, 0xdd, + 0x65, 0x17, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x00, 0x00, 0x00, 0x1d, 0x04, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x6a, 0x00, 0x0f, 0x2a, 0x0e, 0xaa, + 0x0f, 0x6a, 0x0f, 0xb3, 0x0e, 0xea, 0x0e, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x0c, 0x09, 0x34, 0x34, 0x08, + 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, + 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, + 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, + 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, + 0x05, 0x00, 0x05, 0x00, 0x69, 0x63, 0x68, 0x61, 0x74, 0x06, 0x3f, 0x0c, + 0x08, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0xfc, + 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, + 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, 0x05, 0x00, 0x69, 0x63, 0x68, 0x61, + 0x74, 0x05, 0x3f, 0x0c, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, + 0x08, 0x17, 0x01, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, + 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, + 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, + 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, + 0x69, 0x63, 0x68, 0x61, 0x74, 0x04, 0x3f, 0x0c, 0x08, 0x34, 0x34, 0x08, + 0x01, 0x02, 0x02, 0x08, 0x08, 0x17, 0x01, 0x9b, 0x66, 0x83, 0xaf, 0x24, + 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, + 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, + 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, + 0x01, 0x00, 0x01, 0x00, 0x69, 0x63, 0x68, 0x61, 0x74, 0x03, 0x48, 0x0c, + 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x29, 0x01, 0x64, + 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, + 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x02, 0x4c, + 0x0c, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x33, 0x09, + 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, + 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, + 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x6c, 0x6f, 0x63, + 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x69, 0x65, 0x73, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xfb, 0x00, + 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x01, 0x05, 0x0a, 0x00, 0x00, 0x00, + 0x02, 0x0f, 0xf7, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x03, 0x03, 0x00, 0x09, + 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xcf, 0x00, 0x0f, 0xe8, 0x0f, 0xcf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0x7e, 0x0b, 0xaa, 0xec, 0xd2, + 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, 0x20, + 0x84, 0xa7, 0x17, 0x02, 0x17, 0x03, 0x34, 0x09, 0x7e, 0x0b, 0xaa, 0xec, + 0xd2, 0x3c, 0x92, 0x58, 0xd7, 0xfd, 0x92, 0x3c, 0xf8, 0x03, 0x3e, 0x70, + 0x20, 0x84, 0xa7, 0x17, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xcf, 0x00, + 0x0f, 0xe8, 0x0f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0xda, + 0xde, 0x08, 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, 0xf4, + 0xba, 0xe3, 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x02, 0x17, 0x03, 0x34, 0x09, + 0xda, 0xde, 0x08, 0x82, 0x7d, 0xfa, 0x5c, 0xf3, 0x42, 0xb1, 0x04, 0x84, + 0xf4, 0xba, 0xe3, 0x73, 0xe9, 0x35, 0x6f, 0xbb, 0x0a, 0x00, 0x00, 0x00, + 0x02, 0x0f, 0xcf, 0x00, 0x0f, 0xe8, 0x0f, 0xcf, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x03, 0x34, 0x01, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, + 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, + 0x17, 0x03, 0x34, 0x09, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, + 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xf2, 0x0f, 0xe8, + 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xed, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x09, + 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, + 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0x6b, 0x00, + 0x0f, 0xe8, 0x0f, 0xcf, 0x0f, 0xb6, 0x0f, 0x9d, 0x0f, 0x84, 0x0f, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, + 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, + 0x40, 0x1d, 0x5c, 0x06, 0x18, 0x03, 0x34, 0x01, 0xfc, 0x9b, 0xff, 0x1a, + 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, + 0xdb, 0x40, 0x1d, 0x5c, 0x05, 0x18, 0x03, 0x34, 0x01, 0x9b, 0x66, 0x83, + 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, + 0x6a, 0xbc, 0x33, 0xef, 0x01, 0x04, 0x18, 0x03, 0x34, 0x01, 0x9b, 0x66, + 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, 0x61, + 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0x03, 0x18, 0x03, 0x34, 0x01, 0x64, + 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, + 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x02, 0x17, 0x03, 0x34, 0x09, + 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, + 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0x0a, 0x00, 0x00, 0x00, + 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, + 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x08, 0x01, 0x06, + 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x08, 0x01, 0x04, 0x04, 0x03, + 0x08, 0x01, 0x03, 0x04, 0x03, 0x08, 0x01, 0x02, 0x03, 0x03, 0x08, 0x09, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, + 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, + 0x01, 0x04, 0x04, 0x03, 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, + 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, + 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, 0x04, 0x03, 0x09, 0x01, + 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, 0x09, 0x01, 0x03, 0x04, + 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, 0x0a, 0x00, 0x00, 0x00, + 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, + 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, + 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, + 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, + 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x08, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, 0x05, 0x04, 0x03, 0x08, + 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, 0x03, 0x08, 0x01, 0x02, + 0x03, 0x03, 0x08, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x0f, 0xe3, 0x00, + 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, 0x0f, 0xe8, 0x0f, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x08, 0x01, 0x06, 0x04, 0x03, 0x08, 0x01, + 0x05, 0x04, 0x03, 0x08, 0x01, 0x04, 0x04, 0x03, 0x08, 0x01, 0x03, 0x04, + 0x03, 0x08, 0x01, 0x02, 0x03, 0x03, 0x08, 0x09, 0x0a, 0x00, 0x00, 0x00, + 0x06, 0x0f, 0xe3, 0x00, 0x0f, 0xfc, 0x0f, 0xf7, 0x0f, 0xf2, 0x0f, 0xed, + 0x0f, 0xe8, 0x0f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x01, 0x06, + 0x04, 0x03, 0x09, 0x01, 0x05, 0x04, 0x03, 0x09, 0x01, 0x04, 0x04, 0x03, + 0x09, 0x01, 0x03, 0x04, 0x03, 0x09, 0x01, 0x02, 0x03, 0x03, 0x09, 0x09, + 0x0d, 0x00, 0x00, 0x00, 0x05, 0x05, 0x88, 0x00, 0x05, 0x88, 0x07, 0xca, + 0x0a, 0x10, 0x0b, 0x9e, 0x0d, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x55, 0x07, 0x16, 0x00, 0x07, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, + 0x34, 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, + 0xaa, 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x0b, 0x66, + 0x7c, 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, 0x95, 0x22, 0xa7, 0xe3, + 0x08, 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, + 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, + 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, 0x7c, 0xa5, 0xb2, 0x07, + 0xf2, 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, 0xc7, 0x85, 0xd2, 0x16, + 0x2f, 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, 0xbd, 0x3d, 0xd9, 0xc4, + 0x98, 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, 0x20, 0x7b, 0x97, 0xca, + 0xe6, 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, 0xc9, 0x46, 0x27, 0xd4, + 0x4f, 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, 0x3c, 0x4e, 0x8e, 0x37, + 0x6e, 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, 0x17, 0xdb, 0xd1, 0x96, + 0xb9, 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, 0xbf, 0x42, 0x46, 0xfc, + 0x1c, 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, 0x4c, 0x84, 0xde, 0x41, + 0x9f, 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, 0x9c, 0x59, 0xd6, 0xcf, + 0xcd, 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, 0x3b, 0x02, 0xcc, 0x1a, + 0xed, 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, 0x39, 0xa5, 0x82, 0x12, + 0x04, 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, 0xc0, 0x8d, 0xdb, 0xff, + 0x46, 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, 0x5e, 0xc1, 0xa3, 0xca, + 0xd4, 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, 0x22, 0xbf, 0xf6, 0x5a, + 0xe6, 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, 0xba, 0x8b, 0xd2, 0x39, + 0x49, 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, 0xdc, 0x0d, 0x73, 0x1b, + 0xe6, 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, 0x4b, 0x79, 0x8c, 0x23, + 0x8d, 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, 0x3f, 0x09, 0xec, 0xf3, + 0xa8, 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, 0x37, 0xc0, 0x2a, 0x7d, + 0x25, 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, 0x14, 0xd0, 0xa8, 0x1e, + 0x2a, 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, 0xa3, 0xb2, 0xee, 0x83, + 0x36, 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, 0x64, 0xb4, 0x07, 0x7c, + 0x3d, 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, 0x91, 0xf4, 0x32, 0xa8, + 0xf1, 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, 0x78, 0xca, 0xa4, 0x0c, + 0x84, 0x3f, 0x01, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, 0x5e, 0x17, + 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x41, 0xb7, 0x59, + 0x50, 0xd8, 0x33, 0x2b, 0x24, 0x83, 0xad, 0xb6, 0xae, 0x9f, 0x27, 0xa5, + 0x45, 0x30, 0xb3, 0x67, 0xc8, 0x32, 0x58, 0x95, 0x85, 0x06, 0xeb, 0xc1, + 0xf4, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, 0x6b, 0x51, + 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x99, 0xb4, 0x79, + 0xc1, 0x37, 0xc1, 0xe1, 0x5c, 0x49, 0xa0, 0xe1, 0xf3, 0x17, 0xb8, 0x9c, + 0x69, 0xe6, 0xba, 0xdc, 0xe7, 0x78, 0xb2, 0x5d, 0xd6, 0x95, 0xbe, 0xb2, + 0xda, 0x91, 0xd3, 0x9b, 0xf2, 0xd4, 0xe3, 0x95, 0x3c, 0x53, 0x8d, 0x0e, + 0x68, 0xe9, 0x02, 0xb3, 0xed, 0xeb, 0x95, 0xdd, 0x11, 0xb2, 0x64, 0x69, + 0x8a, 0xfe, 0x03, 0x05, 0xd5, 0x04, 0x9b, 0xac, 0x8a, 0xb6, 0x98, 0x29, + 0x56, 0x2e, 0xd3, 0xea, 0x4e, 0x84, 0xee, 0x23, 0x44, 0x03, 0x12, 0x9d, + 0x9c, 0x9c, 0x9f, 0x11, 0x62, 0xf0, 0x86, 0x36, 0x52, 0x15, 0x0f, 0x27, + 0x93, 0xdb, 0xde, 0x13, 0xc9, 0x94, 0x93, 0xe4, 0xa4, 0x6f, 0x58, 0x9d, + 0x58, 0x9f, 0x15, 0xba, 0x5f, 0x4c, 0xf3, 0x9a, 0x90, 0xc0, 0xcb, 0x60, + 0xce, 0x9b, 0x56, 0x0c, 0xfe, 0x5b, 0xd2, 0x4e, 0x0e, 0x82, 0xe6, 0x4c, + 0x62, 0x57, 0x08, 0x6e, 0x5d, 0x54, 0x7b, 0x28, 0xbb, 0x88, 0xdc, 0xec, + 0xaa, 0xd1, 0x6e, 0xd3, 0x94, 0x20, 0x3e, 0x35, 0x81, 0x52, 0xf6, 0xe9, + 0xee, 0x42, 0x89, 0xe9, 0xea, 0x61, 0x2c, 0xd8, 0xdc, 0xe3, 0x82, 0xf7, + 0xf0, 0xc0, 0xf6, 0xf9, 0xb7, 0xef, 0x49, 0xc7, 0x8d, 0x6c, 0x8a, 0x6d, + 0x6e, 0xbc, 0x2d, 0xc0, 0xb1, 0xec, 0x0c, 0xdd, 0xe5, 0xbe, 0x65, 0x3f, + 0x69, 0x81, 0xcf, 0xe8, 0xd8, 0xf3, 0x57, 0x8e, 0xba, 0x73, 0x7f, 0xb0, + 0x4e, 0x65, 0xa2, 0xa5, 0xa5, 0xbb, 0x7b, 0xae, 0xaa, 0x88, 0x06, 0x4f, + 0x2c, 0x43, 0xb9, 0x4c, 0x17, 0xa1, 0x24, 0xfb, 0xe1, 0x90, 0x50, 0xdb, + 0xcc, 0xd9, 0xe5, 0x7b, 0x09, 0xaf, 0x5c, 0x5a, 0x4f, 0xb2, 0x2b, 0x30, + 0x53, 0x0f, 0xd3, 0xe2, 0xbd, 0xcd, 0xf7, 0xa3, 0x19, 0xdc, 0xba, 0xee, + 0xd1, 0x49, 0xbc, 0xa6, 0xde, 0x1b, 0xe6, 0xd3, 0xaf, 0xdd, 0x61, 0xf6, + 0xfd, 0xef, 0xb7, 0xda, 0x9d, 0x93, 0x45, 0x0a, 0xa2, 0xa8, 0x1a, 0xe5, + 0x16, 0xb1, 0xaf, 0x20, 0x00, 0x86, 0x6b, 0x66, 0x42, 0x97, 0x4e, 0x3a, + 0xea, 0x0d, 0x33, 0xb2, 0x93, 0x87, 0x9c, 0xd1, 0x6a, 0x20, 0xbc, 0xc9, + 0x7d, 0x46, 0xb9, 0x0a, 0x26, 0x9a, 0x09, 0x81, 0xc8, 0x6d, 0x9b, 0x63, + 0xa5, 0x1f, 0x63, 0x72, 0x6c, 0xa8, 0x65, 0x65, 0xa2, 0x8a, 0x81, 0x4d, + 0x54, 0xd4, 0xa3, 0xc4, 0x86, 0x48, 0x31, 0x5c, 0x4e, 0x15, 0xf3, 0x48, + 0x30, 0xbc, 0x17, 0xac, 0x0b, 0x85, 0x8f, 0x44, 0x62, 0xf4, 0x57, 0xc7, + 0xbd, 0x18, 0xcf, 0xf5, 0xd8, 0xa9, 0x2d, 0xf5, 0x57, 0xaf, 0x42, 0x09, + 0xf7, 0x5b, 0x25, 0x56, 0xa1, 0x04, 0x0c, 0xf7, 0xa7, 0xc9, 0x2d, 0xd7, + 0x84, 0x78, 0x86, 0x82, 0x2d, 0xd3, 0xaa, 0xd2, 0xbf, 0x77, 0xc0, 0x34, + 0x7b, 0xdb, 0x7e, 0x4d, 0xde, 0x63, 0x8f, 0xcc, 0xb6, 0x6d, 0x01, 0x80, + 0x68, 0x51, 0x3e, 0x8f, 0x2a, 0x7c, 0x0e, 0xaa, 0xc2, 0xbf, 0x77, 0x12, + 0x06, 0x88, 0xdf, 0x3f, 0x6c, 0x7d, 0x69, 0x05, 0x57, 0x71, 0xeb, 0xe7, + 0xf3, 0xcb, 0x32, 0x4d, 0x33, 0x54, 0x8a, 0x2a, 0x1b, 0xb5, 0x6e, 0xb6, + 0xa4, 0x64, 0xcd, 0x34, 0x5c, 0xa9, 0x3d, 0x92, 0xc8, 0x38, 0xbb, 0x84, + 0xed, 0xde, 0xe4, 0xa2, 0xe1, 0x68, 0x2f, 0xcb, 0x4b, 0x3c, 0x76, 0xb2, + 0x3b, 0x84, 0x5f, 0x6b, 0x46, 0x72, 0x2f, 0x7f, 0xf0, 0x6f, 0x6b, 0x7b, + 0xd3, 0xc5, 0x4b, 0x20, 0x2b, 0xae, 0x48, 0x7e, 0xcb, 0x22, 0x38, 0x44, + 0x1f, 0x43, 0x1c, 0x55, 0x85, 0xe0, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, + 0x6b, 0x75, 0x84, 0x43, 0x02, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x87, + 0x66, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x41, + 0xb7, 0x59, 0x50, 0xd8, 0x37, 0x6c, 0x27, 0x77, 0xac, 0x86, 0x8b, 0xf9, + 0xb8, 0xa0, 0x50, 0x0b, 0x1f, 0xb3, 0x50, 0x55, 0xe2, 0x63, 0x81, 0xf6, + 0x85, 0xbc, 0xeb, 0x06, 0x98, 0x7e, 0x8b, 0x09, 0xd8, 0x2e, 0xbe, 0x8c, + 0x6b, 0x51, 0x5c, 0x08, 0x13, 0x58, 0xb4, 0x2e, 0x41, 0xcb, 0x34, 0x02, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf6, + 0xbc, 0x81, 0x5b, 0x23, 0x66, 0x44, 0x13, 0x27, 0xcf, 0x98, 0xc2, 0xc0, + 0x31, 0x38, 0x98, 0xec, 0x01, 0x84, 0xbb, 0x38, 0xb1, 0x79, 0xd7, 0x91, + 0x66, 0x5a, 0x56, 0x22, 0x62, 0x6f, 0xb8, 0xf0, 0x68, 0x00, 0xe7, 0x1a, + 0x7a, 0x93, 0xfc, 0xa8, 0xd4, 0xd9, 0xaf, 0x21, 0x17, 0x71, 0xf3, 0x0c, + 0xd6, 0x22, 0x2f, 0xb0, 0xb7, 0xc3, 0x1e, 0x07, 0xe7, 0x53, 0x34, 0xc9, + 0x17, 0x9d, 0xe8, 0xd3, 0x07, 0x78, 0xe7, 0x74, 0xcd, 0xf0, 0xdd, 0x88, + 0x0d, 0x30, 0x9b, 0x3c, 0x78, 0xfb, 0x43, 0xb7, 0x4f, 0x79, 0xd1, 0x83, + 0xcd, 0x56, 0x60, 0xe7, 0x7e, 0x8d, 0xba, 0x61, 0x9d, 0x4f, 0xf2, 0x71, + 0x9b, 0xbd, 0x11, 0xfc, 0x82, 0x8f, 0xc2, 0x9b, 0x32, 0xb7, 0x4d, 0x5d, + 0x93, 0x87, 0x11, 0x7d, 0xbf, 0x3a, 0x06, 0x11, 0x15, 0xf5, 0x97, 0xf4, + 0x03, 0x24, 0x6a, 0xfb, 0x5e, 0x27, 0x2b, 0xb5, 0xac, 0x20, 0x84, 0xe8, + 0x8d, 0x67, 0xa9, 0xf5, 0x41, 0x8a, 0xbd, 0xea, 0x51, 0x91, 0x30, 0xd7, + 0xf2, 0x81, 0x12, 0xbc, 0x24, 0x61, 0x25, 0x58, 0x9e, 0x4a, 0x4c, 0x89, + 0xa4, 0x19, 0xf1, 0x12, 0xe2, 0x33, 0xf1, 0x37, 0x1f, 0x0f, 0xa0, 0x42, + 0xa1, 0x0e, 0xa2, 0xc4, 0x06, 0xb0, 0xba, 0x61, 0xef, 0xc5, 0x6b, 0x46, + 0x33, 0x62, 0x50, 0xe0, 0xe4, 0x2e, 0x74, 0x20, 0xf4, 0x54, 0xbb, 0xed, + 0xa0, 0x73, 0x51, 0xa5, 0xc6, 0x55, 0x90, 0x61, 0xe9, 0x9c, 0x76, 0x72, + 0x21, 0xa9, 0x19, 0x1a, 0xbd, 0xcf, 0x61, 0x29, 0x8a, 0xef, 0xdd, 0xe0, + 0xc6, 0x0a, 0xf0, 0xd8, 0x50, 0xb9, 0xe9, 0x92, 0x7d, 0xf3, 0xce, 0x7e, + 0x9e, 0xcf, 0x32, 0x92, 0xc7, 0x49, 0x59, 0x23, 0xb5, 0x4e, 0xf2, 0x71, + 0xf0, 0xda, 0xb3, 0x80, 0xe3, 0xb6, 0x7a, 0xe4, 0x14, 0x80, 0x25, 0x3e, + 0xd0, 0x89, 0x13, 0xf4, 0x70, 0x96, 0xee, 0xbe, 0xef, 0x31, 0x61, 0xa1, + 0x8d, 0xf7, 0x9a, 0x5c, 0x92, 0x0a, 0x9b, 0x1f, 0x8c, 0x5e, 0x3d, 0x37, + 0x24, 0xc2, 0x8d, 0x21, 0xe9, 0x47, 0x2e, 0x03, 0xee, 0x32, 0xbf, 0x46, + 0xc7, 0x2c, 0x6e, 0x7a, 0x81, 0x9e, 0x14, 0xb8, 0xbe, 0xdb, 0x22, 0x4f, + 0xf1, 0x8d, 0x47, 0x41, 0x84, 0xc9, 0xeb, 0x4f, 0xe9, 0xf4, 0xad, 0xc4, + 0xbe, 0xf8, 0x28, 0xcb, 0xe6, 0x16, 0xa8, 0x6b, 0xaf, 0xd5, 0x0a, 0x6d, + 0x06, 0x59, 0x4f, 0x7d, 0x53, 0xa6, 0x4e, 0x90, 0xa0, 0x23, 0x1b, 0x92, + 0xf0, 0xe8, 0xef, 0xed, 0x0d, 0xa7, 0x64, 0x01, 0x83, 0x4a, 0x3b, 0x2d, + 0x18, 0x90, 0x1d, 0x19, 0x1d, 0xa2, 0x98, 0xe9, 0xb5, 0xe4, 0x4a, 0x73, + 0xcf, 0xdf, 0x0c, 0x09, 0xd5, 0xf4, 0xd3, 0xd9, 0x12, 0x7c, 0xbb, 0x81, + 0x51, 0x26, 0x2a, 0xcb, 0xa7, 0xc9, 0x6a, 0xe9, 0xfb, 0x1d, 0xca, 0x43, + 0xf1, 0xbe, 0xfb, 0xc3, 0x6f, 0xb6, 0xa1, 0x0c, 0x42, 0x32, 0x18, 0x24, + 0x63, 0xf9, 0xa0, 0x7e, 0x71, 0x8c, 0xa5, 0x16, 0x16, 0x5a, 0x5e, 0x15, + 0x5d, 0x6d, 0x4b, 0x74, 0x5b, 0xde, 0x21, 0xd5, 0xe0, 0x11, 0xa6, 0x91, + 0xc3, 0xb2, 0xd7, 0x38, 0x70, 0xa2, 0x18, 0x29, 0x1b, 0xdc, 0x83, 0x3e, + 0x37, 0x45, 0xc4, 0x1b, 0x61, 0x98, 0x06, 0x12, 0x3e, 0xc0, 0xda, 0x1a, + 0xc9, 0x18, 0x9c, 0x50, 0x0e, 0xc5, 0xe1, 0xa7, 0x4d, 0x05, 0xc6, 0x99, + 0x31, 0xab, 0x17, 0x30, 0xb9, 0xb0, 0x01, 0x1f, 0x93, 0xd9, 0x76, 0xd4, + 0x67, 0x0b, 0xea, 0x7b, 0x2b, 0x0b, 0x42, 0x97, 0x40, 0x07, 0x94, 0x08, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x83, 0x0b, 0x05, 0x16, + 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x3c, 0x29, 0x13, 0x41, 0xb7, 0x59, + 0x5c, 0x53, 0x32, 0x4a, 0x6b, 0x41, 0xb7, 0x59, 0x5c, 0x53, 0x32, 0x4a, + 0x6b, 0x65, 0x6d, 0xb0, 0x14, 0x83, 0xdf, 0x17, 0xb6, 0x73, 0x59, 0x09, + 0xd6, 0x8a, 0xed, 0x02, 0x13, 0x5a, 0x8b, 0xd4, 0x99, 0xda, 0x39, 0xa3, + 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, + 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xaa, 0xa7, 0xbf, 0x94, 0x09, 0x4f, 0x35, + 0x59, 0x31, 0xba, 0xaa, 0x89, 0x4f, 0xfa, 0x26, 0x41, 0x66, 0x87, 0x1b, + 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0xdc, 0x97, 0xef, 0xa5, 0xc0, 0xbc, 0x15, 0x38, 0x95, 0x35, 0x74, + 0x61, 0x34, 0x68, 0xb9, 0x5c, 0xef, 0x21, 0xad, 0xeb, 0xc9, 0x50, 0x73, + 0xed, 0x31, 0x38, 0x33, 0x44, 0x03, 0x44, 0x16, 0xaf, 0xa2, 0xba, 0x34, + 0x58, 0x3f, 0x49, 0xaf, 0x93, 0xf8, 0xe4, 0x6e, 0x6f, 0x7f, 0x23, 0x05, + 0x46, 0x75, 0x49, 0xdf, 0x84, 0xad, 0x64, 0x83, 0x11, 0x43, 0xd9, 0x80, + 0x11, 0x93, 0x6d, 0xcf, 0xb4, 0x72, 0x42, 0xc2, 0x5a, 0x78, 0x57, 0x37, + 0x2d, 0x9e, 0x9a, 0x3e, 0x30, 0x9b, 0x72, 0x7b, 0xfa, 0x1d, 0x9e, 0x2d, + 0x53, 0x16, 0x85, 0x91, 0x3c, 0xe9, 0xf1, 0x39, 0x60, 0x1d, 0x9e, 0xc6, + 0xee, 0xb1, 0xdc, 0xb1, 0x0d, 0xb8, 0x23, 0x68, 0xbf, 0xe5, 0x08, 0xc4, + 0xac, 0x31, 0x4e, 0x2d, 0x0f, 0x1f, 0xe1, 0xb3, 0xfe, 0xd2, 0x31, 0x4a, + 0x52, 0x3e, 0x03, 0xe1, 0x1a, 0x66, 0x58, 0x8b, 0x56, 0x99, 0x55, 0x7f, + 0x6f, 0x5a, 0xa9, 0x8f, 0xcf, 0xb3, 0x03, 0x96, 0x79, 0xb0, 0x6c, 0x67, + 0x60, 0x35, 0xce, 0x8d, 0xc6, 0x1c, 0x70, 0x05, 0xa4, 0x5e, 0x4f, 0x83, + 0x4f, 0x1a, 0x98, 0x88, 0xdd, 0x5a, 0x5d, 0xb3, 0x9b, 0xf6, 0xb2, 0xa3, + 0x2e, 0x1c, 0x41, 0x81, 0x97, 0xef, 0x16, 0xb3, 0x8e, 0xbe, 0x09, 0x08, + 0x3d, 0x47, 0xaa, 0x2b, 0x90, 0x61, 0xc7, 0x67, 0xcb, 0x0d, 0xa5, 0x7a, + 0x58, 0x4d, 0xa7, 0x9f, 0xd4, 0x21, 0xf2, 0x47, 0x65, 0x3b, 0x9e, 0x3b, + 0xa4, 0xb4, 0x15, 0x05, 0x10, 0xee, 0x90, 0xe5, 0xd9, 0x2e, 0xa0, 0xfe, + 0x85, 0x9c, 0xad, 0x37, 0x71, 0x51, 0xba, 0x0e, 0x91, 0x48, 0x3e, 0x54, + 0xa0, 0x10, 0x1b, 0xc7, 0xff, 0x4b, 0xd2, 0x24, 0xf8, 0x37, 0xd9, 0xc3, + 0x17, 0x12, 0x05, 0x28, 0xbe, 0xeb, 0xf5, 0xa3, 0x5a, 0x93, 0x7b, 0x9e, + 0x59, 0xb2, 0x63, 0xbc, 0x71, 0x61, 0x6a, 0x5a, 0x6c, 0xbd, 0xae, 0xeb, + 0xff, 0x2a, 0x53, 0xf3, 0x44, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, 0x64, 0x64, 0x6b, 0x75, 0x84, 0x07, + 0x06, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x86, 0x46, 0x17, 0x13, 0x41, + 0xb7, 0x59, 0x5c, 0x54, 0xdd, 0xc7, 0x58, 0x41, 0xb7, 0x59, 0x5c, 0x54, + 0xdd, 0xc7, 0x58, 0x8e, 0xc3, 0x7e, 0x3a, 0x0f, 0x3a, 0x3a, 0x7e, 0x0e, + 0x1e, 0x69, 0x08, 0x28, 0x2f, 0x21, 0x1c, 0x2a, 0x13, 0xa3, 0x59, 0xe5, + 0x0e, 0x4d, 0x78, 0x41, 0x89, 0x33, 0xa3, 0x28, 0x6d, 0xb9, 0x0a, 0x0b, + 0x36, 0x7b, 0xf9, 0xc7, 0xb9, 0x71, 0xe5, 0x1c, 0x32, 0x04, 0xe7, 0x79, + 0xe1, 0xe0, 0x05, 0x0b, 0xa0, 0xe7, 0xb9, 0xe1, 0x92, 0xbb, 0xa8, 0xae, + 0xca, 0xff, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x99, 0x02, 0x2d, 0xc5, 0xee, 0x94, 0x76, 0x6c, 0x0a, + 0xe2, 0xa1, 0xb1, 0x7a, 0x6d, 0x0c, 0xbf, 0x9d, 0xa2, 0x60, 0xdc, 0xb9, + 0xf4, 0xf9, 0x4e, 0x6f, 0x61, 0x37, 0x18, 0x86, 0xbf, 0xef, 0xe9, 0x55, + 0x9e, 0x44, 0x75, 0x32, 0x4c, 0x20, 0x82, 0xb5, 0x3d, 0x42, 0x72, 0x35, + 0x69, 0xba, 0x22, 0x95, 0x0c, 0xec, 0x46, 0xe8, 0x5b, 0x62, 0xe2, 0x07, + 0xd4, 0x80, 0x99, 0xc1, 0x83, 0x12, 0x3f, 0xcc, 0xd4, 0xf6, 0xcd, 0xc2, + 0xb2, 0xcd, 0x4d, 0x94, 0x4c, 0xab, 0x05, 0x48, 0x0c, 0x09, 0xe1, 0x82, + 0x1a, 0x6c, 0x0a, 0xf5, 0x16, 0x06, 0x57, 0x23, 0x9e, 0x18, 0xe8, 0xd9, + 0xbb, 0x4a, 0x8a, 0xcd, 0x69, 0xed, 0xc3, 0xae, 0x71, 0xe8, 0x8f, 0xeb, + 0xb5, 0x76, 0x50, 0xca, 0xb5, 0x69, 0x05, 0xdc, 0x93, 0x5b, 0x49, 0xed, + 0xa3, 0xf8, 0x25, 0xfe, 0x6a, 0x83, 0x6f, 0x16, 0x1e, 0xef, 0x5b, 0xfd, + 0x24, 0x7f, 0x9f, 0x66, 0xf1, 0x65, 0x8c, 0x38, 0x43, 0xd1, 0xbc, 0x13, + 0x14, 0x45, 0x75, 0x66, 0x3b, 0xd7, 0xe1, 0x7a, 0xde, 0xb1, 0xf6, 0x27, + 0xd6, 0x3e, 0xf6, 0x44, 0x7d, 0xf3, 0x3e, 0xd2, 0x95, 0x49, 0xe5, 0x31, + 0x6f, 0x38, 0x95, 0xd0, 0x78, 0xc8, 0xca, 0x68, 0xaf, 0xec, 0xab, 0x1e, + 0xcf, 0x0c, 0xff, 0x3e, 0xc4, 0x12, 0x3e, 0x48, 0xb4, 0x7e, 0x70, 0xc6, + 0xa0, 0x9b, 0xf8, 0x80, 0x30, 0x75, 0x25, 0x1a, 0xf1, 0xdf, 0x3a, 0x37, + 0xa1, 0xac, 0x43, 0x5b, 0xa0, 0xae, 0x9b, 0x91, 0xb3, 0x4a, 0xfa, 0x5f, + 0x4b, 0xf1, 0xba, 0xcd, 0x41, 0x92, 0x38, 0x6a, 0x8d, 0x69, 0x9e, 0xd3, + 0x09, 0xaa, 0x4c, 0xb2, 0x60, 0xcf, 0xff, 0x37, 0xed, 0xa0, 0x39, 0x36, + 0x03, 0x1a, 0x6a, 0xb7, 0xed, 0xce, 0xc8, 0x4e, 0x46, 0xb1, 0x82, 0xfb, + 0xe1, 0x46, 0x2d, 0x12, 0xf4, 0x8a, 0x6c, 0x38, 0x5c, 0x6b, 0xaa, 0x05, + 0xf1, 0xc0, 0xf2, 0x14, 0x8d, 0x3e, 0xdc, 0xec, 0x04, 0x0c, 0x94, 0xe3, + 0xbf, 0x3b, 0x7b, 0x3f, 0xa2, 0x88, 0x98, 0xe6, 0x0c, 0x5f, 0x23, 0x6d, + 0x0b, 0x6f, 0x8e, 0xe9, 0xce, 0xc0, 0xe2, 0x3e, 0xc7, 0xcd, 0xa0, 0x7b, + 0xda, 0xf1, 0x26, 0xfd, 0x3d, 0xc6, 0xe7, 0xe8, 0xed, 0x9d, 0xeb, 0x74, + 0xc5, 0x14, 0x5c, 0xee, 0xcd, 0x4d, 0xc4, 0x4e, 0x1b, 0x2d, 0x09, 0xf4, + 0x7b, 0xdb, 0xf6, 0x96, 0x17, 0x17, 0xd1, 0x16, 0xd5, 0xea, 0xaf, 0x4f, + 0x7b, 0xc2, 0x1e, 0x0f, 0xe1, 0x2c, 0xd8, 0x26, 0xe1, 0xcc, 0x66, 0x64, + 0xd1, 0x3f, 0xd9, 0x16, 0x99, 0x0c, 0xb1, 0x11, 0xc2, 0x13, 0xe5, 0xab, + 0x99, 0x2a, 0x6f, 0x09, 0x37, 0xc5, 0x7c, 0x8e, 0xb8, 0x04, 0x73, 0x3b, + 0x0b, 0x58, 0x87, 0x10, 0x33, 0x1f, 0x5d, 0xea, 0xe9, 0xcd, 0x4e, 0x5b, + 0x33, 0x88, 0xc2, 0x9c, 0x01, 0x1a, 0xe6, 0x92, 0x57, 0xf9, 0xa8, 0x7d, + 0x03, 0x76, 0x79, 0x4e, 0x1e, 0x25, 0xe8, 0xae, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x64, 0x6b, 0x75, 0x84, 0x55, 0x07, 0x16, 0x00, 0x07, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, + 0x00, 0x88, 0x0a, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, + 0x7a, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xdf, 0xaa, 0x7a, 0x0b, 0x66, 0x7c, + 0x18, 0x9e, 0x44, 0x49, 0x2d, 0x40, 0x62, 0x95, 0x22, 0xa7, 0xe3, 0x08, + 0x19, 0x26, 0x0f, 0xd6, 0x6d, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, + 0x47, 0x10, 0xf5, 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, + 0xb8, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x64, 0x0f, 0xc5, 0x21, 0x02, 0x15, 0x7c, 0xa5, 0xb2, 0x07, 0xf2, + 0xee, 0xe7, 0xeb, 0x55, 0xb1, 0x73, 0x0b, 0xc7, 0x85, 0xd2, 0x16, 0x2f, + 0x68, 0x13, 0x3e, 0x6a, 0x6b, 0x3a, 0x3d, 0xbd, 0x3d, 0xd9, 0xc4, 0x98, + 0x92, 0xea, 0x5a, 0xf1, 0xf3, 0x69, 0x0e, 0x20, 0x7b, 0x97, 0xca, 0xe6, + 0x21, 0x45, 0x98, 0xcf, 0x92, 0x04, 0xf5, 0xc9, 0x46, 0x27, 0xd4, 0x4f, + 0x83, 0x2c, 0x3b, 0xbb, 0x83, 0x22, 0xa3, 0x3c, 0x4e, 0x8e, 0x37, 0x6e, + 0xe1, 0x6f, 0x80, 0x83, 0x0f, 0x19, 0xed, 0x17, 0xdb, 0xd1, 0x96, 0xb9, + 0x33, 0xe6, 0x25, 0x50, 0x4f, 0x40, 0x36, 0xbf, 0x42, 0x46, 0xfc, 0x1c, + 0x4a, 0x84, 0x9a, 0xb5, 0xcb, 0xe1, 0xee, 0x4c, 0x84, 0xde, 0x41, 0x9f, + 0x69, 0x3d, 0x9c, 0xe5, 0x38, 0x68, 0xb1, 0x9c, 0x59, 0xd6, 0xcf, 0xcd, + 0x76, 0xc3, 0xa7, 0x99, 0xf2, 0xe5, 0x8d, 0x3b, 0x02, 0xcc, 0x1a, 0xed, + 0x52, 0xd6, 0xef, 0x8f, 0xb2, 0xba, 0x11, 0x39, 0xa5, 0x82, 0x12, 0x04, + 0x2b, 0x03, 0xda, 0x41, 0x8c, 0x9e, 0xe1, 0xc0, 0x8d, 0xdb, 0xff, 0x46, + 0xce, 0xa9, 0xf3, 0x70, 0xf0, 0x5a, 0xd9, 0x5e, 0xc1, 0xa3, 0xca, 0xd4, + 0x02, 0x2a, 0xce, 0x49, 0x55, 0x61, 0x5d, 0x22, 0xbf, 0xf6, 0x5a, 0xe6, + 0xe4, 0xb4, 0x7a, 0xe2, 0x47, 0x24, 0x72, 0xba, 0x8b, 0xd2, 0x39, 0x49, + 0xf2, 0xa0, 0xda, 0xe6, 0xb6, 0xe1, 0x79, 0xdc, 0x0d, 0x73, 0x1b, 0xe6, + 0x40, 0xe4, 0xda, 0x74, 0x7c, 0xa4, 0x81, 0x4b, 0x79, 0x8c, 0x23, 0x8d, + 0xd5, 0x9d, 0xe0, 0x01, 0xe2, 0x88, 0xa8, 0x3f, 0x09, 0xec, 0xf3, 0xa8, + 0xd5, 0x8b, 0xe2, 0xef, 0x0e, 0x0c, 0x42, 0x37, 0xc0, 0x2a, 0x7d, 0x25, + 0x56, 0xc4, 0x28, 0xc3, 0x70, 0x73, 0xe7, 0x14, 0xd0, 0xa8, 0x1e, 0x2a, + 0xd7, 0xd6, 0x85, 0x0f, 0x4b, 0x94, 0x8d, 0xa3, 0xb2, 0xee, 0x83, 0x36, + 0x0a, 0x59, 0x4b, 0x8a, 0xc3, 0xf8, 0xd1, 0x64, 0xb4, 0x07, 0x7c, 0x3d, + 0x98, 0xaf, 0x7c, 0xd2, 0xed, 0x2a, 0xa2, 0x91, 0xf4, 0x32, 0xa8, 0xf1, + 0x67, 0x0a, 0x34, 0x75, 0x88, 0x4e, 0x69, 0x78, 0xca, 0xa4, 0x0c, 0xf8, + 0x40, 0x9f, 0x86, 0xd9, 0x16, 0x56, 0x67, 0x74, 0xd4, 0x33, 0x9e, 0xb7, + 0xef, 0xa6, 0xdf, 0x32, 0xb2, 0x24, 0x20, 0xe7, 0xe9, 0x80, 0xdf, 0x7b, + 0xa3, 0x49, 0x04, 0xd7, 0x3f, 0x9f, 0xbe, 0xa6, 0x2d, 0xd0, 0xec, 0xed, + 0x04, 0x76, 0xc9, 0x38, 0x0b, 0x2c, 0x02, 0xcc, 0xd0, 0x98, 0x02, 0x73, + 0x96, 0x6b, 0x8b, 0xcb, 0x2b, 0x57, 0x2d, 0xab, 0x0d, 0x5e, 0x97, 0xb8, + 0xd9, 0x81, 0xa6, 0x09, 0x7c, 0x6a, 0x6a, 0xbe, 0xed, 0x44, 0xe1, 0x87, + 0x2a, 0xbd, 0xad, 0x61, 0xfa, 0xdc, 0x76, 0xaa, 0xa5, 0xfd, 0x40, 0xee, + 0x9f, 0xf1, 0xc6, 0x74, 0xe9, 0xba, 0xc1, 0xaf, 0xf1, 0x5d, 0x16, 0x06, + 0x27, 0x60, 0x2b, 0x96, 0x9d, 0x0d, 0xc1, 0x7c, 0xc3, 0x7b, 0xfd, 0x33, + 0xc2, 0xa6, 0x7c, 0xbc, 0xc3, 0x1c, 0xef, 0x9d, 0xf4, 0xe2, 0x8c, 0x2d, + 0xe3, 0x01, 0xc1, 0x95, 0x24, 0x66, 0x15, 0x1a, 0xa1, 0xa0, 0x61, 0x28, + 0x8f, 0x44, 0x77, 0x80, 0xfc, 0x11, 0xce, 0xad, 0xe1, 0xf1, 0xe9, 0x80, + 0x55, 0x6d, 0x77, 0x5d, 0xf7, 0x2a, 0xf8, 0x15, 0x42, 0xdd, 0xf6, 0x62, + 0xac, 0x68, 0x8f, 0xaa, 0x85, 0xd8, 0xfa, 0xc6, 0x21, 0xe9, 0xa8, 0xa2, + 0x1e, 0xe3, 0xd4, 0x32, 0x3e, 0xee, 0xec, 0x96, 0x54, 0xe1, 0xb1, 0x8f, + 0x64, 0x59, 0xc6, 0x49, 0x01, 0x3c, 0xc0, 0x17, 0xa9, 0xf5, 0xf2, 0x6f, + 0x8a, 0xec, 0x9b, 0x66, 0xa7, 0x1d, 0x98, 0xff, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x64, 0x6b, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x04, 0x3a, 0x00, + 0x07, 0x4c, 0x0d, 0x3f, 0x0e, 0xa9, 0x04, 0x3a, 0x05, 0x5c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x1f, 0x11, 0x16, 0x00, 0x07, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x34, 0x00, 0x83, 0x22, 0x15, 0x11, 0x41, 0xb7, 0x59, 0x5c, 0xf4, + 0x84, 0x43, 0x4e, 0x41, 0xb7, 0x59, 0x5c, 0xf4, 0x84, 0x43, 0x4e, 0xda, + 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, + 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xa9, 0x4a, 0x8f, 0xe5, 0xcc, + 0xb1, 0x9b, 0xa6, 0x1c, 0x4c, 0x08, 0x73, 0xd3, 0x91, 0xe9, 0x87, 0x98, + 0x2f, 0xbb, 0xd3, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x72, 0xbd, 0xda, 0xaa, 0x55, 0x31, 0xcc, 0x9a, 0xfc, + 0x33, 0x30, 0x52, 0x07, 0x40, 0x54, 0xcb, 0x27, 0x4e, 0xb7, 0x9f, 0x96, + 0xb8, 0xcb, 0xdc, 0x88, 0x3c, 0x09, 0xd1, 0x96, 0xe2, 0x79, 0x54, 0x21, + 0x46, 0xca, 0x50, 0xa2, 0x46, 0xda, 0x44, 0x2e, 0x3b, 0x4b, 0x18, 0xb7, + 0x5a, 0x17, 0xe6, 0x4f, 0x06, 0xde, 0xec, 0x05, 0x9c, 0xec, 0x8e, 0xb5, + 0xd1, 0xb3, 0xe3, 0x0a, 0x3f, 0x44, 0x9c, 0xa5, 0x30, 0x0a, 0x83, 0x66, + 0x82, 0x89, 0xcf, 0x1b, 0xb8, 0xb8, 0xb2, 0x18, 0x54, 0xcf, 0x4d, 0x85, + 0x93, 0x97, 0x75, 0x54, 0x06, 0x23, 0x05, 0xe8, 0xff, 0x42, 0x33, 0x7f, + 0xdf, 0x26, 0xa0, 0x1e, 0xd3, 0xe2, 0x7b, 0xb7, 0xe2, 0x70, 0x88, 0x82, + 0xba, 0x3e, 0x38, 0xaa, 0x95, 0xee, 0xf7, 0x4f, 0x81, 0xbe, 0xf4, 0xfe, + 0x8f, 0x42, 0xb8, 0x94, 0x25, 0xe3, 0x3a, 0x4b, 0xe1, 0x15, 0xe2, 0xe1, + 0xe6, 0x8b, 0xda, 0x49, 0x9a, 0xb1, 0x47, 0xa4, 0x9c, 0xac, 0x35, 0xb8, + 0xa2, 0xb3, 0xc2, 0x5f, 0x2b, 0x87, 0x11, 0xd7, 0x57, 0x47, 0x05, 0x89, + 0x05, 0x86, 0xfa, 0x97, 0xa7, 0x97, 0x46, 0xcf, 0xaa, 0xa8, 0x94, 0x2c, + 0xde, 0xa3, 0xde, 0xb1, 0x92, 0x20, 0xbd, 0x7d, 0x90, 0xd2, 0xa7, 0x21, + 0x26, 0x6f, 0x2b, 0x6e, 0xd3, 0xd9, 0x1a, 0xea, 0x57, 0x04, 0x94, 0x1c, + 0x73, 0x0e, 0x74, 0x65, 0x73, 0x74, 0x61, 0x6b, 0xe1, 0x06, 0x12, 0x17, + 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x34, 0x34, 0x00, 0x81, 0xc0, 0x6a, 0x17, 0x13, 0x41, 0xb7, + 0x59, 0x5c, 0xfe, 0x44, 0x71, 0x3f, 0x41, 0xb7, 0x59, 0x5c, 0xfe, 0x44, + 0x71, 0x3f, 0x7f, 0xda, 0x6a, 0xa0, 0x63, 0xf3, 0xfc, 0x5a, 0x86, 0x5c, + 0xa8, 0xf7, 0xa6, 0x9b, 0x5d, 0x69, 0x07, 0x3b, 0x91, 0x55, 0x72, 0x29, + 0x9c, 0x30, 0x4b, 0x50, 0xee, 0xe7, 0xb0, 0xc7, 0x1b, 0x05, 0x97, 0x70, + 0xac, 0x8e, 0x43, 0x5d, 0x69, 0x39, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0xbe, 0xad, 0xda, 0xa8, 0x8a, + 0x50, 0x50, 0xa2, 0x05, 0x34, 0x4f, 0x7d, 0x48, 0x22, 0x81, 0x07, 0x45, + 0x81, 0x36, 0x06, 0x10, 0x48, 0xd5, 0xe0, 0xb8, 0x50, 0xbd, 0x5c, 0xe8, + 0x5d, 0x51, 0x93, 0x3c, 0xfa, 0xeb, 0x83, 0x4d, 0x00, 0xa1, 0x9d, 0x8a, + 0x39, 0x91, 0xac, 0x08, 0x70, 0x37, 0x9a, 0x2d, 0x33, 0xdf, 0xfa, 0x44, + 0xed, 0x61, 0x62, 0x10, 0x2c, 0x22, 0x27, 0x44, 0xa8, 0x19, 0xc3, 0x4f, + 0xd4, 0xb6, 0x7a, 0x6c, 0xf3, 0xb2, 0x4f, 0xf4, 0x06, 0x16, 0x5e, 0xc6, + 0x08, 0x61, 0xd5, 0x6b, 0xaf, 0x9d, 0x1e, 0x1f, 0x9c, 0xed, 0x30, 0xda, + 0x7a, 0xf1, 0xa3, 0x24, 0x26, 0xf5, 0xc9, 0xd6, 0xea, 0xdc, 0x1b, 0x4b, + 0xf6, 0x62, 0x78, 0xa6, 0x64, 0x6c, 0xd4, 0xbf, 0x30, 0x29, 0x36, 0x18, + 0x7c, 0x55, 0x1e, 0x12, 0xbe, 0x30, 0xc9, 0x51, 0x4c, 0x18, 0x83, 0x39, + 0x8d, 0xa2, 0xbc, 0x8a, 0x6f, 0x96, 0x1b, 0x69, 0xbf, 0x99, 0x29, 0x58, + 0x7b, 0xd2, 0x9d, 0x50, 0x32, 0x91, 0x31, 0xd2, 0x25, 0xcc, 0x19, 0xab, + 0x51, 0x6a, 0xc8, 0x5b, 0xd9, 0xf3, 0x64, 0x36, 0xf8, 0xbc, 0x73, 0x23, + 0x07, 0x04, 0x93, 0xd9, 0xbc, 0xd4, 0xb8, 0x7b, 0xd3, 0x58, 0x68, 0x2c, + 0x2b, 0x67, 0xae, 0x57, 0x39, 0x6b, 0xb0, 0xf5, 0x62, 0xe5, 0xec, 0xbe, + 0x42, 0x97, 0x9f, 0xec, 0x9c, 0x43, 0x7c, 0xba, 0xab, 0xad, 0xed, 0xd9, + 0xa0, 0xbc, 0xf4, 0x98, 0x03, 0xca, 0xbe, 0xd8, 0xa3, 0x79, 0x4c, 0xdb, + 0x3d, 0x22, 0x15, 0x71, 0xc9, 0x37, 0x92, 0x9b, 0x05, 0x54, 0x72, 0xe2, + 0x41, 0xd7, 0xd8, 0xb2, 0x4f, 0xcf, 0x56, 0xf3, 0x46, 0x4c, 0x39, 0x5d, + 0x49, 0xdf, 0xae, 0x52, 0xb2, 0x8f, 0xf0, 0x9a, 0xae, 0xe0, 0x00, 0xf4, + 0xd0, 0xd0, 0xa3, 0x8d, 0xf4, 0xba, 0x57, 0xe5, 0x0d, 0xa2, 0x0e, 0xcc, + 0xa3, 0xb9, 0xd0, 0x78, 0x24, 0x3e, 0xdb, 0xdb, 0x4b, 0xc8, 0x60, 0xbb, + 0x71, 0xb8, 0xc6, 0xfe, 0xb0, 0x67, 0x5b, 0x86, 0x09, 0x6c, 0xd0, 0x3e, + 0x6e, 0x0a, 0x82, 0x93, 0xcf, 0xdb, 0x9a, 0x72, 0x5c, 0x41, 0x8f, 0xa5, + 0xfd, 0x44, 0x17, 0xe0, 0x5f, 0x85, 0x9c, 0xb5, 0x71, 0xe4, 0x67, 0x94, + 0x88, 0xdf, 0xfe, 0xad, 0x4e, 0x5e, 0x67, 0x41, 0x49, 0xc3, 0xda, 0x1a, + 0x25, 0xcc, 0x8c, 0xaf, 0xb5, 0xf9, 0xb6, 0x37, 0x2f, 0xe9, 0x73, 0x1d, + 0x71, 0xaf, 0x2a, 0x7d, 0x95, 0xef, 0x8a, 0xe0, 0x0f, 0x0a, 0x73, 0x95, + 0x88, 0x33, 0xe2, 0xe0, 0x88, 0x2b, 0x44, 0x60, 0x51, 0x27, 0xfa, 0x90, + 0xfc, 0x5a, 0x35, 0x54, 0x19, 0x9c, 0xb4, 0x60, 0x2b, 0xd8, 0x4c, 0xf9, + 0x2d, 0xba, 0x88, 0x12, 0xa6, 0xfc, 0x0c, 0x22, 0xfd, 0x27, 0x9e, 0x98, + 0x02, 0xf8, 0x06, 0x70, 0x51, 0x66, 0xa0, 0x1e, 0xb1, 0x6e, 0xe1, 0x90, + 0x86, 0x55, 0xa2, 0x84, 0x92, 0xd6, 0xe4, 0x59, 0x00, 0x00, 0x00, 0x1c, + 0x8b, 0x70, 0x08, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x96, 0x40, 0x17, + 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xe2, 0xe0, 0xc1, 0x41, 0xb7, 0x59, + 0x5c, 0x7e, 0xe2, 0xe0, 0xc1, 0x51, 0x96, 0x74, 0xbb, 0x0c, 0xef, 0x0c, + 0xf3, 0x24, 0x61, 0xd2, 0x2c, 0xba, 0x9a, 0xa9, 0xc8, 0x0e, 0x22, 0xff, + 0x0b, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, + 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x4e, 0xcb, 0x84, + 0x35, 0xce, 0xed, 0x00, 0x0f, 0x0d, 0x8f, 0xce, 0xe6, 0x43, 0xc4, 0x14, + 0x6f, 0x42, 0xd5, 0x97, 0xdf, 0xa6, 0x31, 0x52, 0xa2, 0xb2, 0xc4, 0x38, + 0xf2, 0x2e, 0xb2, 0x5e, 0x73, 0x6d, 0xeb, 0x60, 0xa9, 0x70, 0x32, 0xad, + 0x98, 0x3a, 0x23, 0x00, 0x86, 0x4c, 0x75, 0x26, 0x22, 0x28, 0x8f, 0x1a, + 0x96, 0x60, 0x8a, 0x61, 0xa2, 0xc5, 0x0b, 0x5a, 0xf6, 0x7b, 0x3a, 0xb0, + 0x42, 0x02, 0x3a, 0x5f, 0x4c, 0x14, 0xdd, 0x52, 0x6a, 0xff, 0x08, 0x5f, + 0x7e, 0xef, 0x9a, 0x98, 0x0e, 0x06, 0x38, 0x24, 0x6d, 0x4c, 0xa6, 0x29, + 0xeb, 0x44, 0xa8, 0x35, 0x7d, 0x0f, 0x2f, 0x8c, 0x83, 0x5b, 0xc4, 0x43, + 0x5f, 0x9c, 0x33, 0x7f, 0xc0, 0x97, 0x17, 0xed, 0xcb, 0x95, 0xed, 0xa4, + 0xe4, 0x29, 0xdd, 0x62, 0xff, 0x3a, 0x07, 0x91, 0x92, 0xa9, 0xc2, 0x19, + 0xc3, 0xaa, 0xa3, 0xcb, 0xcc, 0x64, 0xf2, 0x00, 0xb8, 0xc9, 0x17, 0x3d, + 0x00, 0x24, 0xb2, 0xaf, 0x0e, 0x6c, 0xd5, 0x64, 0x84, 0x7d, 0x60, 0x19, + 0xad, 0xa6, 0x79, 0x05, 0x88, 0xf7, 0x72, 0x5a, 0xa4, 0x6b, 0x51, 0x77, + 0xb2, 0x28, 0x93, 0xcb, 0xbe, 0x74, 0x70, 0x10, 0x09, 0x00, 0x5f, 0x2d, + 0xe5, 0xf8, 0x9d, 0x90, 0x00, 0x2b, 0xa3, 0xbb, 0x32, 0x6c, 0x2d, 0x9e, + 0x72, 0x25, 0x18, 0x92, 0xec, 0xbf, 0x97, 0x49, 0xc7, 0x4c, 0xee, 0x90, + 0x5d, 0x6d, 0xdc, 0xa4, 0x4f, 0x4c, 0x88, 0x6c, 0x81, 0x9f, 0xcf, 0xd1, + 0x89, 0x29, 0x3d, 0x61, 0x38, 0x33, 0x89, 0x4a, 0x81, 0xd2, 0x0c, 0xc8, + 0xdc, 0x09, 0xb2, 0x6a, 0xa7, 0x16, 0x42, 0x9f, 0xa3, 0x9d, 0x85, 0x02, + 0xb4, 0xb8, 0xd4, 0xae, 0x63, 0xef, 0x50, 0x78, 0x43, 0x3b, 0x20, 0x7c, + 0x87, 0xac, 0xcb, 0x0b, 0x96, 0x1c, 0x8e, 0x1f, 0xc4, 0x84, 0x20, 0xe1, + 0x3c, 0xe3, 0x0a, 0x28, 0xfb, 0x4b, 0xa3, 0x19, 0x7c, 0xc7, 0x37, 0xf0, + 0x29, 0x47, 0x9d, 0xaf, 0xf4, 0xf1, 0xf6, 0x3c, 0x32, 0xae, 0x5b, 0x37, + 0xc5, 0x77, 0x90, 0xf5, 0x59, 0x8b, 0x85, 0x95, 0xee, 0xdf, 0xa7, 0x2e, + 0x4b, 0x5b, 0xf3, 0x0c, 0xe3, 0xc5, 0xe6, 0x6a, 0x85, 0xfb, 0xe2, 0x4a, + 0x5a, 0xb8, 0x06, 0xcc, 0x22, 0x3d, 0x21, 0x76, 0x04, 0xca, 0x5f, 0x61, + 0x18, 0x4f, 0x35, 0x11, 0x20, 0xe9, 0xc1, 0x72, 0x3d, 0x45, 0x58, 0x60, + 0x8b, 0x8e, 0x3d, 0x3d, 0x21, 0xf8, 0xb3, 0xa3, 0x02, 0x57, 0x06, 0xbd, + 0xff, 0xe0, 0x65, 0x35, 0x3a, 0xba, 0xe8, 0xa8, 0x96, 0x6f, 0x6c, 0x67, + 0xeb, 0xd6, 0xf4, 0xdc, 0xf6, 0x26, 0x52, 0xcd, 0xed, 0xc1, 0x73, 0x12, + 0xdb, 0x86, 0xef, 0x36, 0x87, 0x22, 0xc4, 0xfd, 0xaf, 0xc7, 0x35, 0x90, + 0x38, 0xe5, 0xb2, 0x4a, 0x8a, 0xca, 0xcc, 0x1a, 0xd5, 0x82, 0x10, 0xba, + 0xe7, 0x60, 0xb2, 0x0d, 0x6b, 0xb5, 0xbd, 0x9e, 0x6e, 0xd0, 0xe0, 0x36, + 0xd8, 0x0a, 0x09, 0x24, 0x87, 0xcd, 0xc2, 0x94, 0x10, 0x14, 0xc4, 0x15, + 0xc2, 0xf7, 0x37, 0x22, 0x78, 0x6c, 0x88, 0x75, 0x3a, 0x08, 0xdc, 0x81, + 0x58, 0xe6, 0x3a, 0x4b, 0x7a, 0x6b, 0xe8, 0x27, 0x5d, 0x5d, 0xea, 0x6d, + 0x1a, 0xbb, 0x50, 0x8b, 0xa5, 0x7c, 0x1d, 0xd2, 0xd8, 0x86, 0xf3, 0xa7, + 0xd7, 0xd7, 0x82, 0x61, 0x14, 0x7a, 0x4e, 0x32, 0xf3, 0x74, 0x38, 0x09, + 0x9b, 0xeb, 0x7c, 0x55, 0x53, 0x9e, 0x39, 0xec, 0xe1, 0xf0, 0xae, 0x7d, + 0xbe, 0x9a, 0x1d, 0x87, 0xab, 0x97, 0xc2, 0xa6, 0x05, 0xb7, 0xc2, 0x86, + 0x2d, 0xc8, 0x1e, 0x02, 0x0a, 0xa8, 0xaa, 0x4f, 0xb5, 0x70, 0x92, 0x97, + 0x75, 0x7a, 0x3c, 0xe0, 0xd3, 0x2c, 0x87, 0xf6, 0x53, 0x4f, 0x98, 0x69, + 0x2f, 0xb3, 0xa6, 0xeb, 0xb6, 0xfd, 0xf5, 0x07, 0x6d, 0x8c, 0x9d, 0xf7, + 0x70, 0x60, 0xe9, 0x34, 0x66, 0x9b, 0x54, 0x37, 0x20, 0xe2, 0x03, 0xb5, + 0x81, 0xff, 0xa1, 0x52, 0x72, 0x27, 0xae, 0x71, 0xe3, 0x4a, 0xf8, 0xda, + 0xa9, 0x8d, 0xb6, 0x2c, 0x88, 0xa2, 0xa4, 0xf3, 0x01, 0xdc, 0x16, 0x28, + 0xe2, 0xb3, 0x6d, 0x94, 0xa8, 0x17, 0xc7, 0x19, 0x35, 0x57, 0x75, 0x31, + 0x7b, 0x1e, 0x92, 0x44, 0xa3, 0xf4, 0xed, 0x84, 0x9c, 0x3e, 0xae, 0x71, + 0xfe, 0x12, 0x40, 0x76, 0x85, 0xa4, 0x98, 0x0b, 0x07, 0x48, 0x91, 0x22, + 0xff, 0x80, 0x07, 0x51, 0x5a, 0x67, 0x19, 0xa8, 0xf5, 0x11, 0x1b, 0x3a, + 0x2e, 0xae, 0x27, 0x6e, 0x26, 0x0e, 0xb0, 0x3c, 0x3b, 0xaf, 0xc0, 0x31, + 0xf6, 0x76, 0x95, 0x89, 0x66, 0xe5, 0x6d, 0x92, 0x12, 0xc8, 0x96, 0xc6, + 0x42, 0x33, 0x66, 0xb1, 0x3c, 0x9b, 0x45, 0xc8, 0xa2, 0x50, 0x37, 0xeb, + 0x7e, 0xf6, 0x67, 0x9e, 0xda, 0x28, 0x1b, 0x8f, 0x6d, 0xd4, 0x47, 0x71, + 0x6a, 0xa6, 0xd9, 0x0c, 0x3c, 0x49, 0xa8, 0xa5, 0x2a, 0x60, 0x88, 0xd0, + 0x44, 0x8f, 0xb0, 0xb8, 0x28, 0x8b, 0x84, 0xce, 0xdd, 0x05, 0x02, 0x22, + 0xab, 0x7c, 0x7a, 0xfe, 0x5a, 0x6c, 0x60, 0x7e, 0x63, 0x17, 0xc6, 0x8b, + 0xaa, 0x28, 0xf4, 0xa1, 0x59, 0x17, 0x93, 0x8e, 0xfc, 0x20, 0x7a, 0xd2, + 0x6d, 0x60, 0x53, 0x2f, 0xd3, 0x97, 0xaa, 0xc4, 0xc3, 0x1b, 0x81, 0x43, + 0xdd, 0x0b, 0xc2, 0x18, 0x31, 0x05, 0xb3, 0xce, 0xea, 0x46, 0x4a, 0x90, + 0xdb, 0x9f, 0x1e, 0x5b, 0xfd, 0x17, 0x6f, 0x84, 0x0d, 0x05, 0x4b, 0x4b, + 0xcb, 0x63, 0x6c, 0x15, 0x47, 0xcf, 0x8b, 0x77, 0x5d, 0xb7, 0x3a, 0x0e, + 0xe1, 0xc5, 0xd6, 0x4b, 0x8a, 0x81, 0x04, 0x18, 0x4f, 0x2e, 0x25, 0x1d, + 0x3b, 0x45, 0x00, 0xc0, 0xd9, 0x44, 0x23, 0xf0, 0x99, 0xf1, 0xe8, 0xc6, + 0xdc, 0x96, 0x38, 0xde, 0xa9, 0x85, 0x4a, 0x5c, 0x7b, 0x5d, 0xaf, 0x35, + 0xc8, 0x6d, 0xbe, 0x89, 0xd2, 0x2a, 0x5c, 0xec, 0xab, 0xe3, 0x8e, 0x69, + 0x19, 0x54, 0xb0, 0x61, 0xad, 0xfd, 0x0b, 0x68, 0x07, 0x2f, 0xe6, 0x13, + 0xa6, 0x83, 0xc1, 0x23, 0x45, 0x54, 0x9e, 0x19, 0xe0, 0xeb, 0x1b, 0x04, + 0xd4, 0xd9, 0x86, 0x6d, 0x38, 0xe4, 0x5b, 0x63, 0xbb, 0xb5, 0xb6, 0xd5, + 0xc5, 0x6e, 0xb1, 0xa5, 0xaf, 0x16, 0x6e, 0x8e, 0xbe, 0xb2, 0xc4, 0x2a, + 0xa8, 0x2d, 0x41, 0x5e, 0xd4, 0xc9, 0x28, 0x67, 0x65, 0x65, 0x98, 0x4c, + 0x0c, 0xd8, 0x40, 0x79, 0x59, 0x42, 0x77, 0xf3, 0x06, 0x81, 0x06, 0x43, + 0xfb, 0x97, 0xbf, 0x28, 0x41, 0xdc, 0xb5, 0x54, 0xb8, 0xdf, 0x9d, 0xc1, + 0x9d, 0xba, 0x4f, 0x11, 0x2a, 0x4e, 0xca, 0xf9, 0xc4, 0xcb, 0xfc, 0xeb, + 0xc1, 0x2a, 0x87, 0x75, 0x5c, 0x6f, 0xcb, 0x75, 0x36, 0xc2, 0x5e, 0xce, + 0x7a, 0x59, 0x6e, 0x7c, 0x6f, 0xe8, 0x3c, 0xa6, 0x7b, 0xe7, 0x36, 0x4d, + 0xfa, 0xad, 0xac, 0xbd, 0x61, 0xa3, 0x36, 0x53, 0xc4, 0x3d, 0xc5, 0xf5, + 0x46, 0x3a, 0x97, 0x5b, 0x66, 0x0a, 0x84, 0xa2, 0x31, 0xf0, 0xdc, 0xc3, + 0x30, 0xdc, 0x52, 0x93, 0x73, 0xab, 0x2b, 0x7e, 0x61, 0xb1, 0x35, 0xa2, + 0xff, 0x8a, 0x31, 0xf8, 0xfe, 0x0f, 0x22, 0x27, 0xba, 0xe2, 0x9e, 0xd3, + 0xfe, 0x7c, 0x2e, 0xe0, 0x94, 0x45, 0xc5, 0x2b, 0xd6, 0xaa, 0xb5, 0x74, + 0xd0, 0x5a, 0x5b, 0x61, 0x24, 0x69, 0x42, 0x8d, 0x5f, 0xe4, 0x3c, 0xe2, + 0xad, 0x15, 0x2b, 0x87, 0xbe, 0xec, 0xf0, 0x2e, 0x61, 0xb6, 0xc4, 0xe1, + 0xc6, 0x57, 0x9a, 0x5d, 0xc7, 0x35, 0x31, 0x6f, 0xb0, 0x14, 0xcc, 0x59, + 0xfc, 0x8a, 0x88, 0x08, 0xcb, 0x20, 0xdd, 0xc3, 0xc7, 0xa4, 0xdc, 0x9c, + 0x1f, 0x1b, 0x89, 0x28, 0x55, 0xab, 0x36, 0x9c, 0xae, 0x64, 0xb2, 0x7e, + 0x7f, 0x92, 0xb5, 0x79, 0x44, 0x0b, 0x2e, 0x0c, 0x3c, 0xc5, 0xd8, 0xd2, + 0x12, 0x15, 0xb9, 0x5e, 0x76, 0x40, 0xc5, 0xf5, 0x6f, 0x33, 0x41, 0xdf, + 0x83, 0x99, 0x91, 0x9b, 0xc1, 0x72, 0xf6, 0xbe, 0x87, 0xeb, 0x25, 0x82, + 0x49, 0x61, 0x44, 0xc1, 0x0f, 0x79, 0xd3, 0xae, 0x4d, 0x8d, 0xa0, 0xa5, + 0x40, 0x5f, 0xf2, 0x65, 0x94, 0xc3, 0x66, 0x18, 0xa1, 0x3c, 0x3b, 0x50, + 0x4b, 0xc9, 0xc0, 0x55, 0xb6, 0xf6, 0x69, 0xc2, 0x08, 0x10, 0x5f, 0xd7, + 0x7a, 0x62, 0xfb, 0x30, 0xf2, 0xdd, 0x25, 0x45, 0xfb, 0x8c, 0xaa, 0x56, + 0x89, 0xa5, 0xc8, 0x4a, 0xfc, 0x34, 0x57, 0x5a, 0x1c, 0x7b, 0x5b, 0xbd, + 0x7d, 0xfe, 0x43, 0xcb, 0xec, 0x3a, 0xdf, 0x59, 0x46, 0xd4, 0x01, 0xe3, + 0xee, 0xdf, 0x7e, 0xab, 0xc4, 0x55, 0x03, 0xdb, 0x7a, 0x3c, 0x56, 0x84, + 0xec, 0x39, 0x7c, 0xab, 0xd6, 0x64, 0x3b, 0x6e, 0xda, 0xa5, 0x1a, 0x48, + 0x13, 0x31, 0x3f, 0xe2, 0xaf, 0xee, 0x15, 0x74, 0xa6, 0x9d, 0x26, 0x6b, + 0xb4, 0x7d, 0x4d, 0xb2, 0x3e, 0xbe, 0x80, 0xdd, 0x81, 0xad, 0x81, 0x3a, + 0xa8, 0x27, 0x25, 0x13, 0xfc, 0x0e, 0xe6, 0x87, 0xdb, 0xf5, 0x08, 0x50, + 0x7a, 0x2c, 0x06, 0x66, 0x87, 0x07, 0xae, 0x14, 0xa8, 0xe2, 0x49, 0x6b, + 0x5f, 0x03, 0x89, 0x07, 0x8e, 0x1a, 0xa1, 0x5e, 0xa3, 0x9f, 0x1f, 0x1f, + 0xb1, 0x22, 0x14, 0x38, 0x9a, 0xc7, 0x4a, 0x7f, 0xd9, 0xb7, 0xd9, 0xbd, + 0xb5, 0x33, 0xa7, 0x97, 0xbb, 0x24, 0x5c, 0xb0, 0xee, 0x1a, 0xe3, 0x2d, + 0xf1, 0x0d, 0x33, 0x6e, 0x77, 0x02, 0x38, 0x35, 0x7d, 0x0f, 0x4a, 0xfb, + 0x12, 0x10, 0xee, 0x1e, 0xf8, 0x33, 0xa8, 0x19, 0xdb, 0xf1, 0xb3, 0x31, + 0x4b, 0x7b, 0xee, 0x3d, 0x0c, 0x71, 0x3a, 0x7c, 0xb7, 0xbc, 0x5e, 0x44, + 0x97, 0x99, 0xb8, 0x56, 0xee, 0x8a, 0xac, 0x72, 0x12, 0x38, 0xac, 0xe9, + 0x8d, 0x35, 0x05, 0x0a, 0x47, 0x27, 0xea, 0xd9, 0xbe, 0x21, 0xaa, 0xd5, + 0xb3, 0x57, 0x44, 0x15, 0xf9, 0xe7, 0x0d, 0x0d, 0x63, 0xc5, 0xa8, 0xe6, + 0x74, 0x9d, 0x52, 0xf4, 0xdd, 0x04, 0x1b, 0xea, 0x82, 0xe9, 0x5d, 0xca, + 0x43, 0xa5, 0x60, 0x6b, 0x16, 0xee, 0x1b, 0xe0, 0xc2, 0x28, 0x75, 0xad, + 0xb5, 0x87, 0xf2, 0xd2, 0x53, 0x32, 0x00, 0xa7, 0xe6, 0x15, 0xd0, 0x93, + 0x0d, 0x1f, 0x67, 0x56, 0xea, 0xaf, 0x98, 0xe4, 0x87, 0x04, 0x71, 0xfe, + 0xf9, 0x2e, 0xd0, 0x2d, 0x1f, 0x70, 0xa9, 0xee, 0x53, 0xec, 0xdb, 0xc7, + 0x3b, 0x3e, 0x42, 0x7e, 0xf3, 0x07, 0xdd, 0x6e, 0x3f, 0xca, 0x69, 0xcc, + 0xe3, 0x9b, 0x9b, 0xd6, 0xfd, 0xd2, 0x44, 0x27, 0xd5, 0xd0, 0x64, 0x2f, + 0xe8, 0x72, 0x26, 0x3c, 0xaf, 0x49, 0xcb, 0xb6, 0x69, 0xae, 0x95, 0xc1, + 0x24, 0x33, 0xc3, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0x82, + 0x67, 0x09, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x2e, 0x17, 0x13, + 0x41, 0xb7, 0x59, 0x5c, 0x7e, 0xe7, 0x05, 0xea, 0x41, 0xb7, 0x59, 0x5c, + 0x7e, 0xe7, 0x05, 0xea, 0x05, 0xc5, 0x64, 0xf0, 0xff, 0xc1, 0x0a, 0xf4, + 0x42, 0x83, 0x33, 0x33, 0x5d, 0x04, 0x75, 0x9c, 0x85, 0x9a, 0x74, 0x0a, + 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, 0x62, 0xa0, + 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x8e, 0xb4, 0xf5, + 0x90, 0xc1, 0x32, 0x90, 0x6a, 0xe5, 0x04, 0x8f, 0xcf, 0xc2, 0xed, 0xf7, + 0x79, 0x17, 0xfc, 0x2e, 0x73, 0xd6, 0xaa, 0xea, 0xfe, 0xb5, 0x0d, 0x3f, + 0x72, 0xf1, 0x5a, 0x24, 0x01, 0xcd, 0xda, 0x13, 0xc1, 0x2b, 0x8f, 0xa9, + 0x10, 0xf2, 0x28, 0xa0, 0x07, 0xbd, 0xc8, 0x20, 0x8c, 0x85, 0x74, 0x3c, + 0xcb, 0x87, 0xbd, 0x9f, 0x3f, 0xf0, 0xd8, 0x56, 0x35, 0x47, 0x97, 0x13, + 0xc9, 0x22, 0x59, 0x2b, 0x71, 0x3f, 0x46, 0x44, 0xf1, 0x3d, 0x3f, 0xc8, + 0x44, 0x43, 0x4d, 0x5c, 0x56, 0x92, 0x3a, 0x3b, 0x00, 0xb0, 0xc1, 0x42, + 0x91, 0xf8, 0xa5, 0x17, 0x42, 0xa8, 0x6a, 0x4d, 0x1e, 0xfd, 0x6f, 0x05, + 0xfb, 0x89, 0x38, 0x46, 0x67, 0x9f, 0x6d, 0xe5, 0x3b, 0xd5, 0xb1, 0xcc, + 0x8b, 0xa9, 0x67, 0x6f, 0x67, 0x1b, 0x5d, 0x7c, 0xe0, 0x0f, 0xd4, 0xdf, + 0x6e, 0xd1, 0x4a, 0xbb, 0x53, 0x57, 0x47, 0xe8, 0x0c, 0xe7, 0x64, 0x54, + 0x4f, 0x57, 0xb6, 0x8e, 0xce, 0xb3, 0x88, 0x70, 0x36, 0x06, 0x0f, 0xdc, + 0xa8, 0x1d, 0xda, 0x06, 0x2b, 0x03, 0xbb, 0xa4, 0x9d, 0x70, 0xb2, 0x04, + 0xa3, 0xfd, 0x9d, 0x8b, 0x6f, 0x89, 0x74, 0x3a, 0xff, 0xf5, 0x2f, 0x30, + 0x34, 0xb1, 0x6b, 0x21, 0xe3, 0xe9, 0x3a, 0xe0, 0x87, 0x17, 0xf5, 0xb4, + 0x81, 0xf2, 0x8f, 0x5e, 0x86, 0xf1, 0x69, 0x5e, 0x99, 0x20, 0x4c, 0x13, + 0xf6, 0x45, 0x46, 0x54, 0x8a, 0x96, 0xfb, 0x83, 0xee, 0xd3, 0x18, 0xd3, + 0x75, 0xa0, 0x6f, 0x32, 0x71, 0xde, 0x4c, 0x92, 0x22, 0x06, 0xca, 0xd0, + 0x9e, 0x1b, 0x32, 0xb5, 0xc9, 0x6c, 0x7e, 0x5f, 0xd1, 0x34, 0xfa, 0xb6, + 0x70, 0x8c, 0x7d, 0xcd, 0x68, 0x86, 0xd0, 0xb6, 0x97, 0x6d, 0x78, 0x96, + 0x48, 0x96, 0xe5, 0x28, 0x28, 0x87, 0xe1, 0xa6, 0xcc, 0x7f, 0x9c, 0x44, + 0x2e, 0xa4, 0x86, 0xef, 0xa9, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, + 0x75, 0x82, 0x54, 0x0d, 0x16, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x00, 0x84, 0x08, + 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xe0, 0x01, 0x3f, 0x41, 0xb7, + 0x59, 0x5c, 0x83, 0xe0, 0x01, 0x3f, 0x59, 0x27, 0x33, 0x2f, 0x22, 0x90, + 0x8f, 0xdf, 0x8f, 0x07, 0xfa, 0xa9, 0xeb, 0x8d, 0x26, 0x20, 0xc7, 0xc6, + 0x2a, 0x20, 0x3a, 0xdc, 0x09, 0xb3, 0xcd, 0x3d, 0x7c, 0x47, 0x10, 0xf5, + 0x62, 0xa0, 0x5b, 0xd8, 0x50, 0xe7, 0x56, 0xcb, 0xa1, 0xb8, 0x02, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa1, 0x9c, + 0xa0, 0x45, 0x5c, 0x35, 0x23, 0x76, 0xa8, 0xd0, 0x2d, 0x3f, 0xa5, 0x6d, + 0x7a, 0x4d, 0xe6, 0xc5, 0x95, 0x1d, 0xea, 0xcf, 0xd5, 0x75, 0x93, 0x57, + 0x57, 0xc1, 0x28, 0xc0, 0xb2, 0x8f, 0x42, 0x7f, 0x45, 0xd2, 0x6c, 0xc3, + 0xec, 0xe7, 0x48, 0x15, 0xf5, 0xb1, 0x10, 0xf3, 0xbc, 0x0e, 0x78, 0xef, + 0x2f, 0x15, 0x65, 0x7d, 0xe4, 0x09, 0xb7, 0x34, 0x5b, 0x66, 0x24, 0x0c, + 0x93, 0x63, 0xd8, 0xdc, 0xfd, 0x47, 0x1c, 0xeb, 0x4a, 0xd3, 0x86, 0x57, + 0x49, 0xb7, 0x8e, 0x15, 0x47, 0xa1, 0x61, 0xd8, 0x0a, 0x07, 0xb0, 0x97, + 0x08, 0x48, 0x99, 0x2b, 0x88, 0xcf, 0xe5, 0xe8, 0xd3, 0xda, 0xc2, 0xae, + 0x50, 0xd6, 0xbb, 0x64, 0xbf, 0x7a, 0x1f, 0xc8, 0xbe, 0x29, 0x6e, 0x8d, + 0xf1, 0x18, 0x7c, 0xf7, 0x13, 0x78, 0xf6, 0x23, 0x35, 0x9b, 0xf8, 0xf3, + 0x42, 0x4a, 0x5d, 0xef, 0x7d, 0x20, 0x62, 0x2e, 0xa6, 0xb5, 0xce, 0x94, + 0x0a, 0xfd, 0x8b, 0xf9, 0x12, 0xea, 0x53, 0x13, 0x45, 0x9d, 0xdd, 0x66, + 0x7d, 0x42, 0xb2, 0x3f, 0x65, 0xc4, 0x0d, 0xf8, 0x6d, 0xda, 0x0e, 0xe6, + 0x45, 0x35, 0xd4, 0x90, 0xc3, 0x9b, 0x8b, 0xb4, 0x39, 0xf1, 0x4f, 0x70, + 0x4a, 0x7f, 0x51, 0x1d, 0x3d, 0x80, 0x95, 0x4b, 0xd2, 0xb0, 0xd7, 0xb7, + 0xfe, 0xa8, 0x40, 0x38, 0x95, 0x48, 0x27, 0xf8, 0x23, 0xb9, 0xb0, 0xfe, + 0x58, 0x3a, 0x8e, 0x1a, 0x53, 0xf3, 0xa4, 0x59, 0xf9, 0xba, 0x9d, 0x9d, + 0x24, 0x8b, 0xe6, 0x39, 0xc1, 0xaf, 0x86, 0xdc, 0xf7, 0x27, 0x0d, 0x0b, + 0x85, 0xc4, 0x9d, 0x25, 0xb8, 0x81, 0xd4, 0x5d, 0xc2, 0x6a, 0xe4, 0x96, + 0x42, 0x87, 0xaa, 0x67, 0x17, 0xe1, 0x23, 0xa1, 0x32, 0x62, 0xa2, 0x65, + 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x00, 0x00, 0x00, 0x1f, + 0x7d, 0x89, 0x47, 0x47, 0xf5, 0xb7, 0xed, 0xb4, 0x95, 0xd6, 0x75, 0x78, + 0xeb, 0x1d, 0x4e, 0xa4, 0x3c, 0x47, 0x73, 0x5e, 0x8d, 0xd2, 0xd4, 0x7c, + 0xc6, 0x32, 0x4b, 0x5d, 0xc7, 0x78, 0xa2, 0xc7, 0xbd, 0xca, 0x06, 0x92, + 0xf9, 0xba, 0x4d, 0x7d, 0xe3, 0xe0, 0xf8, 0x0a, 0xec, 0x73, 0x88, 0xb6, + 0xab, 0x6d, 0x37, 0x6d, 0x37, 0xd2, 0xa5, 0x3d, 0xa8, 0xd0, 0x47, 0x7b, + 0xa1, 0x58, 0xf7, 0x07, 0x73, 0x23, 0x49, 0xfb, 0xa0, 0x7e, 0xae, 0x30, + 0x88, 0x4c, 0x2b, 0x75, 0x91, 0xd7, 0xe3, 0x5d, 0x80, 0x06, 0x12, 0xcc, + 0xb4, 0xe9, 0xdc, 0xc6, 0x01, 0x48, 0x91, 0x2a, 0x38, 0x93, 0x26, 0xee, + 0x01, 0x8a, 0xad, 0xdb, 0x02, 0xdc, 0x54, 0x5a, 0x08, 0x18, 0xf8, 0xe1, + 0xc2, 0x63, 0x80, 0x13, 0xd4, 0x4c, 0x06, 0xf0, 0x1d, 0x60, 0x66, 0x75, + 0x25, 0x43, 0xb9, 0xa1, 0x2b, 0xc7, 0x54, 0x81, 0x91, 0x2d, 0x66, 0xb2, + 0x74, 0xe7, 0x90, 0x8e, 0xd4, 0x03, 0xca, 0xef, 0x9a, 0x13, 0xfe, 0x40, + 0xf8, 0x42, 0x77, 0x52, 0x5b, 0xae, 0x22, 0xd0, 0x6b, 0xb6, 0x77, 0x41, + 0xff, 0x96, 0x80, 0xbc, 0x8f, 0xfa, 0xa1, 0xb6, 0xe4, 0xf1, 0x93, 0x1d, + 0x91, 0x96, 0x7b, 0x84, 0xc7, 0x60, 0x7e, 0x80, 0x98, 0xcd, 0x7b, 0x12, + 0x11, 0x41, 0x90, 0x33, 0x96, 0xc0, 0xeb, 0x6b, 0x9f, 0xb4, 0x1a, 0x2c, + 0x46, 0x80, 0xf0, 0x56, 0xe2, 0x4b, 0x32, 0x3c, 0x6a, 0xa1, 0x94, 0xca, + 0x46, 0xb4, 0x06, 0x63, 0x85, 0xcf, 0x62, 0x20, 0x79, 0xf2, 0x03, 0x97, + 0xa0, 0xa0, 0x44, 0x7b, 0x8e, 0x39, 0x16, 0xca, 0xe0, 0xb2, 0x04, 0x79, + 0xf8, 0x55, 0xf7, 0xe6, 0x3c, 0x3f, 0x67, 0x2f, 0x2b, 0x75, 0x39, 0x55, + 0x12, 0xd5, 0x85, 0xd4, 0x22, 0x37, 0xb6, 0x8c, 0x40, 0x47, 0x51, 0x11, + 0x88, 0xa1, 0xfa, 0x8f, 0x2d, 0x43, 0x41, 0x0a, 0x58, 0xe3, 0x38, 0x94, + 0xa0, 0xe1, 0xda, 0x1e, 0x7b, 0x07, 0x74, 0xc5, 0xe4, 0xd1, 0xb7, 0x3f, + 0xed, 0x46, 0x1e, 0x35, 0x84, 0x7c, 0x58, 0x3d, 0xc3, 0x99, 0x9f, 0x3f, + 0x0e, 0x30, 0x4f, 0xd5, 0xf4, 0x5d, 0x09, 0xef, 0x01, 0xe3, 0xa3, 0xbc, + 0x17, 0x74, 0xa4, 0x28, 0x5f, 0xab, 0xe5, 0x71, 0x66, 0x34, 0x2e, 0x29, + 0x2a, 0x24, 0xbb, 0x6d, 0x41, 0x16, 0x76, 0x86, 0x15, 0x67, 0xb5, 0x07, + 0x60, 0x13, 0xd2, 0x11, 0xa6, 0x90, 0x22, 0xc4, 0x17, 0x76, 0x38, 0x3a, + 0xaf, 0x51, 0xee, 0x4c, 0x9b, 0xfa, 0x84, 0x25, 0xd9, 0x6d, 0xd3, 0x8d, + 0x3e, 0xb2, 0x95, 0xd7, 0x8a, 0x83, 0x19, 0xaf, 0x7a, 0x2f, 0x6b, 0x87, + 0x36, 0x9e, 0xa3, 0x48, 0xdd, 0x8e, 0xe0, 0xdc, 0x40, 0xf3, 0xb7, 0xb4, + 0x3f, 0x95, 0x70, 0x5b, 0x67, 0xf7, 0xa1, 0xe9, 0x91, 0x7a, 0x94, 0xd1, + 0x81, 0xcc, 0xeb, 0x55, 0xb7, 0xc6, 0xd9, 0x0d, 0x59, 0x4a, 0x9f, 0x37, + 0x06, 0x6a, 0xda, 0x4e, 0xd3, 0xef, 0x35, 0x18, 0xa3, 0x90, 0x19, 0x72, + 0x2e, 0xcd, 0x03, 0x61, 0xf7, 0xb2, 0x0f, 0x69, 0x50, 0x47, 0x2f, 0xb3, + 0x10, 0x4a, 0xb1, 0x5d, 0xe8, 0x5a, 0x36, 0x07, 0xd6, 0x95, 0x03, 0x17, + 0x50, 0x1f, 0xa2, 0x58, 0x01, 0x0d, 0xfc, 0x8d, 0xcc, 0xf2, 0x6c, 0x4d, + 0x2f, 0x58, 0x02, 0xb6, 0x5e, 0x7c, 0x6f, 0x47, 0x3e, 0x13, 0x62, 0x33, + 0xc3, 0x7f, 0x64, 0x88, 0x30, 0x45, 0x5a, 0x6a, 0x8f, 0x49, 0x9a, 0xd1, + 0x6e, 0xf4, 0x3a, 0x3a, 0x9b, 0x50, 0x50, 0x8b, 0x59, 0x36, 0xbc, 0x0c, + 0x2c, 0x73, 0xec, 0x21, 0x0c, 0x95, 0xca, 0x32, 0x28, 0x07, 0x85, 0x91, + 0x0a, 0x90, 0xfe, 0x5a, 0x9d, 0x11, 0x09, 0xa2, 0x38, 0x9b, 0x0f, 0x22, + 0xc1, 0x44, 0x09, 0xca, 0x50, 0xe0, 0x4e, 0x01, 0x24, 0xef, 0x8a, 0x58, + 0xa5, 0x56, 0x69, 0x9b, 0x2e, 0x72, 0xf5, 0xb2, 0xbe, 0xa3, 0xca, 0x84, + 0x36, 0x36, 0x84, 0xb0, 0x88, 0x88, 0x74, 0x60, 0xc3, 0xf2, 0x6b, 0x19, + 0x44, 0xb6, 0x8b, 0x02, 0x38, 0x7d, 0x6e, 0x26, 0x89, 0x37, 0xae, 0xc5, + 0x67, 0x9c, 0x4e, 0x5b, 0xeb, 0x68, 0xc1, 0x3a, 0xb9, 0x10, 0xad, 0x10, + 0x00, 0x1f, 0x6a, 0x9a, 0xfe, 0x6a, 0x7e, 0x03, 0xcc, 0x7d, 0x0d, 0x37, + 0xea, 0x91, 0xfa, 0xf4, 0xdb, 0x22, 0x9b, 0x91, 0x70, 0x07, 0x6d, 0xa8, + 0xd6, 0x95, 0x49, 0x66, 0xd6, 0xbc, 0xd1, 0x57, 0x6e, 0xa5, 0x1c, 0x96, + 0x16, 0xaf, 0x94, 0xa5, 0x00, 0x06, 0x38, 0x55, 0xe9, 0xdc, 0xb8, 0x38, + 0x66, 0x26, 0x2d, 0xac, 0x1a, 0xff, 0x95, 0x52, 0xa3, 0x97, 0x58, 0xd9, + 0xe9, 0x35, 0x54, 0x3d, 0x6a, 0xae, 0xe6, 0xcd, 0x00, 0xbe, 0x68, 0x83, + 0x05, 0x5a, 0x65, 0xb8, 0x8c, 0x94, 0x87, 0x6c, 0x27, 0x82, 0x7b, 0x4a, + 0x48, 0x1e, 0x6e, 0x42, 0xc1, 0xe5, 0xd8, 0x25, 0x9b, 0x8a, 0xe4, 0x2b, + 0x85, 0x6f, 0x40, 0x75, 0x65, 0x9e, 0xc5, 0x03, 0xd1, 0x14, 0x82, 0x91, + 0x15, 0x59, 0x66, 0x48, 0x13, 0xfe, 0xd3, 0x17, 0x1e, 0xff, 0xec, 0x58, + 0x43, 0xb5, 0xb9, 0xbf, 0xad, 0x33, 0xb2, 0x91, 0xe2, 0xb5, 0x3b, 0x57, + 0xd6, 0xb1, 0x55, 0x6c, 0xa2, 0xac, 0x7f, 0x5e, 0x9b, 0x28, 0xa7, 0x98, + 0x44, 0x46, 0x1d, 0x30, 0x16, 0x2f, 0xa5, 0x35, 0x85, 0x68, 0xaa, 0x92, + 0x0f, 0x51, 0xb3, 0x88, 0x42, 0xf3, 0x8d, 0xa0, 0x06, 0x8f, 0x91, 0xcf, + 0xf4, 0x8f, 0xbc, 0x95, 0xb1, 0x57, 0xa5, 0x61, 0xd9, 0x1e, 0x40, 0x29, + 0x79, 0x63, 0x84, 0xfd, 0xf5, 0x93, 0xd4, 0x5b, 0xb9, 0xdf, 0x5d, 0x56, + 0xc5, 0xfb, 0xcb, 0xee, 0x1f, 0x3b, 0x9c, 0x02, 0x0c, 0x7d, 0x7f, 0xbb, + 0x81, 0x8d, 0xbb, 0xa5, 0x83, 0x5c, 0x4f, 0xf1, 0x08, 0xf8, 0x18, 0x87, + 0xab, 0x74, 0x5c, 0xa7, 0x57, 0xa8, 0xcf, 0xf4, 0x2f, 0xcc, 0xd2, 0xcc, + 0x5b, 0x99, 0x00, 0xbc, 0xe5, 0x06, 0x42, 0x24, 0xc9, 0xf0, 0x23, 0x45, + 0x60, 0xf1, 0x34, 0xb0, 0x99, 0xb4, 0x24, 0x94, 0x71, 0x76, 0x16, 0x32, + 0x2d, 0xb5, 0x98, 0x38, 0x9e, 0x02, 0xe4, 0x1b, 0xc9, 0x3f, 0x20, 0xa3, + 0x94, 0xc2, 0x4c, 0xff, 0x81, 0x95, 0x05, 0xd5, 0x8c, 0x13, 0xd2, 0xb8, + 0x54, 0xf5, 0x55, 0xff, 0x4a, 0xfa, 0xd0, 0x93, 0xa7, 0x49, 0x5f, 0x43, + 0x6d, 0x23, 0x3e, 0x5f, 0x37, 0xb1, 0x05, 0xb1, 0xc7, 0x99, 0xb5, 0xab, + 0xbe, 0x04, 0x65, 0xef, 0xb0, 0x79, 0x62, 0x47, 0xbc, 0x7b, 0x57, 0x74, + 0xea, 0xac, 0x2d, 0x45, 0xfc, 0x65, 0x26, 0x3d, 0xf7, 0x91, 0x0e, 0xbd, + 0x78, 0x78, 0x72, 0x6b, 0x8a, 0xfe, 0x8d, 0x6e, 0x03, 0x6d, 0x0c, 0x3a, + 0x52, 0xb5, 0xc4, 0x9c, 0x7d, 0x82, 0xdd, 0x52, 0x75, 0xb7, 0xe3, 0xe3, + 0xff, 0xfc, 0x31, 0xa9, 0xc6, 0xd7, 0xa4, 0x1d, 0x05, 0xde, 0x8b, 0x82, + 0x1d, 0x7d, 0xd0, 0xb3, 0x25, 0xcc, 0x45, 0xce, 0x8e, 0x4c, 0x2b, 0xca, + 0x60, 0x15, 0x6c, 0xba, 0x5d, 0x6b, 0x41, 0x22, 0x62, 0x05, 0xef, 0x55, + 0x04, 0x84, 0x2e, 0x14, 0xe6, 0x5e, 0x23, 0x83, 0x82, 0x39, 0xbe, 0x79, + 0xd1, 0x29, 0xe3, 0xac, 0x54, 0x63, 0x03, 0xf9, 0xa0, 0xb7, 0xb7, 0xd4, + 0x37, 0xdc, 0x91, 0xfc, 0x1e, 0x96, 0xe9, 0xcc, 0x66, 0x6b, 0xa4, 0x67, + 0xb8, 0xc8, 0xed, 0x69, 0x4f, 0x08, 0xa2, 0xaf, 0x34, 0x3b, 0xcb, 0x70, + 0xf2, 0x8c, 0xae, 0xc9, 0x2e, 0x96, 0xe3, 0x47, 0x31, 0x36, 0x13, 0x62, + 0xc8, 0xcc, 0x18, 0x7f, 0x48, 0xea, 0x2e, 0xf4, 0x87, 0x09, 0xa2, 0x68, + 0x19, 0xf7, 0x30, 0x8b, 0x72, 0x65, 0xa6, 0x9f, 0xf3, 0x96, 0x22, 0x68, + 0x59, 0x72, 0x69, 0x2f, 0xdd, 0x88, 0x4c, 0x04, 0xd2, 0xb9, 0x71, 0x0c, + 0xd7, 0x2d, 0xd7, 0xef, 0xce, 0x33, 0x7f, 0x5a, 0xe7, 0x80, 0xba, 0x85, + 0xc0, 0xd3, 0x83, 0x27, 0xe9, 0x11, 0x40, 0x67, 0xb7, 0xf7, 0x8f, 0x8e, + 0x8f, 0x93, 0x7d, 0xfb, 0x04, 0x0f, 0x1e, 0x6d, 0xd7, 0xa9, 0xc6, 0x53, + 0x29, 0x58, 0x55, 0xe5, 0x2d, 0xe1, 0x05, 0xe3, 0x00, 0x3b, 0x6f, 0xb9, + 0xdd, 0x5f, 0x42, 0x47, 0x0a, 0x79, 0x43, 0xef, 0x84, 0x47, 0x6d, 0x37, + 0xba, 0x37, 0xb3, 0xef, 0xae, 0x0b, 0xc9, 0x45, 0x32, 0x1a, 0x9a, 0x94, + 0x3f, 0xb8, 0xc7, 0x72, 0xd8, 0x90, 0xb1, 0x61, 0x62, 0xe0, 0x0f, 0xd1, + 0xef, 0x94, 0x04, 0x2f, 0xff, 0xd6, 0x7e, 0x14, 0x81, 0xb8, 0x62, 0xcc, + 0x4e, 0x76, 0x0a, 0xc6, 0x1f, 0x58, 0x51, 0xa1, 0x14, 0xe8, 0xde, 0x2f, + 0xe6, 0x2e, 0xb2, 0xe2, 0xda, 0x24, 0x47, 0xe1, 0xcf, 0x26, 0x2a, 0xfc, + 0xb1, 0xbf, 0xae, 0x1a, 0xb0, 0x4d, 0x3d, 0x97, 0x4d, 0x18, 0xfb, 0x0d, + 0x00, 0x64, 0x40, 0x75, 0x6a, 0x78, 0x3a, 0x60, 0xda, 0x54, 0x06, 0x92, + 0xb6, 0xa9, 0x1c, 0x36, 0xeb, 0x26, 0x46, 0x10, 0x0d, 0x5d, 0x3e, 0x13, + 0xca, 0x7e, 0xb1, 0xbb, 0xa7, 0x37, 0x71, 0x7c, 0x09, 0xd4, 0x5d, 0xd4, + 0x59, 0xb0, 0x46, 0x37, 0x06, 0x2a, 0xdb, 0xd3, 0x0c, 0x26, 0x0a, 0x9d, + 0x18, 0x65, 0x8a, 0xb4, 0xf1, 0x1b, 0xfd, 0x50, 0x32, 0x6a, 0xa9, 0x2f, + 0x0c, 0x46, 0x1f, 0x9b, 0x50, 0x86, 0xf1, 0x91, 0xf0, 0xe0, 0xc2, 0x8d, + 0x84, 0x8e, 0xfe, 0x6d, 0x1e, 0x6e, 0xd4, 0x93, 0xf1, 0x56, 0x4b, 0x3b, + 0x20, 0x10, 0x1f, 0x6a, 0xc5, 0xf3, 0x8c, 0x2f, 0x88, 0x32, 0x28, 0xbe, + 0x05, 0x9a, 0x1b, 0x7d, 0x1b, 0xaa, 0x2d, 0xa5, 0xe4, 0x82, 0xd0, 0xf3, + 0x65, 0x5a, 0xd5, 0xa5, 0x3e, 0xdd, 0xee, 0x98, 0x03, 0xf4, 0x63, 0x6e, + 0xe5, 0x60, 0x35, 0x54, 0xf9, 0xf8, 0x5c, 0x8c, 0x02, 0x5f, 0xa5, 0xf3, + 0xb2, 0xf8, 0x47, 0xce, 0x74, 0xbc, 0xf5, 0xcc, 0x1e, 0x0f, 0x8b, 0x6f, + 0x1f, 0xd3, 0x11, 0x2d, 0x10, 0x40, 0x5d, 0xb2, 0x45, 0x6f, 0xd3, 0xc3, + 0x44, 0xc5, 0x74, 0xab, 0x29, 0x2f, 0x4c, 0x7e, 0xc8, 0x57, 0xcb, 0xaf, + 0x0b, 0x44, 0x12, 0xa2, 0x1d, 0x3b, 0x1c, 0xfa, 0xf5, 0xd3, 0xe6, 0x75, + 0x4e, 0xc7, 0x04, 0x99, 0xd8, 0x32, 0x14, 0x83, 0xda, 0x35, 0xf0, 0xfa, + 0x67, 0x15, 0x8d, 0xab, 0xa9, 0x30, 0x12, 0xd0, 0x4a, 0xb6, 0x09, 0x20, + 0x89, 0x19, 0xee, 0x60, 0x4b, 0x97, 0xd2, 0x38, 0x2a, 0x57, 0x36, 0x22, + 0xe9, 0x02, 0x2f, 0x2d, 0x30, 0x93, 0x88, 0x14, 0x99, 0xa3, 0x31, 0x93, + 0x2a, 0x33, 0x58, 0xae, 0xe6, 0xe6, 0xcc, 0x89, 0x02, 0x95, 0x52, 0xe3, + 0x60, 0xed, 0xd5, 0x9d, 0xac, 0x7f, 0x1f, 0x35, 0x54, 0xd6, 0x89, 0x8e, + 0xed, 0x13, 0x7f, 0xe6, 0xce, 0xba, 0xe7, 0x00, 0x30, 0x7f, 0x46, 0x25, + 0xdc, 0xb3, 0x22, 0xac, 0xef, 0x54, 0xef, 0x17, 0xf8, 0xdc, 0xc4, 0x12, + 0xdb, 0x40, 0xe8, 0x20, 0x7a, 0x1b, 0x5a, 0x6b, 0x37, 0x8d, 0x46, 0xfd, + 0x26, 0xa5, 0x1f, 0x24, 0xb3, 0xaa, 0xe4, 0xb6, 0x1c, 0x93, 0xd9, 0x77, + 0xc2, 0x66, 0xf7, 0x0a, 0xf8, 0xca, 0xa1, 0xfb, 0xa6, 0x78, 0x9c, 0xc3, + 0x7f, 0x40, 0x63, 0x9a, 0x98, 0x52, 0x23, 0xb2, 0x51, 0x0f, 0xab, 0xf2, + 0xa0, 0x41, 0x87, 0x79, 0x18, 0x2e, 0x50, 0x8a, 0x6a, 0x99, 0xc7, 0xef, + 0x0c, 0x33, 0xee, 0xf2, 0x76, 0x26, 0x40, 0x4b, 0xb7, 0x75, 0xb0, 0x8c, + 0x99, 0x8c, 0x96, 0x8a, 0xc3, 0xb6, 0xfd, 0xa2, 0x62, 0x49, 0x29, 0x8c, + 0xc4, 0xfe, 0xc8, 0xe9, 0x89, 0xeb, 0xc7, 0x59, 0x08, 0x99, 0xd3, 0x73, + 0xea, 0x64, 0x50, 0x9d, 0x09, 0x36, 0xe3, 0x85, 0xc4, 0xac, 0x3e, 0x87, + 0x11, 0x5d, 0xf4, 0x5b, 0x21, 0x91, 0xf6, 0x34, 0xfb, 0x08, 0x15, 0xd2, + 0xe1, 0xcb, 0x8c, 0x72, 0xca, 0x88, 0xd6, 0xb1, 0x65, 0xd4, 0xd7, 0x6e, + 0x10, 0x7b, 0x15, 0x0f, 0x41, 0xd7, 0x12, 0x49, 0xcc, 0x8d, 0x39, 0x13, + 0x9c, 0x22, 0x1d, 0x15, 0x43, 0xc1, 0x8a, 0x6f, 0xf3, 0x1d, 0x46, 0x74, + 0xb3, 0x1f, 0xa4, 0xbd, 0x17, 0x20, 0x69, 0x57, 0x53, 0x2c, 0x6a, 0xec, + 0x29, 0xac, 0x02, 0xb1, 0x47, 0x83, 0xf0, 0x2f, 0xc9, 0x20, 0xcc, 0x14, + 0xf0, 0xe4, 0x4f, 0x43, 0xe1, 0x98, 0x3d, 0xbd, 0x2c, 0x48, 0x7f, 0xd5, + 0xd6, 0x33, 0x98, 0xd2, 0x9d, 0xa8, 0xe0, 0xb1, 0x85, 0xe0, 0x14, 0x96, + 0xec, 0xde, 0x18, 0xc4, 0xe9, 0x8f, 0x67, 0x24, 0x48, 0x6c, 0xf9, 0xaf, + 0xfb, 0x89, 0xd1, 0x35, 0xc9, 0x0d, 0xe9, 0x22, 0x08, 0xef, 0x8b, 0x27, + 0x9d, 0x18, 0xa1, 0x19, 0x7d, 0x20, 0xd1, 0xc1, 0x1b, 0x99, 0x59, 0xea, + 0xba, 0xae, 0xe4, 0x09, 0xd4, 0xb6, 0x23, 0x08, 0x5f, 0x0c, 0x0b, 0x49, + 0x69, 0x8a, 0x36, 0x02, 0xf5, 0x32, 0x3e, 0xfb, 0xb4, 0xdb, 0x45, 0x9d, + 0x19, 0x9d, 0x4b, 0xcf, 0xee, 0xa7, 0xbc, 0x5a, 0x06, 0x4e, 0x43, 0x52, + 0xd3, 0xd2, 0x4a, 0x0e, 0x21, 0x08, 0xd6, 0xc0, 0x93, 0x7d, 0xe8, 0xff, + 0x04, 0xd4, 0xef, 0xe8, 0x0d, 0xd1, 0xe7, 0x74, 0xf2, 0x56, 0x66, 0x51, + 0x4c, 0x79, 0xf4, 0x12, 0x9f, 0xf4, 0xd2, 0x61, 0x12, 0x60, 0xc2, 0xfb, + 0x98, 0x5c, 0xed, 0x73, 0x13, 0x06, 0xa7, 0xce, 0x86, 0xea, 0x65, 0x26, + 0xc0, 0xfc, 0xe6, 0xc1, 0xdb, 0xe0, 0xcc, 0x13, 0xd3, 0x63, 0x5f, 0x2d, + 0xfb, 0x5a, 0x95, 0x9e, 0x27, 0x05, 0x3d, 0xd0, 0x1b, 0xaf, 0x29, 0x79, + 0x70, 0x69, 0x12, 0xc7, 0xe6, 0xc2, 0x57, 0x40, 0x31, 0xcb, 0x50, 0xd4, + 0xfe, 0xf3, 0xb1, 0x3e, 0x79, 0xdb, 0xcf, 0xdd, 0x9a, 0x86, 0x2a, 0x58, + 0xb3, 0x51, 0xe6, 0x74, 0x9f, 0x1e, 0xbd, 0xb1, 0x57, 0xd8, 0xa9, 0xe8, + 0xbf, 0x5e, 0x15, 0xcf, 0x2c, 0x4b, 0x00, 0x88, 0x8d, 0x10, 0x15, 0x25, + 0xeb, 0x36, 0xe6, 0x4b, 0x9c, 0xe5, 0x82, 0x26, 0x6e, 0x61, 0xb3, 0x69, + 0xf4, 0x4c, 0x21, 0x15, 0x64, 0x36, 0x0c, 0x8e, 0x77, 0xc1, 0x89, 0xd5, + 0xfd, 0xb0, 0x81, 0x7c, 0x90, 0x7d, 0xdf, 0xd3, 0xe5, 0xc9, 0xd8, 0x4f, + 0xc5, 0x85, 0x12, 0xb7, 0x02, 0x63, 0xb7, 0x24, 0x2c, 0xeb, 0xb5, 0x89, + 0x59, 0x44, 0x2b, 0xa3, 0x8e, 0xfd, 0x42, 0x48, 0x57, 0x57, 0x17, 0x71, + 0xec, 0xe0, 0x0e, 0x72, 0xfc, 0x6c, 0xa2, 0xa5, 0xfb, 0xd3, 0x17, 0xb7, + 0x1a, 0x19, 0xe4, 0x93, 0x22, 0x4d, 0xde, 0x22, 0x4f, 0xb8, 0x42, 0x3a, + 0x06, 0xa7, 0x35, 0x20, 0x57, 0xc4, 0xe6, 0x0c, 0x7f, 0xae, 0x59, 0xfe, + 0xe6, 0xe7, 0x17, 0x0c, 0xec, 0x33, 0x4d, 0x6e, 0x0a, 0xd8, 0x6e, 0xe2, + 0x27, 0x39, 0x3e, 0x32, 0x1b, 0xf8, 0x9d, 0xd5, 0xdb, 0x38, 0xee, 0xe6, + 0x58, 0xbf, 0xfa, 0x05, 0xc0, 0x7e, 0xf1, 0x70, 0x43, 0x8d, 0xc5, 0x5f, + 0xd1, 0xb8, 0x5f, 0xe2, 0xb4, 0xd7, 0x81, 0xd7, 0x04, 0x8d, 0x06, 0x99, + 0x7f, 0x0b, 0x87, 0xea, 0xe3, 0x9a, 0x51, 0xd4, 0xd4, 0x47, 0xeb, 0x29, + 0x98, 0x56, 0xa7, 0x2f, 0x07, 0xa3, 0x04, 0x88, 0xe9, 0x13, 0x4f, 0xac, + 0x0f, 0x29, 0xda, 0xc7, 0x53, 0x2c, 0x9d, 0x00, 0x7a, 0x9e, 0x7a, 0x74, + 0xac, 0xce, 0xf2, 0xfa, 0xe6, 0xd5, 0xa2, 0x0c, 0xab, 0x80, 0xa9, 0x9f, + 0x46, 0x39, 0xe6, 0x8c, 0xc8, 0xf3, 0x90, 0xca, 0x9e, 0xb6, 0xdd, 0x0c, + 0xf9, 0xe6, 0x8c, 0x83, 0x46, 0xb0, 0x12, 0xe3, 0x47, 0xba, 0x12, 0x7b, + 0xf5, 0xb7, 0xe6, 0x49, 0x8c, 0x78, 0x45, 0xc2, 0xa3, 0x7a, 0xdf, 0x47, + 0xa9, 0x80, 0x41, 0x03, 0x29, 0x7f, 0xeb, 0xa1, 0xa8, 0x4b, 0x4f, 0xa8, + 0x41, 0x57, 0xb9, 0xfe, 0x06, 0xa9, 0xce, 0xbc, 0x27, 0x81, 0xed, 0x1b, + 0xab, 0x19, 0x4a, 0xbf, 0x6b, 0xe0, 0xef, 0x58, 0xfb, 0xfa, 0xe3, 0xa1, + 0x85, 0x02, 0x0d, 0x57, 0x9b, 0x04, 0x2b, 0xc0, 0x8e, 0x21, 0x73, 0xdc, + 0x34, 0x21, 0x63, 0x1d, 0xaf, 0xd8, 0xe0, 0x42, 0xaa, 0x45, 0xe9, 0x3c, + 0x44, 0xc5, 0x22, 0x77, 0xc0, 0xe5, 0xa5, 0xf7, 0xa4, 0x83, 0x66, 0xad, + 0xc7, 0x4a, 0x32, 0xc6, 0x7e, 0xca, 0x8f, 0x35, 0xa7, 0x88, 0x64, 0x56, + 0x45, 0x25, 0xec, 0xfa, 0x85, 0x61, 0x34, 0x0d, 0x83, 0x92, 0x1e, 0xf0, + 0x58, 0x4c, 0x47, 0x93, 0xe5, 0x17, 0xaa, 0xe8, 0x22, 0x53, 0xa6, 0x9e, + 0x3d, 0xb1, 0x47, 0x25, 0x09, 0x93, 0x93, 0x9d, 0x08, 0x31, 0x5b, 0xdc, + 0x07, 0x1f, 0x82, 0xbc, 0x88, 0x31, 0xbd, 0xc3, 0xa6, 0x4d, 0x2a, 0xed, + 0xf9, 0xc2, 0x76, 0x1e, 0xa1, 0xfd, 0xca, 0x7e, 0xcd, 0x62, 0x83, 0x06, + 0xca, 0xf3, 0x13, 0xcd, 0x25, 0xa1, 0x45, 0x0c, 0x3a, 0xc3, 0xb1, 0x3b, + 0xf5, 0xa1, 0x12, 0x1e, 0x90, 0xff, 0xf6, 0x56, 0x06, 0x7b, 0x14, 0xb7, + 0x37, 0x5c, 0x7a, 0xe9, 0x7e, 0xca, 0x33, 0x05, 0xc0, 0x7c, 0xa7, 0xcd, + 0xb2, 0x11, 0x2a, 0x0c, 0xe7, 0x2b, 0x36, 0x11, 0x5f, 0xa6, 0xba, 0xc5, + 0x56, 0x6f, 0x7c, 0xb7, 0x8c, 0xee, 0x54, 0xa0, 0x8c, 0x59, 0x85, 0x22, + 0x98, 0xad, 0xbb, 0x93, 0x66, 0x23, 0xfa, 0x00, 0x81, 0x88, 0xb0, 0x0a, + 0x1d, 0xfb, 0x66, 0xa2, 0x14, 0x88, 0x2a, 0x4e, 0x41, 0xb4, 0x89, 0x91, + 0x6d, 0x73, 0x5a, 0x3c, 0x4f, 0xc9, 0xd3, 0xa3, 0x08, 0x10, 0xe0, 0xb2, + 0xc2, 0xda, 0xa1, 0x23, 0x91, 0x40, 0x92, 0x51, 0xa0, 0xf4, 0x92, 0x01, + 0xb1, 0xa7, 0xd1, 0x80, 0x1d, 0xf0, 0x30, 0x29, 0xed, 0x0b, 0xec, 0x80, + 0x02, 0x09, 0x4e, 0x8d, 0x3f, 0xdf, 0x7a, 0x53, 0xcf, 0xed, 0xad, 0x6c, + 0x1b, 0x9c, 0x6a, 0x25, 0xff, 0xc3, 0xd7, 0xe9, 0x99, 0xf8, 0xa6, 0x8d, + 0x3f, 0x4a, 0x17, 0xf1, 0xe4, 0x54, 0x2b, 0x55, 0x67, 0x4a, 0xd2, 0xee, + 0x29, 0x53, 0x44, 0x71, 0x87, 0x6c, 0x98, 0xef, 0x8f, 0x23, 0x06, 0xf5, + 0x56, 0x9d, 0x12, 0x1f, 0x9c, 0xe5, 0x22, 0x51, 0x6e, 0x5b, 0x41, 0x7e, + 0x89, 0x6f, 0x40, 0x4b, 0xd6, 0x81, 0xd1, 0x7f, 0x63, 0xd1, 0x3f, 0xa1, + 0x60, 0xe2, 0xe4, 0x01, 0x7b, 0x76, 0x86, 0xf5, 0x13, 0x4f, 0xa2, 0x50, + 0xaf, 0xc8, 0x74, 0xe3, 0x2f, 0x7a, 0xd0, 0x81, 0x3e, 0xcf, 0xfa, 0x31, + 0xeb, 0xc0, 0xc3, 0x07, 0xc7, 0xe8, 0xb2, 0x9a, 0x51, 0xb9, 0xf7, 0x98, + 0x55, 0x90, 0xce, 0xdd, 0x60, 0xac, 0xc9, 0x08, 0x5e, 0xe8, 0xae, 0xad, + 0x22, 0xed, 0x73, 0x29, 0xa1, 0x5f, 0x43, 0x27, 0x2f, 0xb9, 0x38, 0x78, + 0x9d, 0x32, 0x1f, 0xff, 0xe0, 0xf7, 0x77, 0x37, 0xdf, 0xd1, 0xcb, 0xf7, + 0x50, 0xcd, 0x4a, 0xe9, 0xdd, 0x21, 0x50, 0xa0, 0xf2, 0x7f, 0x73, 0x31, + 0xae, 0xfb, 0x6e, 0xb7, 0x99, 0x1a, 0x43, 0x16, 0x5a, 0x17, 0x3a, 0x77, + 0xf1, 0xc3, 0xa8, 0x33, 0xde, 0xc6, 0x5b, 0xe8, 0x59, 0x53, 0x19, 0xf9, + 0x7f, 0xc5, 0x20, 0x56, 0xfc, 0x99, 0x19, 0x38, 0x77, 0x92, 0xe4, 0x7c, + 0xf3, 0x96, 0xac, 0x22, 0x87, 0x16, 0x5d, 0x43, 0x43, 0x65, 0x4e, 0x46, + 0x45, 0x44, 0x2d, 0x3f, 0x7f, 0x9d, 0xf0, 0x0c, 0x0e, 0x5b, 0xf7, 0x5b, + 0x31, 0x71, 0xcd, 0x27, 0x5b, 0xa3, 0x4a, 0x7a, 0xef, 0x28, 0x1c, 0x9a, + 0x98, 0x26, 0x95, 0xda, 0x35, 0x8d, 0x0d, 0xce, 0x04, 0xa2, 0xed, 0x8a, + 0xbb, 0x46, 0xf7, 0xca, 0x2b, 0x92, 0xd7, 0x8d, 0xae, 0x1b, 0xf1, 0xe4, + 0x9d, 0x67, 0x5b, 0x03, 0x57, 0xd1, 0xf6, 0x1e, 0x8f, 0x03, 0x7d, 0x8d, + 0xb8, 0x4a, 0x74, 0x99, 0x0f, 0x76, 0x3d, 0xe7, 0xb3, 0x4f, 0xdb, 0x9f, + 0x5c, 0xa7, 0x1b, 0x23, 0xa7, 0x99, 0x48, 0x34, 0x65, 0x46, 0x32, 0x83, + 0xc8, 0xcb, 0xee, 0xb3, 0xab, 0xe8, 0x99, 0xc9, 0x8a, 0x50, 0x34, 0x15, + 0x13, 0x52, 0xda, 0x12, 0xbd, 0x20, 0x21, 0x41, 0x57, 0x2a, 0xa0, 0x2c, + 0xba, 0x6c, 0xa9, 0xed, 0xcb, 0x03, 0xc9, 0x10, 0x26, 0x9d, 0x31, 0x52, + 0xf2, 0x66, 0x88, 0x2e, 0x51, 0x80, 0x76, 0xc9, 0xce, 0xfb, 0x8a, 0x4a, + 0x10, 0x8c, 0x83, 0x34, 0xe9, 0x02, 0xfc, 0x4e, 0xfe, 0xaa, 0x6c, 0xd6, + 0xcc, 0x81, 0x5d, 0x45, 0xc8, 0xa6, 0xa0, 0x3a, 0xef, 0xa4, 0xc5, 0xf1, + 0xba, 0x32, 0x93, 0x12, 0x2b, 0x59, 0x68, 0x19, 0x21, 0xe8, 0xd2, 0x8f, + 0x1d, 0x38, 0xd3, 0x56, 0x54, 0x38, 0x1d, 0xbb, 0xa0, 0x69, 0xe4, 0x82, + 0xfc, 0x21, 0x55, 0xee, 0xf8, 0x84, 0x7b, 0xab, 0x5e, 0x83, 0x42, 0x7e, + 0x18, 0xab, 0x3b, 0x1b, 0xea, 0x0e, 0xa0, 0xbd, 0x74, 0x33, 0x6d, 0x8a, + 0xe6, 0x7f, 0xe9, 0x78, 0xcf, 0xc9, 0xfd, 0xb6, 0x95, 0x90, 0x0e, 0x76, + 0x1a, 0xce, 0xb5, 0x72, 0x3f, 0x48, 0xa2, 0xcc, 0x6b, 0xf6, 0x6e, 0x72, + 0xef, 0x0c, 0x5f, 0x1b, 0xb4, 0x61, 0x5d, 0xf2, 0xc3, 0x9f, 0x09, 0x5b, + 0x60, 0xd8, 0xfd, 0xb0, 0x12, 0xe3, 0xc3, 0xeb, 0x4a, 0x5b, 0x26, 0xf8, + 0x5c, 0xfe, 0xd8, 0x93, 0xf1, 0xc8, 0x38, 0x29, 0x2c, 0xfe, 0x76, 0xf8, + 0xf5, 0x7b, 0x1b, 0x48, 0x6e, 0x27, 0xc3, 0xc8, 0xba, 0x23, 0xa8, 0x23, + 0xa3, 0xae, 0x48, 0x24, 0x83, 0x13, 0x6c, 0xbb, 0xfe, 0x7c, 0x36, 0xf7, + 0x7e, 0xe6, 0x1b, 0xd8, 0x86, 0x39, 0xc1, 0x84, 0x89, 0x2d, 0x0e, 0x80, + 0x3f, 0xb9, 0x5f, 0x25, 0x05, 0x85, 0xfa, 0x34, 0x23, 0xb9, 0xfa, 0xa2, + 0x2b, 0xaa, 0x40, 0x6d, 0xd3, 0x9b, 0xc9, 0x6a, 0xf7, 0xe8, 0x60, 0x2b, + 0x38, 0xe2, 0x79, 0xc9, 0x37, 0x62, 0x7d, 0xe0, 0x7a, 0xb5, 0xc6, 0x1f, + 0x80, 0xb1, 0xba, 0x4a, 0xdc, 0x65, 0x99, 0x0d, 0xe4, 0xae, 0x7f, 0x79, + 0x27, 0x93, 0xe6, 0x89, 0xbf, 0xb6, 0xeb, 0x8b, 0x1d, 0xfc, 0xb2, 0x8f, + 0x41, 0x0d, 0x0d, 0xa6, 0x20, 0x8f, 0x14, 0xf7, 0x33, 0x0c, 0xbb, 0x79, + 0xa4, 0xf3, 0x03, 0x23, 0xe9, 0xa3, 0x0a, 0x8b, 0xc2, 0xa6, 0xe3, 0xd3, + 0xaf, 0x11, 0xd3, 0x00, 0xfe, 0x84, 0x36, 0x8e, 0x51, 0x62, 0x00, 0x8a, + 0xaf, 0x45, 0x34, 0xc7, 0x96, 0xc1, 0x48, 0x5f, 0xd7, 0xc4, 0xa1, 0x2e, + 0xf6, 0x86, 0x0e, 0x74, 0xfd, 0x0f, 0x2d, 0x70, 0x9a, 0x83, 0xa6, 0x47, + 0x91, 0x50, 0x9e, 0xf7, 0xbe, 0x00, 0xce, 0xe1, 0xe0, 0x93, 0x47, 0x0f, + 0x3c, 0x2b, 0x1b, 0x68, 0x34, 0x07, 0xc4, 0x28, 0x8f, 0x66, 0xb9, 0xb6, + 0xad, 0xfc, 0x53, 0x42, 0xbb, 0x21, 0x00, 0x35, 0xe7, 0x74, 0xd8, 0x36, + 0x66, 0x7c, 0x54, 0xc2, 0x59, 0xe4, 0x11, 0x52, 0x8f, 0xdb, 0xb5, 0x46, + 0xe6, 0xb3, 0x16, 0x6a, 0xf5, 0x79, 0x51, 0x11, 0x56, 0x13, 0xa9, 0xfe, + 0x39, 0xe7, 0xfe, 0x27, 0x86, 0x05, 0x2a, 0xde, 0x90, 0x43, 0xa3, 0x84, + 0x41, 0x78, 0x24, 0xfb, 0xe3, 0x4f, 0x42, 0xc1, 0x56, 0x65, 0x45, 0xab, + 0x8d, 0x69, 0x42, 0x6d, 0x44, 0x22, 0x19, 0x50, 0x43, 0x73, 0x52, 0x34, + 0xdd, 0xb9, 0xcf, 0x78, 0xe7, 0x81, 0xa7, 0x3a, 0x51, 0xe3, 0x9e, 0xc4, + 0x38, 0xa3, 0x03, 0x2c, 0xe6, 0x45, 0x67, 0x70, 0xc7, 0xc5, 0x4c, 0x50, + 0xf7, 0x68, 0x52, 0x7f, 0x08, 0x94, 0x78, 0xd7, 0xb8, 0x8c, 0xb2, 0x56, + 0x45, 0x90, 0x65, 0xd3, 0x55, 0x1c, 0x20, 0x9c, 0x3c, 0x54, 0x96, 0xf3, + 0x45, 0x42, 0x9b, 0x1b, 0x20, 0xab, 0xc7, 0x1e, 0x73, 0x85, 0x6d, 0x03, + 0x0e, 0xc7, 0x17, 0xc5, 0xf6, 0x02, 0x10, 0x3b, 0x54, 0x2c, 0x17, 0x5c, + 0x08, 0xa2, 0xd6, 0x2e, 0xcc, 0x18, 0x9b, 0x71, 0x60, 0xba, 0xdb, 0xae, + 0x18, 0x54, 0x57, 0xd0, 0x30, 0xda, 0xe9, 0x15, 0x5f, 0x90, 0x43, 0x52, + 0xd9, 0xf5, 0xb6, 0x4e, 0x5b, 0x83, 0x83, 0xaa, 0xc0, 0x16, 0xe2, 0xa9, + 0x5f, 0x31, 0x30, 0x79, 0x87, 0x9d, 0x0c, 0xd8, 0xf2, 0xdb, 0x4e, 0x3e, + 0xe6, 0xd9, 0xc9, 0x17, 0xb7, 0x11, 0x8d, 0x9c, 0x72, 0x17, 0x45, 0xde, + 0x2b, 0x6a, 0xc7, 0x60, 0x79, 0x3f, 0xbe, 0xf8, 0xdd, 0x47, 0x07, 0x66, + 0x24, 0xe3, 0xa6, 0x00, 0x91, 0xa2, 0x6f, 0x6d, 0xbf, 0x76, 0x0c, 0x18, + 0xe0, 0x87, 0xe1, 0xb8, 0x0e, 0x75, 0x18, 0xa2, 0x46, 0x62, 0x9a, 0x20, + 0x85, 0x5e, 0x8b, 0xb4, 0xfe, 0xd2, 0x24, 0x4b, 0x6b, 0x2c, 0x53, 0x3e, + 0xba, 0xb3, 0x28, 0x6b, 0x29, 0x81, 0x6a, 0x74, 0xc8, 0xb6, 0x92, 0x13, + 0x77, 0x2b, 0xe7, 0xad, 0x1f, 0x20, 0x41, 0x0c, 0xdd, 0xb4, 0xa7, 0xa2, + 0xb8, 0x88, 0x2e, 0xb3, 0x12, 0xec, 0xfb, 0x36, 0x7a, 0xea, 0x77, 0xb3, + 0x22, 0xb4, 0x52, 0xd0, 0x97, 0x41, 0xae, 0xc1, 0xb2, 0x04, 0xd0, 0x7f, + 0x88, 0x23, 0x66, 0x50, 0x21, 0xee, 0xb5, 0x89, 0xcd, 0xeb, 0xe4, 0x46, + 0xed, 0x7b, 0x89, 0x4a, 0xb9, 0xc2, 0xa6, 0x33, 0x13, 0xdd, 0xc3, 0x96, + 0x16, 0xd5, 0xe0, 0x70, 0xfb, 0x13, 0xb8, 0xa3, 0x64, 0x86, 0x18, 0x2e, + 0xb6, 0x0f, 0x86, 0x2c, 0x1f, 0xda, 0x82, 0xb0, 0x79, 0x9c, 0x73, 0xa9, + 0x7e, 0x7b, 0xe9, 0x49, 0x84, 0x08, 0x53, 0x14, 0x31, 0x77, 0xdc, 0xa1, + 0x65, 0xd5, 0xaa, 0xb2, 0x99, 0xa6, 0x85, 0x30, 0x45, 0x95, 0x06, 0x31, + 0xc3, 0xd2, 0xb2, 0x5e, 0xcd, 0x8d, 0x4a, 0x24, 0x66, 0xfb, 0x97, 0x02, + 0xf0, 0xca, 0x1c, 0x5c, 0x79, 0x28, 0xa1, 0x97, 0x47, 0xac, 0xba, 0x85, + 0x05, 0x79, 0x1c, 0x06, 0x2c, 0xdf, 0x1f, 0xcf, 0xca, 0xd4, 0xa8, 0x31, + 0xa6, 0x76, 0x8d, 0x3d, 0x3e, 0xd6, 0xba, 0xf9, 0xe6, 0xb1, 0xae, 0x49, + 0xca, 0x4c, 0x5b, 0xb3, 0x58, 0xee, 0x44, 0xec, 0xa9, 0x82, 0x73, 0xa3, + 0xe3, 0x1e, 0xd0, 0xc0, 0x28, 0x15, 0x6a, 0x7a, 0x1f, 0x5b, 0xc1, 0xc6, + 0x14, 0x17, 0x15, 0x2f, 0x15, 0xd5, 0xcb, 0xb0, 0x4a, 0x58, 0x56, 0x5a, + 0xa5, 0xac, 0x82, 0x89, 0x22, 0x2d, 0xe0, 0x0c, 0x89, 0xab, 0x05, 0x82, + 0x29, 0x73, 0x03, 0xc9, 0xcc, 0x03, 0x8e, 0x4e, 0x81, 0x75, 0x16, 0x2e, + 0x7f, 0xe4, 0x41, 0x3f, 0x6b, 0x49, 0xfa, 0xb4, 0x15, 0xd0, 0x71, 0xea, + 0x53, 0xf0, 0xa3, 0x40, 0x0e, 0x63, 0x8e, 0x31, 0x30, 0x02, 0x6d, 0x35, + 0x47, 0x65, 0x84, 0x72, 0x12, 0xd3, 0x78, 0x6e, 0x35, 0xba, 0x32, 0x41, + 0x62, 0x26, 0x61, 0x33, 0x39, 0x89, 0xc2, 0xc3, 0x58, 0x09, 0x2a, 0x32, + 0x44, 0xaf, 0xd8, 0xe9, 0x16, 0x41, 0x08, 0xbf, 0x6f, 0x20, 0x0d, 0x9f, + 0xc8, 0xdd, 0x5a, 0xdf, 0xc7, 0xec, 0xcc, 0x81, 0x57, 0x12, 0xa1, 0x9a, + 0x5e, 0xe2, 0x68, 0x2d, 0xa9, 0x6b, 0xd8, 0x7f, 0x36, 0x5f, 0xe1, 0x43, + 0xca, 0xbc, 0x7e, 0x8c, 0x74, 0x11, 0xd4, 0xf4, 0x20, 0xa5, 0xf8, 0x28, + 0x3b, 0x7d, 0x24, 0xe6, 0x3c, 0x46, 0xd8, 0x46, 0x4d, 0xea, 0x84, 0x16, + 0x7b, 0xf7, 0xb9, 0x9b, 0x7f, 0xf6, 0x1d, 0x53, 0x6f, 0x32, 0x02, 0x74, + 0xd3, 0x12, 0x62, 0x92, 0x0c, 0x53, 0xa2, 0xbf, 0x16, 0x4e, 0xde, 0x1d, + 0xe5, 0xe4, 0x9f, 0x75, 0xe4, 0xac, 0xa0, 0x71, 0x54, 0x45, 0x37, 0xfc, + 0x3b, 0x1a, 0x40, 0x99, 0x1e, 0x4a, 0x66, 0xe3, 0x1e, 0x47, 0x18, 0xe1, + 0xa6, 0x66, 0x26, 0x90, 0x31, 0xc6, 0x89, 0xb1, 0x0e, 0x98, 0x3d, 0x1e, + 0xb8, 0x47, 0x8a, 0xb5, 0xd1, 0x4c, 0xee, 0x25, 0x2c, 0x1f, 0x29, 0x30, + 0xd6, 0x57, 0x9a, 0xb7, 0x66, 0x6c, 0x92, 0x13, 0xa8, 0x49, 0xdd, 0x59, + 0xc4, 0xc3, 0xe0, 0x44, 0x2e, 0xeb, 0x4e, 0x2e, 0x39, 0x4f, 0x37, 0x63, + 0xf9, 0xbe, 0x7d, 0x39, 0x53, 0x0b, 0x8b, 0x6b, 0x40, 0x6a, 0x6f, 0x21, + 0x3a, 0xea, 0x15, 0xc9, 0xc3, 0x19, 0x58, 0x50, 0x27, 0x5f, 0xd0, 0x33, + 0x55, 0x68, 0xad, 0xe3, 0xf2, 0x84, 0x97, 0x0b, 0x7f, 0x39, 0xeb, 0xad, + 0x25, 0x6b, 0xa4, 0xbe, 0x77, 0x5d, 0xcc, 0x25, 0xda, 0x50, 0xbf, 0xbb, + 0xfc, 0x03, 0xd1, 0x54, 0xfb, 0x21, 0x5c, 0x7f, 0x35, 0x7f, 0x4b, 0x76, + 0x2e, 0x46, 0x5c, 0x6d, 0xc0, 0x40, 0xbc, 0x08, 0x54, 0xab, 0x27, 0xfd, + 0xaf, 0x2c, 0xff, 0x4e, 0x14, 0xe2, 0xa9, 0xa4, 0xba, 0xa0, 0x34, 0x47, + 0xbd, 0x7a, 0x81, 0x7c, 0xd1, 0xe4, 0xe3, 0xa3, 0x20, 0x33, 0xa3, 0x64, + 0x9a, 0x78, 0x0c, 0xc2, 0x3a, 0x55, 0xdb, 0x98, 0x35, 0x2d, 0x39, 0x04, + 0x2d, 0xf3, 0x22, 0xdf, 0x2e, 0x9c, 0x7c, 0x57, 0x53, 0xf3, 0x9d, 0xd3, + 0x1e, 0xcf, 0xf9, 0x15, 0xd4, 0x5b, 0x1f, 0xac, 0x56, 0x47, 0xb7, 0x36, + 0x4e, 0x5c, 0x88, 0x0c, 0x01, 0xf5, 0x7c, 0xc7, 0xe0, 0x20, 0xea, 0xcc, + 0xe7, 0x6e, 0x41, 0xab, 0xcc, 0xa6, 0x2b, 0x8a, 0x99, 0xe5, 0x01, 0x47, + 0xf5, 0xb7, 0xbf, 0x98, 0x73, 0x89, 0x44, 0xa9, 0xa1, 0x75, 0x6f, 0xfb, + 0x0b, 0x64, 0x55, 0xca, 0xb4, 0x75, 0xbf, 0xc3, 0x55, 0xce, 0x87, 0x50, + 0xce, 0x0b, 0xf7, 0x7c, 0x24, 0x19, 0xe4, 0xe9, 0x97, 0x29, 0x86, 0x5f, + 0x8a, 0x16, 0x97, 0xf7, 0x87, 0x5a, 0x41, 0x7b, 0x38, 0x13, 0x70, 0x62, + 0x0f, 0xf0, 0xad, 0xe9, 0xd7, 0xf9, 0x7f, 0x62, 0xda, 0x77, 0x2a, 0x60, + 0x8d, 0xd2, 0x85, 0x5c, 0x6b, 0xc4, 0x43, 0xa7, 0x30, 0x27, 0x2d, 0x18, + 0x79, 0x52, 0x94, 0x76, 0xd8, 0xea, 0xb2, 0xb7, 0x2d, 0x86, 0xbb, 0xef, + 0xf7, 0x54, 0x17, 0x1b, 0xec, 0x1d, 0x9a, 0x7f, 0xa9, 0xb7, 0x35, 0x15, + 0xb1, 0xdf, 0x61, 0xd9, 0x76, 0x7c, 0x2d, 0x4a, 0x59, 0xf5, 0xf6, 0x5e, + 0xde, 0xfe, 0x3a, 0x27, 0x8d, 0x33, 0xa9, 0x72, 0xfc, 0x7e, 0xa9, 0xf5, + 0xdd, 0x72, 0xe9, 0x2c, 0x0d, 0xd3, 0x89, 0x89, 0x54, 0xc0, 0x9e, 0xd2, + 0x61, 0x68, 0xc5, 0x7b, 0xd1, 0x91, 0xd0, 0x55, 0xaa, 0x69, 0xb5, 0x19, + 0x0f, 0x83, 0x37, 0xbb, 0x72, 0x90, 0xb9, 0x7f, 0x47, 0xd8, 0xc4, 0xf0, + 0x29, 0x9d, 0x96, 0xe8, 0x32, 0x70, 0x64, 0x85, 0xc4, 0xa0, 0xfb, 0x53, + 0x9a, 0x45, 0xe6, 0x94, 0xcb, 0x6d, 0x09, 0x8a, 0xe2, 0x9d, 0xf7, 0x35, + 0xa7, 0x43, 0xbb, 0x46, 0x9d, 0x18, 0x37, 0x58, 0x14, 0x5b, 0xc5, 0x1c, + 0x35, 0x57, 0xf5, 0x30, 0x60, 0x8d, 0x3b, 0xba, 0xab, 0x90, 0x3f, 0x22, + 0xa1, 0x2a, 0xff, 0xae, 0xa4, 0xe4, 0x95, 0xa9, 0x43, 0x89, 0x12, 0x2d, + 0xf0, 0xe0, 0x70, 0x25, 0x1c, 0x90, 0xd7, 0x70, 0x1b, 0xbe, 0x82, 0xad, + 0x26, 0x59, 0x01, 0x05, 0x2c, 0x8e, 0xf4, 0x74, 0x50, 0xa0, 0x83, 0xbe, + 0x76, 0x05, 0x41, 0x55, 0xf8, 0x12, 0x3e, 0x0c, 0x11, 0xf6, 0x59, 0x9c, + 0x23, 0xc3, 0x13, 0x41, 0xee, 0xd3, 0x0d, 0xa6, 0x00, 0x5c, 0x11, 0x12, + 0x00, 0x00, 0x00, 0x1b, 0x99, 0x90, 0xef, 0x9c, 0x6b, 0x48, 0x2f, 0x5d, + 0xe2, 0x75, 0x64, 0x30, 0x6e, 0x94, 0x88, 0xcd, 0xc7, 0xb1, 0x7d, 0xd2, + 0xc6, 0xc6, 0x44, 0xab, 0x2d, 0xff, 0x54, 0x7b, 0x29, 0x79, 0x07, 0xd6, + 0xd2, 0x68, 0x7c, 0x74, 0xcd, 0x27, 0x28, 0x1c, 0x58, 0x5c, 0xd9, 0x4e, + 0xbd, 0xee, 0xc0, 0x02, 0xe7, 0x71, 0x41, 0xc9, 0x31, 0x14, 0x6b, 0x68, + 0x2f, 0xb9, 0xfb, 0xf5, 0x49, 0x17, 0x23, 0x35, 0x8d, 0x3e, 0x7b, 0x5a, + 0x21, 0x21, 0x3a, 0x71, 0x00, 0x14, 0xb1, 0x84, 0x71, 0x13, 0x3d, 0xf2, + 0xb3, 0xad, 0x9c, 0xff, 0xe9, 0xd3, 0x19, 0x7c, 0x67, 0x5c, 0x7c, 0x5d, + 0x0b, 0xb9, 0x4e, 0xfc, 0x2a, 0x9d, 0x19, 0x37, 0x80, 0xe6, 0xbe, 0xef, + 0x5d, 0xb6, 0xf9, 0x90, 0x5d, 0xdf, 0x25, 0x93, 0x98, 0x04, 0x0a, 0x46, + 0xce, 0xd8, 0xe3, 0x92, 0xd1, 0x8e, 0x90, 0xf6, 0xce, 0xe8, 0x6f, 0x58, + 0x8c, 0xe0, 0x4c, 0x44, 0x61, 0x8d, 0x84, 0xe8, 0xc7, 0xc9, 0xa6, 0x80, + 0xdf, 0x96, 0x8d, 0x22, 0x2d, 0x86, 0x38, 0x19, 0x0f, 0x36, 0x1c, 0xbb, + 0x5c, 0xa1, 0xa1, 0xb3, 0xb0, 0xc6, 0xbf, 0xf1, 0x41, 0x9b, 0x3f, 0xf6, + 0x5c, 0x1f, 0x96, 0xc5, 0xce, 0x8f, 0x8a, 0xd5, 0xcc, 0xc5, 0xc4, 0x14, + 0xce, 0xe0, 0xea, 0x87, 0x7a, 0x30, 0xac, 0x17, 0xf6, 0xc8, 0x4a, 0x17, + 0xb2, 0x2d, 0xf8, 0x46, 0xf9, 0x5c, 0xad, 0x02, 0xc7, 0x4a, 0x19, 0x33, + 0xe1, 0x7e, 0x39, 0x06, 0xe7, 0x88, 0x1a, 0x3b, 0xc7, 0x4b, 0xb7, 0x0f, + 0x05, 0x34, 0x06, 0xae, 0x6d, 0x92, 0x5b, 0xea, 0x22, 0x17, 0x6c, 0xad, + 0x65, 0x86, 0x68, 0xba, 0x4e, 0x38, 0xf5, 0x3a, 0xeb, 0xe4, 0x81, 0x2a, + 0xff, 0x22, 0x33, 0x73, 0x85, 0xeb, 0x11, 0x78, 0x98, 0xcb, 0x4d, 0xc9, + 0xbf, 0x4f, 0x24, 0x8e, 0x6b, 0xf7, 0x44, 0x7b, 0xbf, 0xf2, 0xa9, 0x4e, + 0x08, 0xcd, 0xfc, 0xb7, 0xfc, 0xd9, 0xb8, 0x19, 0xf5, 0x80, 0xd1, 0xce, + 0x45, 0x06, 0x9b, 0xc8, 0x4c, 0xd8, 0xd1, 0x19, 0xd7, 0x9b, 0xc8, 0x67, + 0x11, 0x04, 0x86, 0x69, 0xae, 0x5d, 0xd5, 0xa2, 0xb3, 0xe5, 0x64, 0x50, + 0x2b, 0x9c, 0x18, 0xf5, 0xef, 0x65, 0x90, 0xdc, 0xb9, 0x7a, 0x67, 0x1d, + 0x62, 0xf3, 0x17, 0xbf, 0x1d, 0x67, 0xaf, 0xb3, 0x0c, 0xe4, 0xda, 0x27, + 0x06, 0xa3, 0x34, 0xe6, 0x8f, 0x43, 0xd1, 0x20, 0x17, 0x44, 0x44, 0x10, + 0x93, 0x91, 0x61, 0x43, 0xb7, 0x75, 0x9f, 0x1e, 0x91, 0x0b, 0xa0, 0x5e, + 0x49, 0x02, 0xba, 0x5d, 0xbc, 0xde, 0x6c, 0xb5, 0xbb, 0x26, 0x87, 0x68, + 0x03, 0x94, 0xe1, 0x05, 0xd1, 0xfc, 0xba, 0x48, 0xc7, 0x87, 0x86, 0xef, + 0xe9, 0x54, 0x0a, 0xaf, 0xd1, 0x7b, 0x0a, 0xd4, 0xf5, 0x07, 0xe6, 0x1f, + 0x60, 0xec, 0x82, 0x2c, 0xc5, 0x93, 0xc3, 0x60, 0xee, 0x78, 0x85, 0x28, + 0xa5, 0x08, 0x9f, 0x36, 0x47, 0x9c, 0xb2, 0x8e, 0x0a, 0x90, 0xf2, 0xa2, + 0xd0, 0x13, 0x3e, 0xfa, 0x40, 0x46, 0x6e, 0x97, 0x92, 0xea, 0x56, 0x60, + 0xe3, 0x95, 0xa1, 0x35, 0x3c, 0x26, 0xe2, 0x4d, 0x35, 0x92, 0x5e, 0xe4, + 0xbd, 0x4c, 0xea, 0x8e, 0xbf, 0x81, 0xd6, 0xe8, 0xa2, 0x37, 0x70, 0x3b, + 0x3c, 0xc4, 0x8d, 0x05, 0x16, 0x9a, 0x3a, 0x34, 0x47, 0x99, 0xd7, 0x49, + 0xc7, 0x9a, 0x34, 0x1c, 0x7f, 0xbf, 0xce, 0x56, 0x7e, 0x64, 0xaa, 0xba, + 0xc6, 0xfc, 0xe7, 0x3e, 0x62, 0x7f, 0xa6, 0x38, 0xdd, 0x3a, 0x95, 0x80, + 0xd4, 0xf8, 0x49, 0x58, 0xe7, 0x02, 0x4e, 0xa0, 0x08, 0x74, 0x71, 0x19, + 0x79, 0x75, 0x41, 0x95, 0x88, 0xc8, 0xe1, 0xe4, 0x9d, 0x19, 0x7c, 0x06, + 0x03, 0x0d, 0x27, 0x36, 0x5d, 0x2b, 0xbc, 0xa6, 0xb6, 0x22, 0x94, 0x12, + 0x17, 0xa2, 0xa2, 0x1e, 0x07, 0x60, 0x0e, 0x8d, 0x53, 0x60, 0x41, 0x7b, + 0x92, 0xfb, 0x13, 0x74, 0x1c, 0x6c, 0x1a, 0xd3, 0x7d, 0xda, 0xe1, 0x1c, + 0x16, 0xb9, 0xf9, 0xd2, 0x39, 0x36, 0xc0, 0xbb, 0x49, 0x00, 0xd4, 0x8d, + 0x7a, 0x59, 0x41, 0x9c, 0x2f, 0x09, 0x3b, 0x63, 0x1c, 0x82, 0x15, 0xe3, + 0x36, 0x62, 0x37, 0x07, 0x3b, 0x6e, 0x7c, 0x8d, 0x6c, 0x7b, 0x2b, 0xa0, + 0xa8, 0xd2, 0xe1, 0x24, 0x58, 0x3d, 0xb2, 0xf2, 0x3f, 0xf8, 0x86, 0x44, + 0x09, 0xe7, 0xab, 0x5f, 0x34, 0xa8, 0x37, 0xda, 0x2d, 0xd8, 0xae, 0x01, + 0x88, 0x0d, 0x43, 0x38, 0x35, 0x7d, 0xb5, 0xe7, 0x6e, 0x79, 0x0d, 0xe9, + 0xe9, 0x25, 0xf8, 0xdb, 0xfd, 0x3b, 0xd9, 0x73, 0x77, 0x55, 0x45, 0xc3, + 0x22, 0xf5, 0x43, 0x22, 0x4f, 0x47, 0xbf, 0x78, 0xfb, 0x34, 0xd1, 0xee, + 0xd0, 0xcc, 0x3a, 0xa5, 0xa4, 0xe5, 0x78, 0xe9, 0xd6, 0x55, 0xe0, 0x15, + 0x86, 0x4b, 0x58, 0x9d, 0x62, 0x2f, 0x29, 0x62, 0xd8, 0xdf, 0x96, 0x80, + 0x05, 0x1a, 0x9d, 0xc1, 0x0d, 0xb9, 0xd1, 0x44, 0x29, 0x6f, 0xe0, 0x86, + 0x25, 0xde, 0x7f, 0x78, 0x6f, 0xe0, 0x9c, 0xdf, 0x14, 0xdd, 0x89, 0x3e, + 0x44, 0xf4, 0xe0, 0x4c, 0x20, 0x58, 0xbb, 0x55, 0xf5, 0x4e, 0x96, 0xaa, + 0x82, 0x74, 0x2d, 0xbd, 0xc2, 0xad, 0x7f, 0xc3, 0xed, 0x8b, 0xd5, 0x98, + 0xf7, 0xad, 0x5a, 0xc4, 0x90, 0x14, 0xb2, 0xa8, 0xf4, 0x81, 0xc4, 0xaf, + 0x6c, 0x05, 0xfe, 0xee, 0x04, 0x3c, 0x51, 0xbd, 0x75, 0xd7, 0x32, 0xf5, + 0x7e, 0x45, 0x19, 0x39, 0x19, 0x28, 0x45, 0x9a, 0xc7, 0xcf, 0x82, 0x7d, + 0x56, 0xac, 0x68, 0xdb, 0xde, 0x89, 0x9d, 0x72, 0x1a, 0x46, 0xea, 0xb0, + 0xc3, 0xbc, 0x6f, 0x0d, 0x4b, 0x41, 0x3b, 0x38, 0xb3, 0xc7, 0xcb, 0x04, + 0xbe, 0xf3, 0x4c, 0x3b, 0x74, 0xa9, 0x2a, 0xe4, 0xe3, 0x2f, 0xc7, 0x8c, + 0x90, 0x30, 0x67, 0xcb, 0xb1, 0x1f, 0xbf, 0xc0, 0xad, 0x37, 0x74, 0x80, + 0xa9, 0x04, 0x7c, 0xc8, 0x57, 0x33, 0x83, 0x5b, 0x8c, 0xe6, 0xfc, 0xd5, + 0xa4, 0xf3, 0x9b, 0x6b, 0x2d, 0xdc, 0x64, 0x2b, 0x83, 0xe7, 0xdc, 0xb4, + 0x48, 0x8d, 0x11, 0x65, 0x22, 0xb5, 0xb5, 0x54, 0xec, 0x26, 0xdc, 0x1f, + 0x96, 0xbc, 0x68, 0x87, 0x67, 0xed, 0x1c, 0x41, 0xd3, 0xd8, 0x4f, 0xe2, + 0xc8, 0x43, 0xbb, 0x22, 0xd9, 0xa1, 0x39, 0xe1, 0x72, 0xdb, 0x75, 0x81, + 0x58, 0x74, 0x89, 0xb9, 0x58, 0x8b, 0x0f, 0x8a, 0xa0, 0x6a, 0x9e, 0x70, + 0x6b, 0x3b, 0x01, 0x2f, 0x2b, 0xf4, 0x00, 0xb8, 0x1c, 0xf9, 0x34, 0xa4, + 0x30, 0x80, 0x80, 0x4a, 0x0e, 0xcc, 0x52, 0x4e, 0xc7, 0xc1, 0x01, 0xfd, + 0x73, 0x22, 0x26, 0x33, 0x68, 0xfe, 0x01, 0x1d, 0xe1, 0xf0, 0x04, 0x66, + 0xfd, 0xcc, 0x77, 0xe5, 0xa1, 0x4b, 0xbe, 0x0e, 0xde, 0x95, 0x74, 0x72, + 0xbf, 0xbb, 0xa2, 0x5c, 0x08, 0x5d, 0x13, 0xcb, 0xcb, 0xd7, 0xa6, 0x34, + 0x61, 0x53, 0x0b, 0x3e, 0xb1, 0xe0, 0xb5, 0xd3, 0xaf, 0xe9, 0x07, 0x67, + 0x4c, 0x1a, 0x5b, 0x64, 0x68, 0xac, 0x94, 0x6f, 0xc4, 0xdb, 0x0f, 0x84, + 0x52, 0x88, 0x4b, 0x1e, 0xe5, 0xf1, 0x05, 0x70, 0x94, 0xee, 0xc1, 0x62, + 0xfd, 0x6f, 0x41, 0x2a, 0x1f, 0xda, 0xbe, 0x9f, 0xfb, 0x87, 0xf0, 0x96, + 0x8d, 0xa0, 0x60, 0x74, 0x7d, 0x53, 0x6e, 0x2e, 0x2d, 0x42, 0x49, 0x3d, + 0x9a, 0xae, 0xbc, 0x1b, 0x76, 0xa0, 0xc7, 0xaf, 0x4b, 0xb9, 0x18, 0x6f, + 0x4b, 0xe8, 0xbc, 0x56, 0x7b, 0x57, 0x60, 0xd1, 0xd3, 0x0c, 0x4d, 0xe0, + 0xe2, 0x3d, 0xcc, 0x82, 0x36, 0x78, 0xa2, 0x53, 0xe8, 0xe8, 0xf6, 0x13, + 0xa6, 0xc1, 0x1f, 0x0c, 0x9f, 0x5b, 0x0c, 0xf9, 0x89, 0x8e, 0xae, 0x70, + 0x51, 0xd0, 0x1f, 0x7b, 0xab, 0x69, 0xda, 0xb9, 0x56, 0x4d, 0x2d, 0x93, + 0x18, 0xa4, 0x40, 0x55, 0x95, 0xdf, 0x58, 0xca, 0xbd, 0x36, 0x89, 0x07, + 0x58, 0x11, 0xa6, 0x22, 0xf8, 0x83, 0x1c, 0x8e, 0xe7, 0xa9, 0xc7, 0xd3, + 0xdc, 0x5e, 0x54, 0x35, 0xd6, 0xf1, 0xe4, 0x41, 0x98, 0xa4, 0x16, 0x67, + 0x73, 0x56, 0xdd, 0x69, 0x6d, 0xaa, 0x3f, 0xb8, 0xad, 0xfa, 0xd7, 0xce, + 0xee, 0x65, 0xc5, 0x10, 0xe8, 0x39, 0x1d, 0xff, 0x57, 0x1a, 0x85, 0x43, + 0x77, 0x3f, 0xb1, 0xe1, 0x21, 0x81, 0xa6, 0x8e, 0xd8, 0x49, 0xec, 0xe8, + 0x44, 0x0c, 0x4c, 0x44, 0x8f, 0x8d, 0x78, 0x45, 0xcc, 0x81, 0xed, 0x17, + 0xd1, 0xac, 0x54, 0x3c, 0x58, 0xa4, 0x8e, 0x65, 0xd0, 0xd8, 0x94, 0xc9, + 0xd7, 0x8d, 0x46, 0x5d, 0xc1, 0x3c, 0xb6, 0xb9, 0x0d, 0x88, 0xdf, 0x2c, + 0xb8, 0x51, 0x6d, 0x30, 0x87, 0x76, 0x27, 0x0a, 0xd7, 0xfe, 0x0a, 0x2b, + 0x2d, 0xdc, 0xd1, 0xd2, 0xfd, 0x72, 0xcd, 0x0f, 0x1b, 0xb7, 0xb6, 0x0d, + 0xbd, 0xe0, 0x10, 0x60, 0xec, 0xfd, 0xe1, 0x18, 0x0d, 0x88, 0x48, 0x34, + 0xec, 0xf6, 0x7f, 0x4a, 0x24, 0xce, 0xa9, 0x8d, 0x45, 0x4e, 0xde, 0xcc, + 0x5e, 0xfc, 0x48, 0xf8, 0x7e, 0xa8, 0x0a, 0x9c, 0x5b, 0xad, 0x3c, 0x5e, + 0x5d, 0x3e, 0x33, 0x89, 0xec, 0x88, 0x58, 0xa9, 0xca, 0xa6, 0xe7, 0x59, + 0x5a, 0x8e, 0xfb, 0x21, 0x43, 0x8a, 0x45, 0x49, 0x0f, 0x91, 0xb8, 0xf8, + 0x60, 0x5b, 0x35, 0x44, 0xd7, 0x0d, 0x68, 0x9f, 0x47, 0x6f, 0xbf, 0x3d, + 0xa1, 0x6f, 0xd7, 0xfc, 0xef, 0xbd, 0x9b, 0x84, 0xce, 0x79, 0xbd, 0xf9, + 0x59, 0x4d, 0x46, 0x6e, 0xde, 0x49, 0xdd, 0xde, 0xb8, 0x27, 0x33, 0xf9, + 0xdb, 0x33, 0xdb, 0xea, 0x42, 0x30, 0xff, 0x96, 0x72, 0x5b, 0x55, 0xb6, + 0xa3, 0xa9, 0x15, 0xb3, 0xbd, 0x31, 0xb6, 0x7c, 0x4e, 0xc8, 0xec, 0x5a, + 0x2a, 0x53, 0xe9, 0xa8, 0x25, 0x26, 0x75, 0xeb, 0xce, 0xd5, 0x27, 0x6e, + 0x85, 0xe2, 0x01, 0x0b, 0xd6, 0x1b, 0x09, 0xe8, 0x0a, 0x11, 0xf3, 0x2d, + 0x94, 0xcf, 0xab, 0x03, 0xb9, 0x83, 0x8a, 0x6f, 0x3b, 0x05, 0x98, 0xb4, + 0x72, 0x3b, 0xba, 0x90, 0xbd, 0x23, 0x07, 0x8b, 0xf8, 0xd9, 0x26, 0x13, + 0x74, 0xe3, 0x1c, 0x85, 0xec, 0x8f, 0x43, 0x29, 0xa8, 0x17, 0x6d, 0xb7, + 0x00, 0xda, 0xd1, 0x34, 0x1d, 0x1c, 0xd2, 0xc3, 0xe6, 0xd7, 0x11, 0x51, + 0x79, 0x1b, 0x73, 0x00, 0x51, 0xd0, 0xe7, 0x92, 0xe1, 0x11, 0x5d, 0x9b, + 0x5c, 0x11, 0x88, 0x4c, 0xfa, 0x02, 0x82, 0x78, 0x86, 0xed, 0x65, 0x08, + 0x4f, 0x1c, 0xcb, 0x8c, 0x78, 0x59, 0x65, 0xea, 0x97, 0x8c, 0xe6, 0x52, + 0xe1, 0x3f, 0xdd, 0xbb, 0x20, 0xe6, 0x7c, 0xf9, 0xc7, 0xf8, 0xb9, 0xe6, + 0x74, 0xa0, 0xa5, 0xcb, 0xe9, 0x89, 0xb9, 0xff, 0x88, 0xa3, 0xb8, 0x7b, + 0x60, 0x8d, 0xb0, 0xca, 0x50, 0xe8, 0xc0, 0x80, 0xc1, 0x68, 0x27, 0xef, + 0x48, 0xe7, 0x00, 0x22, 0x52, 0xb4, 0x2e, 0x30, 0x97, 0x96, 0xde, 0xb3, + 0xd0, 0xa1, 0x8b, 0x6a, 0x31, 0x6a, 0xc4, 0x52, 0xef, 0xba, 0x74, 0x57, + 0xf1, 0xc6, 0x19, 0x37, 0x0b, 0x22, 0xa0, 0x23, 0xb9, 0xe0, 0x26, 0x0c, + 0x23, 0xa3, 0xb8, 0x4c, 0x71, 0x7b, 0x45, 0xa4, 0xe8, 0xfd, 0x94, 0xfc, + 0x96, 0x47, 0xba, 0x0f, 0xaa, 0x67, 0x90, 0xa3, 0x2d, 0x95, 0x70, 0xd2, + 0xa3, 0xfa, 0x7b, 0x49, 0x03, 0x45, 0x44, 0x45, 0x8a, 0x38, 0x2a, 0x04, + 0x1b, 0x9a, 0xa3, 0xbd, 0xc6, 0xa9, 0xcf, 0x4f, 0x88, 0x41, 0x98, 0x0c, + 0x2a, 0x5e, 0x22, 0x60, 0x01, 0xf3, 0x78, 0x98, 0xf4, 0x13, 0xc9, 0x27, + 0x80, 0x6e, 0xee, 0x4f, 0xa0, 0xf2, 0xbe, 0x8f, 0x83, 0x69, 0x52, 0xc4, + 0xf8, 0x82, 0x36, 0xd6, 0xe4, 0x91, 0xd9, 0x62, 0xa4, 0x09, 0xa1, 0xbd, + 0xff, 0xec, 0x96, 0x74, 0x0d, 0x6f, 0x17, 0xf9, 0xb7, 0xe3, 0xe4, 0x16, + 0x7f, 0x03, 0xd7, 0x27, 0x7f, 0xaa, 0x94, 0x27, 0x61, 0x3a, 0x3c, 0x0a, + 0x92, 0x82, 0x93, 0x6a, 0xed, 0x55, 0x12, 0xac, 0xe4, 0x89, 0xc2, 0x25, + 0x36, 0x50, 0x63, 0x68, 0x49, 0xb7, 0x5f, 0x44, 0x95, 0xe8, 0x41, 0x09, + 0x6f, 0xdf, 0x66, 0x0c, 0xde, 0x6f, 0xba, 0x7a, 0x0f, 0x9e, 0x87, 0x43, + 0x62, 0x99, 0x9b, 0x97, 0xe7, 0xb1, 0x46, 0x2d, 0xa2, 0x10, 0x57, 0x92, + 0x5a, 0xbe, 0xec, 0xc1, 0x24, 0x91, 0x94, 0x80, 0x1c, 0xea, 0x0f, 0xc7, + 0xfe, 0x02, 0x4d, 0x99, 0x88, 0x1b, 0xc1, 0xaa, 0xce, 0x4d, 0x6a, 0xc7, + 0xe0, 0x93, 0x4b, 0x35, 0x71, 0x49, 0x81, 0x6b, 0x98, 0x54, 0x17, 0x6d, + 0xf5, 0xbc, 0xc2, 0xc3, 0xb8, 0x5b, 0x00, 0xfd, 0xec, 0x50, 0x50, 0x6e, + 0xb6, 0xe7, 0xdc, 0x6c, 0x2b, 0x4b, 0x77, 0x73, 0xeb, 0xee, 0xc1, 0xc3, + 0xe1, 0xee, 0xc1, 0xc6, 0xc9, 0xce, 0xad, 0x6b, 0x8f, 0x40, 0x95, 0xb3, + 0x41, 0xb9, 0x86, 0xf8, 0x6a, 0x9a, 0x59, 0x7e, 0xc8, 0xb3, 0x26, 0xa0, + 0x55, 0x6e, 0x41, 0x90, 0xff, 0xf2, 0x69, 0x01, 0x70, 0x61, 0x81, 0x6a, + 0x61, 0x14, 0x78, 0x8c, 0x31, 0xbc, 0xc4, 0x51, 0x81, 0x4e, 0x12, 0x54, + 0xef, 0xd8, 0x85, 0x07, 0x92, 0xa4, 0x02, 0xae, 0x54, 0x80, 0x70, 0x94, + 0x26, 0x49, 0x8a, 0xa2, 0x3e, 0x63, 0x6f, 0x3a, 0xa5, 0xbe, 0x71, 0x02, + 0x22, 0x99, 0xf0, 0x98, 0xe8, 0x8f, 0xc5, 0x58, 0x1e, 0xcd, 0x2b, 0xe8, + 0xf5, 0xa0, 0x2c, 0xd0, 0x21, 0x87, 0x3a, 0x38, 0x28, 0x0d, 0x87, 0x1f, + 0x0f, 0x3e, 0xfb, 0xd6, 0xd3, 0x12, 0x86, 0x66, 0x25, 0x02, 0x6c, 0x08, + 0x54, 0x10, 0xfb, 0x29, 0x8f, 0x7f, 0xe5, 0x96, 0xa8, 0x56, 0xba, 0x72, + 0x71, 0x36, 0xdd, 0xc6, 0x81, 0xe2, 0x1f, 0x7a, 0xd4, 0x8d, 0xdc, 0xea, + 0xe6, 0xff, 0x2f, 0xb5, 0xea, 0x44, 0xea, 0x88, 0x69, 0x80, 0x2e, 0x49, + 0x4d, 0x84, 0x6f, 0xa1, 0x7a, 0xed, 0x05, 0x55, 0x73, 0x42, 0x56, 0xe4, + 0xa6, 0x9f, 0x65, 0x32, 0x46, 0x32, 0xb3, 0x97, 0x87, 0x74, 0x7a, 0xd3, + 0xdd, 0xcf, 0x9f, 0x01, 0x96, 0x37, 0xf2, 0xd1, 0xeb, 0x45, 0x4a, 0x23, + 0xb5, 0x33, 0x6c, 0xa5, 0x7b, 0x98, 0x65, 0xd2, 0xe1, 0x78, 0xf9, 0x44, + 0x03, 0x3b, 0x29, 0xa8, 0xf2, 0x45, 0xb2, 0x96, 0x3e, 0xac, 0x09, 0x24, + 0x76, 0x48, 0xb9, 0x75, 0x87, 0xba, 0x2c, 0x4e, 0x33, 0x67, 0xdf, 0xdc, + 0x70, 0x3b, 0xc3, 0x1f, 0xbb, 0xd9, 0x36, 0xf8, 0x19, 0x2e, 0xeb, 0x42, + 0xe5, 0x6b, 0xaa, 0x85, 0x3f, 0xeb, 0xac, 0x51, 0x78, 0xdb, 0x62, 0x9e, + 0x2a, 0x5f, 0x1e, 0xb2, 0x72, 0xa7, 0xdd, 0x25, 0xb0, 0x6b, 0xcb, 0xc5, + 0xb5, 0xe3, 0x88, 0x1c, 0xcd, 0xfa, 0xa8, 0x6e, 0x2a, 0x0e, 0xa0, 0x79, + 0x7a, 0x04, 0x1f, 0xed, 0x3d, 0xc2, 0x65, 0xaf, 0x0b, 0xaa, 0xb2, 0xec, + 0x73, 0x6e, 0x0f, 0xd4, 0x21, 0xd8, 0x29, 0x39, 0x10, 0x53, 0x2c, 0xf8, + 0x31, 0xaf, 0x5f, 0x4b, 0x81, 0xff, 0xb2, 0x6f, 0x96, 0x41, 0xcf, 0x25, + 0x0f, 0x03, 0x13, 0x05, 0x72, 0x7f, 0x75, 0x5c, 0x31, 0x09, 0x72, 0x90, + 0x65, 0x01, 0x43, 0x4b, 0xef, 0x55, 0x91, 0xd3, 0x75, 0x85, 0x44, 0x78, + 0xe9, 0x4c, 0xb0, 0x9b, 0x68, 0xdd, 0xf2, 0x2d, 0x4a, 0x96, 0x21, 0xb6, + 0x2c, 0x2f, 0x86, 0x76, 0x6f, 0xc5, 0x1f, 0x30, 0x6c, 0xc4, 0xf8, 0x12, + 0x8d, 0x0a, 0x1d, 0x76, 0xe7, 0x79, 0xac, 0x85, 0xd4, 0x2f, 0xfc, 0x2c, + 0x9b, 0x54, 0x2b, 0xdc, 0xf7, 0xad, 0x4a, 0x64, 0x03, 0x40, 0xb4, 0xaa, + 0x21, 0x5f, 0x47, 0x55, 0xf2, 0xfd, 0x9d, 0xe2, 0x14, 0x2e, 0x68, 0x84, + 0xef, 0x98, 0x8e, 0xcd, 0xe3, 0x04, 0x52, 0xd1, 0xc2, 0x6c, 0x3b, 0xc3, + 0x2c, 0x49, 0xc4, 0x53, 0x6c, 0xcb, 0x7e, 0xb5, 0x8a, 0xce, 0x18, 0x02, + 0x34, 0x3c, 0xcb, 0xa4, 0xd6, 0xd8, 0xc9, 0xea, 0xa0, 0x19, 0x08, 0x52, + 0x3a, 0x76, 0x49, 0xc5, 0x6c, 0xb3, 0xbf, 0x23, 0x4d, 0x17, 0x18, 0xa4, + 0x27, 0xea, 0x2c, 0x89, 0xc0, 0x77, 0xe5, 0x5c, 0xab, 0x78, 0xdc, 0x17, + 0x29, 0x7a, 0xde, 0x43, 0x4b, 0x40, 0x06, 0x5d, 0x57, 0xa4, 0xf4, 0xe9, + 0xf0, 0xc3, 0xfe, 0x75, 0x71, 0xb3, 0x57, 0x5d, 0x02, 0x84, 0x1e, 0x35, + 0x9c, 0x2b, 0x97, 0x4b, 0x73, 0x8b, 0xaf, 0x7c, 0x1f, 0xae, 0x2b, 0xb2, + 0x85, 0x3b, 0x00, 0xe6, 0xa6, 0x3f, 0x93, 0x8a, 0xfb, 0x47, 0x71, 0x47, + 0xcb, 0xfd, 0x34, 0xd9, 0xf0, 0xbd, 0x7d, 0x85, 0x02, 0x9b, 0x90, 0x88, + 0x7f, 0x6e, 0x97, 0xce, 0x1a, 0x9f, 0x61, 0x19, 0x59, 0x81, 0x05, 0xfb, + 0xb8, 0xbc, 0x3c, 0x19, 0x1c, 0x1a, 0x5b, 0x60, 0xe0, 0x24, 0xcc, 0x52, + 0xb7, 0x49, 0x9e, 0xb6, 0x08, 0xd5, 0x0e, 0x69, 0xfe, 0xc0, 0x92, 0x74, + 0x73, 0x72, 0x93, 0x32, 0xe7, 0xe6, 0xe9, 0x8f, 0xb2, 0xb4, 0x86, 0x47, + 0x67, 0x67, 0xff, 0xc5, 0x2f, 0x25, 0x54, 0x36, 0x50, 0xeb, 0xf4, 0x34, + 0x91, 0x83, 0xde, 0x05, 0xd7, 0xc6, 0xc8, 0xce, 0xf8, 0xe0, 0xbb, 0xc7, + 0x27, 0x24, 0x65, 0x60, 0x21, 0x47, 0x0d, 0x4e, 0x2c, 0x03, 0xad, 0x14, + 0x0b, 0xe3, 0x0f, 0xe3, 0x50, 0xef, 0x06, 0x63, 0x22, 0xb0, 0x51, 0xff, + 0x72, 0x6d, 0x03, 0xaf, 0x76, 0xf6, 0x0f, 0x06, 0xa1, 0x84, 0x53, 0xa2, + 0x79, 0xe1, 0x68, 0x1c, 0xe7, 0x57, 0x09, 0xf3, 0xff, 0x64, 0x6a, 0x33, + 0x81, 0x8a, 0x84, 0x80, 0xd0, 0x85, 0x84, 0x99, 0x75, 0xc6, 0x2e, 0xae, + 0xe0, 0x6d, 0x49, 0xaa, 0xbd, 0x0e, 0x8d, 0xb9, 0x88, 0xb7, 0x52, 0x55, + 0x00, 0xaf, 0xcb, 0x68, 0xb4, 0x53, 0x25, 0x8d, 0x58, 0xc3, 0xcf, 0x94, + 0x1f, 0x80, 0x8a, 0xda, 0x1f, 0x70, 0xe2, 0x19, 0x6d, 0xdd, 0x1d, 0xac, + 0xab, 0xf8, 0xef, 0x0f, 0x43, 0xe0, 0x91, 0xd7, 0x7c, 0xed, 0xb4, 0x8f, + 0x2f, 0x2a, 0xa6, 0x36, 0x18, 0x86, 0xd7, 0xcc, 0xd1, 0xde, 0xda, 0x0d, + 0x0c, 0xde, 0xae, 0x9f, 0xbc, 0x49, 0xf7, 0x07, 0x82, 0xbe, 0x6e, 0xd0, + 0x2b, 0xb1, 0xd4, 0xfa, 0x1a, 0xfe, 0xcc, 0x57, 0x97, 0x2f, 0x4d, 0x12, + 0xf0, 0xba, 0xa0, 0x3f, 0x7f, 0xb4, 0xfe, 0xb8, 0x0f, 0xb3, 0xc5, 0x03, + 0xdc, 0x77, 0x98, 0x95, 0xc6, 0x0b, 0x7b, 0x6f, 0xad, 0xae, 0x9d, 0xb4, + 0xf0, 0x0d, 0xa2, 0xa1, 0xa8, 0x83, 0x62, 0xc7, 0x31, 0x27, 0x9c, 0x52, + 0x36, 0x06, 0x13, 0x52, 0x0e, 0xd6, 0x30, 0x41, 0xc4, 0x38, 0x29, 0x1d, + 0x39, 0x7c, 0x23, 0x32, 0x45, 0xcc, 0x79, 0xca, 0xa5, 0x9a, 0x62, 0x6e, + 0x00, 0x02, 0xc9, 0xb9, 0xd3, 0x84, 0x02, 0x5d, 0xe3, 0x69, 0x5c, 0x8e, + 0xbe, 0x55, 0xf4, 0x96, 0xdf, 0xcb, 0x8b, 0x52, 0xa1, 0x4e, 0x9c, 0x38, + 0x56, 0xa1, 0xd7, 0x82, 0x4a, 0x6a, 0xd3, 0x19, 0xa6, 0x74, 0x80, 0x04, + 0x6d, 0xc5, 0x7e, 0xd6, 0xda, 0x91, 0x5e, 0x2c, 0x81, 0x3b, 0x0c, 0x6a, + 0xc6, 0xe8, 0x40, 0xb7, 0x9c, 0x2a, 0x4f, 0xb3, 0x87, 0x46, 0xc5, 0x4b, + 0x81, 0x87, 0xbe, 0x93, 0x5a, 0x9c, 0xc8, 0xdc, 0x97, 0x93, 0xff, 0x06, + 0x36, 0x8e, 0xa6, 0x24, 0x03, 0x10, 0x17, 0xf9, 0x20, 0xed, 0x75, 0xef, + 0xed, 0xcf, 0x28, 0x1b, 0x7b, 0x64, 0x00, 0x7c, 0x78, 0x10, 0x84, 0xa2, + 0x96, 0x4b, 0x04, 0x42, 0x57, 0x76, 0xaa, 0x2b, 0x7d, 0x7c, 0xc4, 0x85, + 0x83, 0xef, 0x04, 0xdd, 0x6a, 0x68, 0x5e, 0xe3, 0xba, 0xb4, 0x08, 0xe0, + 0x8a, 0xdc, 0x32, 0x53, 0x1a, 0x4b, 0x06, 0x06, 0x8c, 0x12, 0xb9, 0xf7, + 0xd2, 0xf6, 0x5d, 0x12, 0x7b, 0x1b, 0xb9, 0xcf, 0x0d, 0x8c, 0xfe, 0xb2, + 0x4b, 0xfb, 0xaf, 0x0c, 0xf6, 0x1a, 0x89, 0xe1, 0xdb, 0xa0, 0x92, 0x3b, + 0xb0, 0x15, 0xaf, 0x76, 0xe5, 0x22, 0x5f, 0x93, 0x0f, 0x08, 0x33, 0xa6, + 0xe0, 0x52, 0x00, 0x49, 0x7d, 0xf2, 0xd0, 0xdd, 0xe0, 0xb5, 0xbb, 0x07, + 0x78, 0x2f, 0xd3, 0x17, 0xe0, 0xce, 0xd1, 0x60, 0xef, 0x26, 0x27, 0x68, + 0x81, 0x7e, 0x23, 0xa2, 0xcf, 0x93, 0x12, 0xc6, 0x44, 0x1b, 0xaf, 0x47, + 0x8b, 0x26, 0x47, 0xba, 0x95, 0x7c, 0x2f, 0xc0, 0xff, 0xc6, 0xdc, 0xe8, + 0x1f, 0x2c, 0x35, 0xa1, 0x4b, 0xdc, 0x16, 0x1a, 0xbf, 0x78, 0x05, 0xbc, + 0xb2, 0x1d, 0x69, 0x75, 0x74, 0x6e, 0x32, 0x05, 0x4e, 0x20, 0x6e, 0x1f, + 0xaf, 0x11, 0xf2, 0x37, 0x41, 0x0a, 0x7b, 0xfd, 0x28, 0x9f, 0xa4, 0x47, + 0xfc, 0x25, 0xf5, 0x1c, 0xd5, 0x62, 0xde, 0x84, 0xcb, 0xf9, 0x52, 0xe2, + 0xdd, 0x26, 0x3f, 0x8e, 0x8c, 0xd4, 0xba, 0x54, 0x34, 0xbf, 0x9b, 0xff, + 0x9e, 0x05, 0x2f, 0x9c, 0x98, 0xce, 0xa6, 0x4e, 0x36, 0xde, 0x96, 0x81, + 0x30, 0x05, 0x75, 0x07, 0xdd, 0xa0, 0x74, 0x4f, 0x39, 0x60, 0xcb, 0x5e, + 0x26, 0x2e, 0xbb, 0x00, 0xaf, 0xf7, 0x3b, 0xd9, 0xb1, 0x70, 0x4f, 0xa4, + 0x31, 0x45, 0x06, 0x63, 0x61, 0x03, 0x45, 0x27, 0xe3, 0x66, 0xf7, 0x9f, + 0x15, 0x5b, 0x22, 0x45, 0xb7, 0x6d, 0xe8, 0xb2, 0x67, 0x35, 0x8e, 0x72, + 0x02, 0x76, 0xf4, 0xb4, 0x63, 0x4a, 0x7c, 0xd7, 0xd1, 0x00, 0x6c, 0x93, + 0xfc, 0x63, 0x53, 0x20, 0x40, 0x59, 0xbb, 0x2e, 0xad, 0x26, 0x9c, 0xff, + 0x63, 0xbf, 0xb8, 0x7c, 0x2c, 0x87, 0xb8, 0x5d, 0x07, 0xeb, 0x6d, 0x40, + 0x04, 0x8d, 0x48, 0xc2, 0x92, 0x67, 0x47, 0x16, 0x95, 0x9f, 0x31, 0x93, + 0x3e, 0x09, 0x92, 0x7f, 0xcf, 0xaf, 0x10, 0xec, 0x39, 0xff, 0xd7, 0xb7, + 0xee, 0x8f, 0x86, 0x4e, 0x02, 0x83, 0x04, 0x76, 0x9f, 0x32, 0xf5, 0xa6, + 0xc4, 0xeb, 0xc0, 0x7a, 0xa3, 0x9c, 0x77, 0xd0, 0xb8, 0x9e, 0xf7, 0xad, + 0x51, 0x69, 0xf0, 0x1b, 0xf6, 0x57, 0xde, 0x1e, 0x2b, 0x24, 0xa6, 0x15, + 0x20, 0xba, 0xde, 0xe5, 0xfb, 0x62, 0x60, 0x9c, 0x3e, 0x94, 0xa1, 0x6a, + 0x16, 0x02, 0xa2, 0xc0, 0xc7, 0xe9, 0x21, 0x33, 0x5b, 0xf2, 0x18, 0xbc, + 0x6b, 0x11, 0x13, 0x0a, 0xaa, 0x71, 0x4e, 0xd0, 0x6a, 0x17, 0x91, 0x65, + 0xfd, 0x5f, 0x5e, 0x93, 0xba, 0x9f, 0x70, 0xfa, 0x91, 0xc2, 0x74, 0xf2, + 0xbb, 0xe0, 0x47, 0xf5, 0x7c, 0x0a, 0x91, 0x3c, 0x08, 0x13, 0x74, 0x3f, + 0x63, 0xd6, 0x9c, 0xc6, 0xf6, 0x04, 0x7f, 0xd7, 0x5b, 0xa9, 0x8c, 0x74, + 0x0a, 0x57, 0x45, 0x32, 0x5e, 0x31, 0xf9, 0xa2, 0x68, 0xed, 0xc5, 0xba, + 0x08, 0xf5, 0x41, 0x83, 0x98, 0x65, 0x47, 0x9a, 0x86, 0x87, 0x75, 0x64, + 0xa6, 0xd2, 0x6c, 0xfe, 0x0b, 0xdd, 0x17, 0xb0, 0x4e, 0xbe, 0x09, 0xdb, + 0xe7, 0x2f, 0x5e, 0xd4, 0x2b, 0x2d, 0x2d, 0x26, 0x63, 0xd2, 0xeb, 0x64, + 0x79, 0xd2, 0x55, 0x4f, 0xf1, 0x45, 0x89, 0xc2, 0xf9, 0x38, 0x96, 0xab, + 0xba, 0x5a, 0xfb, 0x42, 0x06, 0xb9, 0xe6, 0x9d, 0x16, 0xaf, 0x79, 0x45, + 0xf7, 0xe7, 0xe6, 0x2e, 0xec, 0x1b, 0x69, 0xe6, 0xbf, 0x54, 0x88, 0x2c, + 0xea, 0xd2, 0x0c, 0xc6, 0x96, 0xfe, 0xc9, 0x5a, 0x5b, 0x16, 0xd8, 0x9a, + 0x13, 0x77, 0x43, 0x37, 0x88, 0xe8, 0x6a, 0x82, 0x06, 0xe4, 0x5d, 0x0a, + 0x50, 0xd9, 0xff, 0xd0, 0x62, 0xcd, 0x8c, 0xcf, 0x86, 0x47, 0xd4, 0xba, + 0x7b, 0xec, 0x4d, 0x78, 0xa5, 0xff, 0x67, 0x2f, 0xf8, 0x70, 0xf4, 0x42, + 0x4b, 0xce, 0xa3, 0xef, 0x25, 0x4c, 0x92, 0x3d, 0x7e, 0x10, 0xfb, 0x03, + 0x97, 0x0a, 0xfe, 0xf4, 0xd3, 0x73, 0x64, 0x00, 0xa1, 0x5e, 0x68, 0xdb, + 0x5f, 0x7a, 0xff, 0x2e, 0x9f, 0xe2, 0x75, 0xd4, 0xf9, 0xa4, 0x49, 0xf0, + 0xe9, 0x5b, 0xe2, 0x37, 0x3b, 0x0c, 0xa9, 0x0c, 0x77, 0x3b, 0x7a, 0x64, + 0xe4, 0x7a, 0x9f, 0x10, 0x9d, 0x18, 0x25, 0x92, 0xd0, 0xcf, 0x6d, 0x1c, + 0xdd, 0xc4, 0xd5, 0x51, 0x6c, 0x52, 0x92, 0x62, 0x57, 0xaa, 0x50, 0x44, + 0xdd, 0xc9, 0xef, 0x8d, 0x28, 0x8a, 0x8b, 0x9c, 0x2c, 0xf6, 0x8d, 0x42, + 0xa2, 0x83, 0xf9, 0xc8, 0xc6, 0x65, 0x0b, 0x6b, 0xd5, 0x5f, 0x76, 0x5e, + 0x76, 0xc1, 0x6f, 0x00, 0x2c, 0xc5, 0x8d, 0x27, 0x7b, 0x28, 0xf0, 0xa3, + 0x0d, 0x5d, 0x1e, 0xa9, 0x6e, 0xe6, 0x4c, 0xc0, 0x12, 0x22, 0x77, 0x0f, + 0x9e, 0x73, 0xba, 0x83, 0x41, 0xbf, 0x8f, 0x0d, 0x7c, 0x27, 0x65, 0x85, + 0x76, 0x88, 0xf4, 0xf1, 0x65, 0x33, 0x55, 0x27, 0x18, 0xcb, 0x1d, 0xd0, + 0xc8, 0xf7, 0x2d, 0x53, 0x94, 0x1f, 0x2a, 0xfa, 0xdd, 0x48, 0xf7, 0x9a, + 0x25, 0xf4, 0xba, 0x8c, 0x16, 0xd3, 0xfa, 0xec, 0x7f, 0x67, 0x28, 0x61, + 0x44, 0x0a, 0x55, 0xaf, 0x9e, 0xd1, 0x51, 0x69, 0x9d, 0x22, 0x3b, 0xf5, + 0x17, 0x23, 0x4c, 0xb9, 0x79, 0xcc, 0xac, 0x6e, 0xc0, 0x3e, 0x81, 0xa6, + 0x4e, 0xec, 0x98, 0x18, 0x6f, 0xf1, 0x05, 0x68, 0xd5, 0x9c, 0x43, 0x1c, + 0x17, 0xbc, 0x34, 0x9d, 0xa5, 0x9f, 0x87, 0x53, 0x0d, 0xdf, 0xf7, 0xa1, + 0xb2, 0xab, 0x5d, 0x0e, 0xc6, 0xb7, 0x7a, 0x0d, 0xe5, 0x35, 0xfc, 0xab, + 0xea, 0x40, 0xfb, 0xd5, 0xc6, 0xc0, 0x4c, 0xfc, 0x28, 0x5c, 0xc0, 0x0a, + 0x4d, 0xac, 0x1e, 0xb0, 0xb3, 0x63, 0xdd, 0x9d, 0x48, 0x87, 0xee, 0x2d, + 0xb3, 0x63, 0xbf, 0x9c, 0x21, 0xe2, 0x5c, 0xd6, 0x03, 0x79, 0x25, 0x00, + 0x98, 0xf8, 0xf6, 0xb5, 0x4c, 0x6f, 0xfb, 0x16, 0x09, 0xbc, 0x64, 0x10, + 0x78, 0xb7, 0x57, 0x26, 0x40, 0x0c, 0xf1, 0x09, 0xcc, 0x93, 0xc1, 0x52, + 0xf4, 0x74, 0xf6, 0x96, 0xb6, 0x97, 0x73, 0xcd, 0x1a, 0xb4, 0x4d, 0xac, + 0x4f, 0xfd, 0x76, 0x0a, 0xc1, 0xc0, 0xd7, 0x94, 0xe4, 0x89, 0xd5, 0xc6, + 0x37, 0xe1, 0xf8, 0x47, 0x20, 0x78, 0xc8, 0xf9, 0xe9, 0xdf, 0xaa, 0xe9, + 0x53, 0x51, 0x0c, 0xc5, 0xac, 0xea, 0x6c, 0xd4, 0x4d, 0x2e, 0x4d, 0x78, + 0x36, 0x00, 0x36, 0x5b, 0xce, 0xca, 0x92, 0xea, 0xb9, 0x90, 0x7e, 0x15, + 0xc2, 0xe2, 0xa9, 0xff, 0x53, 0xa5, 0x91, 0x0f, 0x26, 0x79, 0x72, 0x8e, + 0x69, 0xd9, 0xde, 0xdf, 0x41, 0x85, 0x5a, 0x9b, 0xbe, 0xb7, 0xf7, 0x0f, + 0x0c, 0x24, 0x55, 0xc9, 0x64, 0x85, 0x69, 0xa5, 0x09, 0x92, 0x25, 0x47, + 0x0a, 0x47, 0x49, 0x3d, 0x16, 0x2d, 0xe1, 0x44, 0xf9, 0x3a, 0x0a, 0x82, + 0xcf, 0x3a, 0xf4, 0x1f, 0x18, 0xc4, 0xba, 0x5c, 0x4a, 0xdb, 0xe8, 0xf3, + 0xbb, 0xa4, 0x71, 0x96, 0x6f, 0x5a, 0x77, 0x53, 0x74, 0xf9, 0x40, 0xbc, + 0xae, 0x54, 0xf5, 0x02, 0xae, 0xd1, 0x5f, 0x08, 0xf6, 0x44, 0x65, 0x70, + 0xc2, 0x97, 0x34, 0x10, 0x9a, 0x74, 0x6c, 0x4f, 0x22, 0xa1, 0x50, 0xdf, + 0x17, 0xec, 0x82, 0xed, 0x1d, 0xca, 0x19, 0xdd, 0x67, 0x56, 0x77, 0x3f, + 0x3d, 0x91, 0x19, 0x0e, 0xbb, 0x3b, 0x71, 0x4c, 0xfc, 0x48, 0x60, 0x49, + 0xb2, 0x40, 0x80, 0xbf, 0xc6, 0x71, 0xdf, 0x58, 0x59, 0x73, 0x68, 0x4e, + 0xdb, 0x63, 0xc8, 0xd8, 0x37, 0x97, 0x6a, 0x0a, 0x2a, 0x46, 0xbf, 0xd6, + 0xab, 0x38, 0xaf, 0xf6, 0x42, 0xe6, 0x82, 0x49, 0x3b, 0x6a, 0x0a, 0x43, + 0x04, 0x59, 0xd3, 0x29, 0xf5, 0xd7, 0xef, 0x9e, 0x81, 0x57, 0x3e, 0xa9, + 0x65, 0xa2, 0x20, 0xfd, 0xa3, 0xdc, 0x1e, 0xc3, 0xde, 0xcc, 0x7d, 0xc0, + 0x93, 0xb9, 0x60, 0x56, 0x52, 0x13, 0x51, 0x98, 0xac, 0x60, 0xc2, 0x5f, + 0x84, 0xe9, 0xd6, 0xaa, 0xc6, 0x3c, 0x50, 0x99, 0x98, 0xf5, 0x6e, 0xd7, + 0x7c, 0xe1, 0x08, 0x80, 0x24, 0x76, 0xd0, 0xcc, 0x3a, 0xbd, 0x31, 0x18, + 0x40, 0x7f, 0x79, 0x66, 0xf4, 0x74, 0xb5, 0x83, 0xb3, 0xe2, 0xcc, 0xbc, + 0x49, 0x67, 0x5f, 0x3a, 0x1f, 0xd2, 0x4f, 0x79, 0xf6, 0x38, 0x67, 0xf6, + 0x02, 0x55, 0x21, 0x64, 0xf2, 0x93, 0x5e, 0xbb, 0x3d, 0xa7, 0x5a, 0xc6, + 0xa7, 0x90, 0xd6, 0x46, 0x71, 0x13, 0xb0, 0xa3, 0x47, 0xfe, 0xd5, 0xe0, + 0x17, 0xbd, 0xdc, 0x35, 0x72, 0x68, 0x4e, 0xa0, 0x96, 0xc2, 0xbc, 0x78, + 0x5b, 0xb1, 0x4f, 0x34, 0x26, 0xdc, 0x0f, 0x84, 0x58, 0x6e, 0x7d, 0xb1, + 0x54, 0xc2, 0x9d, 0xac, 0x2c, 0xde, 0xf5, 0xf8, 0x72, 0x43, 0x15, 0x5c, + 0x52, 0x48, 0x0c, 0x67, 0x39, 0x25, 0x8c, 0x3f, 0x49, 0xd2, 0x8b, 0x51, + 0x43, 0xe8, 0x2f, 0x3c, 0x16, 0xdc, 0x48, 0x0b, 0x76, 0xee, 0xd9, 0xb7, + 0x8e, 0x2e, 0x99, 0xbb, 0xa5, 0xda, 0xdd, 0xfe, 0x99, 0x47, 0xf1, 0x22, + 0x53, 0xfc, 0x2e, 0xaa, 0xf7, 0xcf, 0x7b, 0x13, 0x1b, 0x08, 0x18, 0x3a, + 0x6b, 0xe4, 0x66, 0x8a, 0x3e, 0x77, 0xbd, 0x14, 0xb0, 0x90, 0x60, 0xaa, + 0x97, 0x65, 0x1a, 0xd5, 0x0e, 0xea, 0x12, 0xa5, 0x05, 0x87, 0x78, 0x0f, + 0xf4, 0x05, 0xd5, 0x8c, 0x2e, 0x14, 0x26, 0x80, 0x01, 0x7d, 0x06, 0x79, + 0x37, 0x63, 0x70, 0xb1, 0x57, 0x2b, 0x62, 0x2a, 0xe8, 0x76, 0x48, 0x46, + 0x79, 0xea, 0x4a, 0x7a, 0x35, 0xf2, 0xcb, 0x10, 0x7a, 0x3b, 0x62, 0x04, + 0x34, 0x76, 0xe0, 0xf7, 0x9c, 0x1d, 0x73, 0x89, 0x90, 0xf2, 0xc5, 0x79, + 0x7c, 0x15, 0xa0, 0x7f, 0x99, 0x5f, 0xb8, 0x73, 0x62, 0x75, 0x6b, 0x0f, + 0xbe, 0xf1, 0x34, 0x5f, 0x28, 0x14, 0x18, 0x71, 0xe9, 0xde, 0xb7, 0x28, + 0x00, 0x65, 0xa2, 0x08, 0x57, 0xdd, 0x5e, 0x14, 0xa9, 0xc5, 0x0b, 0xb1, + 0x92, 0xa8, 0x20, 0xb2, 0xbd, 0x42, 0x77, 0xf5, 0xb0, 0xa0, 0x00, 0xbe, + 0xa7, 0x82, 0xd0, 0x6a, 0xc8, 0xa9, 0x57, 0xfa, 0x07, 0x3a, 0x97, 0x69, + 0x60, 0xe8, 0xd1, 0x94, 0x0d, 0xa5, 0x7d, 0x74, 0x7f, 0x50, 0xc6, 0x50, + 0x9b, 0x05, 0x41, 0x8d, 0x08, 0x2b, 0x2b, 0x01, 0x37, 0xd0, 0xee, 0x4d, + 0xca, 0x15, 0x70, 0xca, 0x75, 0x4a, 0xc2, 0x54, 0x10, 0xc0, 0x80, 0x27, + 0xe1, 0xcd, 0x52, 0xec, 0x06, 0xb5, 0x73, 0xf4, 0xc2, 0x0b, 0xea, 0x79, + 0xe6, 0x30, 0x5d, 0x41, 0x07, 0x4c, 0x8a, 0xae, 0x03, 0xb0, 0x9b, 0xc2, + 0x5d, 0xf2, 0x43, 0x3f, 0x5e, 0xb7, 0x53, 0x36, 0xc3, 0x81, 0xf6, 0xe5, + 0xd9, 0x35, 0x69, 0x04, 0xe0, 0x36, 0xb8, 0xeb, 0x71, 0x58, 0x71, 0x6f, + 0x47, 0x17, 0xf2, 0x16, 0xe2, 0x09, 0xc7, 0xc2, 0x35, 0xa4, 0x4d, 0xfe, + 0x1a, 0xd2, 0x28, 0x06, 0x34, 0xb3, 0x0f, 0x33, 0xf0, 0xd6, 0x18, 0xf4, + 0x6d, 0x54, 0xb2, 0xbd, 0x88, 0x17, 0x02, 0x40, 0x11, 0x21, 0x59, 0x8b, + 0x62, 0xcb, 0x87, 0xad, 0x0f, 0xc0, 0x08, 0x14, 0x29, 0xf9, 0x5c, 0x3e, + 0xfc, 0xe4, 0x95, 0x1c, 0x9b, 0x60, 0x94, 0xcb, 0x83, 0xb4, 0x1c, 0x1b, + 0xbd, 0xfd, 0x55, 0x88, 0xbf, 0xa6, 0xa5, 0x94, 0xc2, 0xb3, 0x76, 0x5a, + 0x9b, 0xd4, 0xc1, 0xe1, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x51, 0x00, + 0x0a, 0xec, 0x05, 0xf9, 0x03, 0x35, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x85, 0x61, 0x04, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, + 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, + 0x56, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0x41, + 0xb7, 0x59, 0x5c, 0x83, 0x2b, 0xa8, 0x0d, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, + 0x0f, 0xc0, 0x25, 0xc5, 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, + 0x52, 0xf9, 0x26, 0x9b, 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, + 0x76, 0x12, 0x4a, 0x40, 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, + 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, + 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x4e, 0x6b, 0x19, 0x54, 0xf5, 0xf0, 0xaf, 0x61, 0xfa, 0x1e, 0x1f, 0x1f, + 0x5e, 0x17, 0xd3, 0x8e, 0x04, 0x4b, 0xfa, 0x8d, 0x34, 0x55, 0x45, 0x92, + 0xd5, 0xd0, 0xb8, 0x8e, 0x56, 0xe9, 0x39, 0x37, 0x8e, 0x7d, 0x7e, 0x88, + 0x56, 0x30, 0x48, 0x61, 0xb4, 0xed, 0x1e, 0x15, 0x64, 0xfc, 0xa8, 0xb1, + 0x02, 0xbb, 0x9c, 0x14, 0xe9, 0xd1, 0xe0, 0xcf, 0x40, 0x41, 0x46, 0x5d, + 0xb0, 0xda, 0xba, 0x8c, 0x3a, 0x41, 0x12, 0x91, 0xeb, 0x13, 0xdf, 0x2c, + 0x6e, 0x25, 0x75, 0xb3, 0x92, 0xff, 0xb0, 0xa9, 0xa5, 0xef, 0x3a, 0x4c, + 0x6b, 0x54, 0x55, 0x0e, 0x7e, 0x93, 0x16, 0x7f, 0xe6, 0x22, 0x22, 0x51, + 0xe2, 0x22, 0xa4, 0x35, 0x33, 0xec, 0xdc, 0xa8, 0x73, 0x64, 0x59, 0xc1, + 0x4d, 0xad, 0xa0, 0x56, 0xbf, 0xad, 0x45, 0x64, 0xda, 0xb0, 0x08, 0x4a, + 0x82, 0xfc, 0x0d, 0x21, 0xb7, 0x8b, 0x59, 0x90, 0xac, 0xb2, 0x08, 0x1b, + 0x50, 0x82, 0x0c, 0x87, 0xd6, 0x48, 0x5c, 0xdd, 0x6b, 0x02, 0x7f, 0xab, + 0x3e, 0xdc, 0x25, 0x1f, 0x53, 0x49, 0xb5, 0x6d, 0x0f, 0x0c, 0xbe, 0xae, + 0x1d, 0xab, 0x8b, 0x13, 0x9d, 0xd7, 0x6c, 0x91, 0xaa, 0x90, 0xe8, 0x63, + 0x06, 0x6d, 0xa8, 0xf0, 0xea, 0x21, 0xf6, 0xa8, 0xfd, 0x15, 0x6d, 0x78, + 0x66, 0x42, 0xae, 0x4c, 0xa7, 0x7a, 0x85, 0x15, 0x7d, 0xf9, 0xed, 0x92, + 0x1c, 0xde, 0x7c, 0x71, 0xd0, 0x6b, 0x25, 0x24, 0x22, 0x6b, 0xe4, 0x5e, + 0x60, 0xda, 0xbd, 0x95, 0x32, 0x21, 0xe8, 0xb1, 0xcb, 0x07, 0x1b, 0x08, + 0xf5, 0x49, 0x4f, 0x60, 0x8c, 0xe8, 0xb0, 0x71, 0x2a, 0x8b, 0x91, 0x17, + 0x16, 0x93, 0x39, 0x49, 0x8d, 0x47, 0x1f, 0xe8, 0x2b, 0x12, 0xa6, 0x4f, + 0xa1, 0x77, 0x37, 0xe7, 0x39, 0x68, 0x5c, 0x68, 0x2b, 0xad, 0xa8, 0x3c, + 0xa0, 0x8a, 0xf5, 0xb7, 0x51, 0x9f, 0x2d, 0x85, 0x1a, 0x99, 0x02, 0x4c, + 0x84, 0x5f, 0x4d, 0xe6, 0x55, 0x64, 0xd7, 0x5b, 0x00, 0x48, 0xde, 0xf2, + 0x77, 0x39, 0x6e, 0x7b, 0x0e, 0x97, 0x81, 0xd2, 0x8a, 0x1b, 0x20, 0x30, + 0x60, 0xbe, 0x94, 0xf0, 0x09, 0x34, 0xfe, 0x64, 0xbb, 0xbb, 0xcb, 0x97, + 0x91, 0x43, 0x6d, 0x57, 0x45, 0x7d, 0xc5, 0x43, 0x5a, 0x78, 0x0d, 0xd8, + 0xb9, 0xf5, 0x43, 0x13, 0x21, 0xd6, 0x31, 0x6e, 0x21, 0x9a, 0x3f, 0x8f, + 0xe2, 0x57, 0x32, 0xdb, 0x50, 0x61, 0x45, 0x9f, 0xb9, 0x7b, 0x73, 0x10, + 0xb9, 0xd0, 0x66, 0xaf, 0xa0, 0x3a, 0x77, 0x93, 0x9b, 0xd3, 0x32, 0xb0, + 0xda, 0x01, 0x17, 0x90, 0x1a, 0xa5, 0x9f, 0x2b, 0x9f, 0x8f, 0x93, 0x6e, + 0x4d, 0x69, 0x40, 0xec, 0x56, 0x76, 0x61, 0x2d, 0xcd, 0xdf, 0xc5, 0xfe, + 0x9e, 0x26, 0x2f, 0x78, 0x78, 0xab, 0x5a, 0x32, 0xa6, 0xe9, 0x7a, 0x85, + 0x15, 0xc6, 0x2f, 0x10, 0x37, 0x35, 0xf6, 0xfa, 0xc0, 0xdd, 0xb0, 0xa9, + 0xa1, 0x0d, 0x22, 0xc1, 0xab, 0xc8, 0x8c, 0x2a, 0x77, 0x0b, 0xd3, 0x52, + 0xdb, 0x53, 0x33, 0x78, 0xf3, 0xf6, 0x33, 0x5d, 0x9f, 0xb7, 0xb6, 0x46, + 0xf6, 0x79, 0x9e, 0x08, 0x16, 0xd8, 0x48, 0xcf, 0x70, 0x4d, 0x00, 0x36, + 0x30, 0xdb, 0xb3, 0x76, 0xa5, 0x16, 0x78, 0xf8, 0xaf, 0x71, 0x6b, 0x50, + 0x92, 0xfc, 0x52, 0xd6, 0x2c, 0xee, 0xa8, 0xb0, 0xbe, 0x89, 0x18, 0xc0, + 0x7a, 0x72, 0xa5, 0x36, 0x31, 0x7b, 0x86, 0xca, 0xc0, 0xe4, 0x08, 0x17, + 0x1d, 0x6e, 0xe5, 0x4c, 0x82, 0x86, 0x3e, 0x8c, 0x60, 0xf7, 0x04, 0x8f, + 0x2c, 0x64, 0x3d, 0x2e, 0x23, 0x22, 0x10, 0x8e, 0x88, 0x45, 0xcd, 0x18, + 0xd6, 0xba, 0x4c, 0x40, 0x1e, 0x31, 0xfb, 0xbf, 0xda, 0xe7, 0xae, 0x87, + 0x72, 0x81, 0xb2, 0x69, 0x97, 0xe3, 0x2c, 0x5e, 0xbb, 0x26, 0x1b, 0xe2, + 0x83, 0xf3, 0x90, 0x37, 0x0d, 0xb1, 0xa2, 0x58, 0x88, 0x63, 0xe7, 0x6e, + 0x4a, 0xbd, 0x76, 0x90, 0x73, 0x65, 0x85, 0x96, 0xcc, 0x2d, 0xb7, 0x51, + 0x0d, 0xa7, 0x8a, 0xe2, 0x8c, 0x47, 0xb9, 0x44, 0x09, 0xc3, 0x8f, 0x24, + 0x65, 0x79, 0xf0, 0xd0, 0xc3, 0xa5, 0x1f, 0xc3, 0xca, 0xd7, 0x57, 0xac, + 0x1c, 0xcf, 0xa9, 0xfc, 0x81, 0x12, 0x53, 0x0b, 0xe5, 0x9d, 0x38, 0x29, + 0x14, 0xd6, 0xf5, 0x17, 0x06, 0xfb, 0xc2, 0x9d, 0x25, 0x10, 0xf9, 0xde, + 0x4b, 0x33, 0x0d, 0xf1, 0xdd, 0xf5, 0xbc, 0xa8, 0x2b, 0xdc, 0xdb, 0x51, + 0x7d, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x85, 0x41, 0x03, + 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, + 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, + 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x89, 0x16, 0x17, 0x13, 0x41, + 0xb7, 0x59, 0x5c, 0x83, 0x25, 0xab, 0x8f, 0x41, 0xb7, 0x59, 0x5c, 0x83, + 0x25, 0xab, 0x8f, 0xdf, 0xb4, 0xb1, 0x32, 0xb5, 0x0f, 0xc0, 0x25, 0xc5, + 0x8d, 0xd9, 0x08, 0xc5, 0x28, 0x81, 0xd3, 0x73, 0x52, 0xf9, 0x26, 0x9b, + 0x66, 0x83, 0xaf, 0x24, 0x40, 0x8e, 0xa7, 0xd6, 0x76, 0x12, 0x4a, 0x40, + 0x61, 0xb5, 0x6a, 0xbc, 0x33, 0xef, 0x01, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0x2b, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe3, 0xb5, 0xfb, 0x0d, + 0xa0, 0x75, 0xd1, 0xa9, 0x33, 0x31, 0xc6, 0x84, 0xba, 0x58, 0x50, 0xb0, + 0x71, 0x32, 0x4f, 0x72, 0x88, 0x46, 0x71, 0x06, 0xb3, 0x82, 0x5e, 0x30, + 0xfd, 0xc8, 0x5b, 0xc8, 0xf3, 0x24, 0x92, 0xe0, 0xce, 0x8b, 0xf7, 0x50, + 0x20, 0xc3, 0xeb, 0x1b, 0xf4, 0xef, 0x4f, 0xfa, 0x28, 0x4d, 0x02, 0x4d, + 0x7c, 0x46, 0xf1, 0x91, 0x89, 0xde, 0xc6, 0xfa, 0x79, 0xc5, 0xbd, 0x17, + 0xa1, 0xc6, 0x1d, 0x8c, 0xd4, 0x57, 0xa6, 0x58, 0x66, 0xce, 0xe5, 0xb0, + 0x8b, 0x54, 0xef, 0x3b, 0x24, 0x9b, 0xa4, 0xc4, 0x6a, 0xa9, 0xf3, 0x1b, + 0x73, 0x37, 0x10, 0xc0, 0xe1, 0xcb, 0xc8, 0x90, 0x14, 0x88, 0x97, 0x25, + 0x8b, 0x7c, 0xa2, 0x66, 0x36, 0x89, 0x55, 0x8d, 0x68, 0xe7, 0x55, 0x20, + 0x10, 0x68, 0x14, 0x2f, 0x05, 0x3b, 0xe3, 0x81, 0x08, 0xfe, 0x54, 0x7d, + 0xa5, 0x51, 0x2a, 0x39, 0x86, 0x11, 0xce, 0x26, 0x8d, 0xe1, 0xec, 0x30, + 0x3f, 0xf9, 0xa3, 0x3d, 0x43, 0x6c, 0xad, 0x23, 0x54, 0x20, 0x7d, 0x60, + 0xa5, 0x42, 0xbd, 0x3d, 0x22, 0xc8, 0x95, 0x9b, 0xab, 0x5b, 0xf7, 0xc1, + 0x11, 0xfb, 0xf1, 0x70, 0xa2, 0x43, 0xcb, 0x53, 0x8c, 0x18, 0x0d, 0x8a, + 0xb2, 0xa5, 0xbd, 0x87, 0x2b, 0x8b, 0xdf, 0x79, 0x96, 0x29, 0x20, 0x8e, + 0x34, 0x4a, 0x45, 0x96, 0x33, 0x8d, 0xa8, 0xb0, 0x47, 0x26, 0x4f, 0x8b, + 0xad, 0xb5, 0xa7, 0x2d, 0x15, 0x58, 0x92, 0x7b, 0x4b, 0x53, 0xa9, 0x5e, + 0x51, 0x39, 0x9c, 0xbd, 0x7e, 0x8f, 0x7f, 0x9f, 0xb7, 0x38, 0xcd, 0x7e, + 0xff, 0x7d, 0x73, 0x1f, 0xab, 0x3a, 0x61, 0xaa, 0xde, 0x73, 0x28, 0xb2, + 0x6f, 0x1e, 0xc9, 0x5e, 0x59, 0x71, 0x6b, 0xe8, 0x6d, 0x63, 0xf3, 0x9e, + 0xdf, 0x52, 0x86, 0x60, 0x1c, 0xbd, 0xc7, 0xeb, 0xaf, 0x82, 0x83, 0xaa, + 0x68, 0xa6, 0x71, 0x7a, 0xe8, 0xd3, 0xd4, 0xc8, 0xe7, 0x9a, 0xcc, 0x3c, + 0xc2, 0xdf, 0x0c, 0x42, 0xe8, 0xae, 0xc7, 0xd8, 0x1f, 0x66, 0x0a, 0x57, + 0x09, 0x14, 0x02, 0x74, 0x9a, 0x7a, 0x07, 0xb3, 0x19, 0x87, 0x8d, 0xa9, + 0x45, 0x25, 0x26, 0x48, 0xb3, 0x20, 0x3c, 0xf7, 0x5a, 0x1c, 0xae, 0xc7, + 0x06, 0x9e, 0x1a, 0x0a, 0x23, 0xf3, 0x39, 0x25, 0x2c, 0x91, 0x7c, 0x5e, + 0x87, 0xe7, 0x55, 0xc4, 0x69, 0xf3, 0x3e, 0xeb, 0xc5, 0x44, 0xa8, 0xe3, + 0xec, 0xc1, 0xfe, 0x70, 0xbf, 0xdd, 0xbb, 0xf0, 0x22, 0xe1, 0x19, 0xa1, + 0x6d, 0x7a, 0x9a, 0xa3, 0x36, 0x90, 0xbc, 0x1a, 0xa7, 0x37, 0xf8, 0xcf, + 0xdc, 0x9e, 0x23, 0x17, 0x42, 0xd5, 0xa0, 0xd3, 0x36, 0xb0, 0xb1, 0xf5, + 0x1a, 0x95, 0xbc, 0xe8, 0x0f, 0xb4, 0x58, 0x76, 0x40, 0x74, 0xd0, 0x21, + 0xaf, 0xae, 0xc6, 0xb4, 0x84, 0xd7, 0xfc, 0x70, 0x6a, 0x8f, 0x41, 0x57, + 0x2b, 0x8e, 0xbc, 0x6b, 0x21, 0x65, 0xcc, 0xa0, 0x8e, 0xb9, 0x0b, 0x46, + 0xef, 0xb3, 0x56, 0xec, 0x8a, 0xd6, 0x4d, 0xdd, 0x97, 0xbd, 0xdd, 0x65, + 0xbf, 0x26, 0xab, 0xba, 0x0d, 0xd1, 0x22, 0x7e, 0xb6, 0x8a, 0xb4, 0x92, + 0xc9, 0xa6, 0x48, 0xd4, 0x64, 0x17, 0xc6, 0xb5, 0xb9, 0xce, 0x45, 0x6d, + 0xf4, 0xd9, 0x3d, 0xa0, 0xb3, 0x86, 0x67, 0x19, 0xad, 0xd8, 0x32, 0x2b, + 0xf7, 0xab, 0x90, 0xee, 0x91, 0x8f, 0x73, 0xe4, 0xc0, 0x29, 0xde, 0x45, + 0x8a, 0xfb, 0xca, 0x74, 0x3b, 0x50, 0xf1, 0x34, 0x40, 0x36, 0x25, 0x8a, + 0xe0, 0xf9, 0x7f, 0x55, 0xc5, 0x59, 0x89, 0xbb, 0x43, 0x03, 0xa3, 0xdd, + 0x8c, 0x83, 0x03, 0xc6, 0xef, 0x60, 0x02, 0xc5, 0xd8, 0x29, 0x3f, 0x2f, + 0x56, 0xba, 0x8b, 0x97, 0x0a, 0xc4, 0xf3, 0x07, 0x3f, 0xca, 0x0f, 0xdf, + 0xb9, 0x5d, 0x59, 0x42, 0x36, 0x02, 0xf7, 0x0f, 0x03, 0xc8, 0xf2, 0xb7, + 0xd8, 0x64, 0xcd, 0x1e, 0xe4, 0xe1, 0xa0, 0xbd, 0x0f, 0x70, 0xfb, 0xcf, + 0x77, 0x77, 0xef, 0x9d, 0xdd, 0xc1, 0x61, 0xab, 0x3c, 0xdb, 0xe4, 0x35, + 0x11, 0xab, 0xde, 0x40, 0x7d, 0x51, 0xba, 0xb1, 0x7d, 0x13, 0xf1, 0x58, + 0x03, 0xca, 0xae, 0x12, 0x4a, 0xa3, 0xb6, 0xed, 0xd7, 0x18, 0x1c, 0xb6, + 0xd8, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x89, 0x70, 0x02, + 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, + 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, + 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x91, 0x62, 0x29, 0x13, 0x41, + 0xb7, 0x59, 0x5c, 0x4b, 0xa2, 0xb8, 0x84, 0x41, 0xb7, 0x59, 0x5c, 0x4b, + 0xa2, 0xb8, 0x84, 0x37, 0xee, 0x5a, 0x85, 0xe1, 0xcb, 0xdd, 0xc8, 0xce, + 0x07, 0x77, 0xee, 0x01, 0x3f, 0x96, 0x7b, 0x33, 0x30, 0x3a, 0xcd, 0x64, + 0x14, 0x5e, 0x86, 0xb3, 0x7b, 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, + 0x7e, 0x59, 0x45, 0xac, 0xff, 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0x2a, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xfa, 0x4b, 0x92, 0xea, + 0x4b, 0xef, 0xde, 0x03, 0xd5, 0xe2, 0xee, 0xe5, 0x67, 0xd4, 0x99, 0x63, + 0x37, 0x68, 0x91, 0xbc, 0x4f, 0xbc, 0x41, 0xe9, 0x01, 0xc5, 0x4d, 0x59, + 0x2a, 0x9b, 0x42, 0x60, 0x07, 0x7e, 0xc2, 0xbc, 0x62, 0xcc, 0xbc, 0xa7, + 0xf1, 0xe4, 0x20, 0x5f, 0xe3, 0xe8, 0x9f, 0x16, 0x7a, 0x77, 0xd2, 0xb7, + 0xad, 0x98, 0xc3, 0xb4, 0x99, 0xdb, 0x36, 0x1a, 0xe4, 0xf0, 0xfc, 0xe1, + 0xc8, 0x2f, 0x8c, 0xcf, 0x6f, 0x97, 0x48, 0x09, 0x4a, 0xae, 0xc7, 0xf9, + 0xfb, 0xb7, 0x5f, 0x64, 0x6a, 0x79, 0xa1, 0x27, 0xeb, 0x59, 0x7d, 0x0a, + 0xd3, 0x56, 0x27, 0x1d, 0x56, 0xd3, 0x62, 0x1e, 0x7f, 0xb5, 0x0f, 0x50, + 0x9c, 0x4d, 0x1d, 0xd5, 0x53, 0xcb, 0x08, 0x07, 0x56, 0x93, 0x9e, 0x4f, + 0xb2, 0xd0, 0x12, 0xc7, 0x50, 0xcf, 0x99, 0xac, 0x24, 0xdb, 0x94, 0xab, + 0x08, 0x89, 0x60, 0x2f, 0x6c, 0xd0, 0xc2, 0x2e, 0x6d, 0x08, 0xe0, 0xf9, + 0xfc, 0x7e, 0x5b, 0x54, 0x92, 0xaa, 0x01, 0xfd, 0xf6, 0x49, 0xb1, 0xfc, + 0xd4, 0x51, 0x83, 0x73, 0xaf, 0xac, 0x38, 0x78, 0x8e, 0x9b, 0x42, 0x4e, + 0x83, 0xbb, 0x9d, 0xd7, 0x5c, 0xdb, 0x73, 0xd3, 0x3d, 0x2c, 0xe2, 0x4c, + 0x57, 0xa4, 0xfa, 0xdf, 0x53, 0x44, 0x29, 0x71, 0x22, 0xb6, 0x89, 0x84, + 0x80, 0xca, 0xcb, 0x7c, 0x5f, 0x15, 0x19, 0x4b, 0x06, 0x28, 0x5d, 0x4a, + 0x9b, 0xc8, 0x59, 0xa7, 0x9e, 0xa2, 0xba, 0x32, 0x5d, 0xf2, 0xcb, 0xa9, + 0xc6, 0xba, 0x09, 0xee, 0xd2, 0x00, 0x32, 0x53, 0x8b, 0x39, 0xff, 0xc4, + 0x63, 0xac, 0xbc, 0x1c, 0x15, 0xb8, 0x79, 0xc2, 0xe3, 0xda, 0x8d, 0xb2, + 0x95, 0x8d, 0x3c, 0x10, 0xec, 0x93, 0x03, 0xc1, 0x07, 0x84, 0x47, 0xf3, + 0xeb, 0xe3, 0x10, 0x33, 0xa1, 0x2e, 0xc6, 0x48, 0x44, 0x2c, 0x38, 0x36, + 0xe1, 0x68, 0x3c, 0xe8, 0x0d, 0x5c, 0x8a, 0xdc, 0x1f, 0xe8, 0x3b, 0xb2, + 0x0f, 0xea, 0x27, 0x18, 0x7a, 0x7f, 0x82, 0x6a, 0x96, 0xfa, 0x63, 0xd3, + 0x5c, 0xbf, 0xf6, 0x1d, 0x9e, 0xf2, 0xd9, 0x83, 0x3b, 0xf0, 0x1b, 0x29, + 0x49, 0x8d, 0xb3, 0xdc, 0x60, 0x47, 0x9d, 0x2b, 0xac, 0xd6, 0x6e, 0x59, + 0xb3, 0x09, 0x0d, 0xa7, 0xfb, 0x0e, 0x43, 0x56, 0xa3, 0x80, 0x2c, 0x9f, + 0xc1, 0xe8, 0xd2, 0xef, 0x05, 0xc5, 0x25, 0x4c, 0x5b, 0x67, 0x1a, 0x54, + 0x0b, 0x55, 0x83, 0x3d, 0xfb, 0x38, 0x0e, 0xd2, 0xc0, 0x1a, 0xcd, 0x9f, + 0x81, 0x3e, 0x6d, 0x7f, 0xe4, 0x3f, 0x34, 0x0c, 0xdc, 0x99, 0x5a, 0x77, + 0xd4, 0xe4, 0xff, 0x4a, 0x7b, 0x8a, 0x95, 0xe4, 0x46, 0x3d, 0x7b, 0xc4, + 0x0e, 0xdd, 0xc7, 0x2d, 0xf4, 0xfa, 0x5e, 0x50, 0xae, 0x9c, 0xca, 0x64, + 0x97, 0xad, 0x03, 0x30, 0x3e, 0x05, 0xc4, 0x33, 0x1e, 0x2c, 0x03, 0x2b, + 0x06, 0x2c, 0x79, 0x13, 0xae, 0x1b, 0x65, 0xf1, 0x1f, 0xb9, 0xe4, 0x8a, + 0x06, 0x96, 0xea, 0xc4, 0x6e, 0x17, 0x19, 0x03, 0x54, 0xe8, 0x39, 0xe7, + 0xeb, 0x7b, 0xbc, 0x25, 0xd6, 0x55, 0x6c, 0x76, 0x5f, 0xf7, 0xd2, 0x0e, + 0x54, 0x46, 0x9f, 0x5d, 0xa4, 0x3d, 0xac, 0xa1, 0x19, 0x7b, 0x7c, 0x5a, + 0x44, 0x54, 0x65, 0x5d, 0x43, 0x26, 0x5f, 0x47, 0x63, 0x2b, 0x00, 0xe3, + 0xb4, 0xe9, 0x70, 0x8c, 0x31, 0x50, 0x7c, 0x37, 0x01, 0x43, 0x6c, 0x29, + 0xc3, 0xae, 0x59, 0xb7, 0x0b, 0xb9, 0x9a, 0x72, 0x69, 0xe0, 0xd1, 0xb0, + 0x47, 0x53, 0xf0, 0xb8, 0x8b, 0xc8, 0x80, 0x3c, 0x58, 0xfa, 0x34, 0xf2, + 0x44, 0x27, 0xb7, 0xfc, 0x44, 0x73, 0xfb, 0xe5, 0xe1, 0x8b, 0xdb, 0x2b, + 0xc5, 0x73, 0x97, 0x25, 0xb3, 0xef, 0x16, 0xfd, 0xba, 0x08, 0x3d, 0x15, + 0x2a, 0x03, 0xb5, 0x4d, 0x2a, 0x8c, 0xf5, 0x53, 0x11, 0x97, 0x3c, 0x35, + 0x66, 0x1d, 0x59, 0xc8, 0xc9, 0x79, 0x48, 0x6d, 0x19, 0x4f, 0xa7, 0x07, + 0x25, 0x4d, 0xb2, 0xfc, 0x1e, 0xbc, 0x9a, 0x0c, 0x6e, 0x46, 0x2b, 0x58, + 0x45, 0xbe, 0xe7, 0x8e, 0x09, 0xa5, 0xa0, 0xd3, 0x5a, 0xf5, 0x6e, 0x92, + 0x7b, 0x5b, 0x21, 0x07, 0xab, 0xf3, 0x57, 0xd6, 0x93, 0x4b, 0x56, 0x3b, + 0x9c, 0x3c, 0x4b, 0x85, 0xb0, 0x62, 0x18, 0x3e, 0x7c, 0xc5, 0x25, 0xe2, + 0xf2, 0xfc, 0xa3, 0xca, 0x88, 0xd6, 0xb2, 0x01, 0x11, 0xcd, 0x93, 0x9a, + 0x76, 0x84, 0xc2, 0x2d, 0x07, 0xd3, 0xbb, 0xac, 0x99, 0xde, 0x29, 0x00, + 0xf7, 0x3d, 0x06, 0xea, 0xdc, 0x88, 0xfd, 0xc6, 0x6e, 0xf5, 0x55, 0x64, + 0x73, 0x4e, 0x3b, 0xa9, 0x24, 0x44, 0x63, 0x1c, 0x50, 0x29, 0x66, 0xc4, + 0x74, 0x70, 0xcb, 0xd8, 0x57, 0x0c, 0x60, 0x50, 0x6d, 0x64, 0x64, 0xd1, + 0x53, 0xef, 0x62, 0xef, 0x61, 0xf4, 0xe2, 0xfe, 0x4c, 0xaa, 0x9f, 0xe9, + 0x81, 0x01, 0xe1, 0x97, 0xaa, 0xc0, 0x06, 0xbf, 0x40, 0x19, 0x64, 0x24, + 0x6e, 0x80, 0x73, 0x00, 0x5c, 0x86, 0x3e, 0xc2, 0xcf, 0x8c, 0x09, 0xc0, + 0xfa, 0x4a, 0xb3, 0x3a, 0x0d, 0x81, 0x1d, 0x49, 0x58, 0x09, 0xe8, 0x31, + 0x0e, 0xd7, 0x60, 0x8d, 0x9d, 0xfe, 0x9f, 0x35, 0xf7, 0x8d, 0xa1, 0x12, + 0x04, 0xb2, 0x47, 0xac, 0x31, 0x92, 0x03, 0x0a, 0x10, 0x50, 0xb7, 0x86, + 0x3d, 0xcd, 0x15, 0x8f, 0x25, 0x93, 0x24, 0x7a, 0x5f, 0xa0, 0x3c, 0x41, + 0xaa, 0xb2, 0x96, 0xce, 0xd3, 0x0c, 0xe9, 0x55, 0x66, 0x37, 0x5c, 0xf3, + 0x02, 0x3c, 0xa1, 0x09, 0xa4, 0x9e, 0x90, 0xc9, 0x82, 0xab, 0xd4, 0x04, + 0x2e, 0x8b, 0xb4, 0x8d, 0x5b, 0xcc, 0x19, 0x5a, 0xfe, 0x86, 0x9c, 0x6c, + 0x56, 0x09, 0x86, 0x36, 0xef, 0xe8, 0x1f, 0x3a, 0xbc, 0xda, 0x4c, 0x68, + 0xac, 0xa2, 0x1b, 0xd1, 0x23, 0x75, 0x28, 0xed, 0x9f, 0x84, 0x2e, 0x40, + 0x57, 0x5f, 0x0a, 0x85, 0xe4, 0x77, 0x59, 0x53, 0x12, 0x32, 0xd6, 0x3c, + 0x1b, 0xaf, 0x95, 0xa1, 0x1c, 0x14, 0x1a, 0x42, 0x7d, 0xc7, 0x7b, 0x21, + 0xd1, 0x4e, 0xb9, 0x29, 0x85, 0xef, 0xa2, 0x61, 0x1c, 0xe5, 0x16, 0x44, + 0xbe, 0xfb, 0xa3, 0x21, 0x4f, 0x94, 0x70, 0xff, 0x5c, 0xc2, 0x1d, 0x0b, + 0x39, 0x36, 0x84, 0x0e, 0x61, 0xe2, 0x1c, 0x63, 0x74, 0xe0, 0x30, 0x01, + 0xbe, 0x39, 0x0f, 0x6f, 0xe6, 0x29, 0xad, 0xd8, 0x8c, 0xdd, 0x8b, 0x24, + 0x38, 0x6f, 0x67, 0x8a, 0x2d, 0x82, 0x1e, 0x8e, 0x45, 0xcb, 0xec, 0x2d, + 0xe3, 0xb4, 0x03, 0x8e, 0x46, 0x2e, 0x01, 0xb0, 0xca, 0x4f, 0xe0, 0x2c, + 0x52, 0xd3, 0x4c, 0xdd, 0xd6, 0x62, 0xf3, 0x38, 0x3f, 0x3c, 0xc1, 0x58, + 0xaa, 0x87, 0x3d, 0x4f, 0xb2, 0xb1, 0x54, 0x65, 0xdc, 0x1c, 0xc8, 0x16, + 0x88, 0x15, 0x53, 0xb0, 0x4e, 0x77, 0xae, 0xe0, 0x34, 0x18, 0x36, 0x34, + 0x31, 0x74, 0x4c, 0x79, 0x0f, 0x2b, 0x1a, 0x11, 0x06, 0x06, 0xaa, 0x60, + 0x31, 0x6e, 0x65, 0x9e, 0x1b, 0xb0, 0x61, 0xd6, 0x90, 0xd1, 0x1d, 0x4c, + 0x36, 0xfe, 0xec, 0x26, 0xcc, 0xba, 0xce, 0xd7, 0xe7, 0x0c, 0x53, 0x90, + 0xe8, 0xce, 0xce, 0xed, 0x58, 0x37, 0x37, 0x3f, 0x40, 0x39, 0xeb, 0x8c, + 0xfb, 0x7d, 0x93, 0xa2, 0x26, 0x4e, 0xbf, 0x49, 0xe7, 0x95, 0xc0, 0x12, + 0x6a, 0xec, 0xfb, 0xbe, 0x00, 0x62, 0xb9, 0xc9, 0x0d, 0x5a, 0x37, 0xf9, + 0xae, 0x84, 0x95, 0x89, 0x20, 0x47, 0x48, 0xf6, 0xf8, 0x73, 0x92, 0x5f, + 0xe1, 0x4a, 0xb4, 0x9e, 0xd8, 0x75, 0xf3, 0x38, 0x48, 0xe1, 0x29, 0x95, + 0x0d, 0x74, 0x6b, 0x98, 0x96, 0x6e, 0xc9, 0x3f, 0xfc, 0x44, 0x91, 0x4d, + 0xf4, 0x4c, 0xb7, 0x38, 0xd7, 0xec, 0xbf, 0xf6, 0x78, 0x05, 0x7d, 0x1b, + 0xe5, 0x68, 0x8a, 0xbc, 0x6a, 0x6a, 0x29, 0xb6, 0xc6, 0x9a, 0x8d, 0x7a, + 0x0e, 0x00, 0x80, 0x73, 0xf5, 0x88, 0x5d, 0x2a, 0xa2, 0x60, 0x98, 0x1e, + 0xf5, 0x06, 0x3b, 0xef, 0xa9, 0x46, 0x6b, 0x89, 0x24, 0xb0, 0xf4, 0x34, + 0x42, 0x15, 0x87, 0xd3, 0xc9, 0x36, 0xe0, 0x52, 0x5f, 0x57, 0x8e, 0x65, + 0x5c, 0x7f, 0x7c, 0xf2, 0x66, 0xd8, 0xd1, 0xbf, 0x13, 0x95, 0x65, 0xb0, + 0x7a, 0xa0, 0xbb, 0xee, 0xc9, 0x20, 0xff, 0x26, 0xda, 0xa0, 0x61, 0x65, + 0xd5, 0x3c, 0xdf, 0xb5, 0xf0, 0xd2, 0x02, 0x4f, 0x97, 0x65, 0x48, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x73, + 0x64, 0x64, 0x6b, 0x75, 0x8a, 0x11, 0x01, 0x23, 0x00, 0x07, 0x07, 0x09, + 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, + 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, + 0x08, 0x09, 0x92, 0x1a, 0x33, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, + 0xf6, 0xba, 0x41, 0xb7, 0x59, 0x5c, 0x4b, 0x89, 0xf6, 0xba, 0xb1, 0x0a, + 0x33, 0x78, 0x48, 0x21, 0xea, 0x97, 0x6e, 0xb7, 0xc7, 0x2e, 0xdb, 0x0f, + 0x9b, 0x01, 0xd0, 0x22, 0x6d, 0xbb, 0x64, 0x14, 0x5e, 0x86, 0xb3, 0x7b, + 0x2d, 0x6c, 0xa9, 0xc0, 0xcf, 0xd8, 0x43, 0x7e, 0x59, 0x45, 0xac, 0xff, + 0x92, 0x4b, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x04, + 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x12, 0x83, 0x28, 0x8c, 0xcd, 0x78, 0x8c, 0x1b, 0x02, + 0xa2, 0x38, 0xa7, 0x25, 0xc1, 0x25, 0x59, 0xcd, 0x36, 0xb2, 0x21, 0xa1, + 0x91, 0xd0, 0xc3, 0x54, 0x89, 0x64, 0xa8, 0x3d, 0x07, 0xcb, 0x8f, 0xf7, + 0xa6, 0x55, 0xc2, 0x96, 0xf6, 0x35, 0xc1, 0x67, 0xdf, 0x2f, 0x1f, 0xda, + 0xa8, 0xf8, 0x8c, 0xc9, 0xa7, 0x5e, 0x7f, 0x1f, 0xa8, 0xd3, 0x38, 0x57, + 0xa2, 0xf4, 0x57, 0x32, 0x17, 0xe3, 0x06, 0xe3, 0xb6, 0x56, 0x60, 0x6e, + 0xbe, 0x12, 0x60, 0x00, 0xfd, 0xa8, 0x4c, 0x3f, 0x2b, 0x54, 0x9c, 0xfb, + 0x87, 0x8b, 0xfa, 0x9e, 0xb8, 0xb2, 0x80, 0x36, 0xf1, 0x5b, 0xcd, 0x9d, + 0x74, 0xa1, 0x7b, 0xbf, 0xf6, 0x4c, 0x64, 0x58, 0x67, 0x8b, 0x68, 0x05, + 0x15, 0x7e, 0x4b, 0x54, 0xe9, 0x84, 0x59, 0x70, 0x42, 0x80, 0x67, 0x6c, + 0x45, 0x62, 0x12, 0x03, 0x27, 0x2b, 0x32, 0xdc, 0x78, 0x85, 0x3d, 0x74, + 0x28, 0x89, 0x5c, 0x33, 0x15, 0x79, 0x63, 0x1f, 0xd7, 0x26, 0xbf, 0x5d, + 0xf6, 0xb1, 0xb7, 0x9e, 0x37, 0x86, 0xd8, 0xf6, 0xf9, 0xc3, 0x66, 0x90, + 0x50, 0x5a, 0x0e, 0xeb, 0xcc, 0xe0, 0xf2, 0x19, 0xbb, 0xd7, 0x6a, 0xe4, + 0xea, 0x87, 0xf9, 0x17, 0x20, 0x88, 0xf6, 0xc0, 0xc7, 0xb7, 0x55, 0x25, + 0xef, 0x15, 0xec, 0xc5, 0x80, 0x52, 0x9a, 0x92, 0xdb, 0x32, 0xf3, 0xc2, + 0xa2, 0x55, 0xd6, 0xd9, 0x5b, 0xe6, 0xb1, 0x95, 0x18, 0x2b, 0xf8, 0x94, + 0x21, 0x56, 0x29, 0x30, 0xf3, 0x61, 0x39, 0x22, 0x03, 0x86, 0xce, 0x81, + 0x6d, 0x9e, 0xdb, 0x5b, 0x49, 0xdb, 0x2c, 0x1d, 0x0d, 0x45, 0xa9, 0xb3, + 0x1c, 0x1a, 0x43, 0x36, 0x1d, 0xd2, 0x76, 0x28, 0x27, 0xe0, 0xd3, 0x19, + 0x56, 0xd3, 0x52, 0xb2, 0xa0, 0x9c, 0xda, 0xb7, 0xac, 0x4d, 0xb1, 0x98, + 0x22, 0xa5, 0x86, 0x5d, 0x79, 0x6a, 0x69, 0x06, 0xd7, 0x07, 0xe7, 0x44, + 0x55, 0x6c, 0xc7, 0xd0, 0x8a, 0x2b, 0xa1, 0x45, 0xc6, 0xbf, 0xf3, 0x21, + 0x2e, 0x41, 0x5c, 0x84, 0xa2, 0x77, 0x46, 0x65, 0x80, 0x75, 0xba, 0x49, + 0xd6, 0xd7, 0x73, 0xeb, 0x35, 0x2c, 0x46, 0x58, 0xc4, 0x1d, 0x2f, 0x6b, + 0xe6, 0x6c, 0xa7, 0x5f, 0x95, 0x0c, 0xbc, 0x60, 0x00, 0x3d, 0xa9, 0x0a, + 0xd6, 0x0a, 0x66, 0x59, 0xc0, 0x9b, 0x49, 0x5b, 0x4c, 0x73, 0xf5, 0x9e, + 0x6d, 0x38, 0xdd, 0x0f, 0x25, 0xe4, 0x35, 0x84, 0x34, 0x25, 0xfe, 0x71, + 0x35, 0x78, 0xa7, 0x5b, 0xc1, 0x7a, 0xab, 0xd7, 0xeb, 0x2f, 0x54, 0x93, + 0x94, 0x49, 0x8a, 0x1e, 0x04, 0xe6, 0xfc, 0xd7, 0xe3, 0xa2, 0x41, 0x25, + 0x5a, 0xa5, 0x46, 0x59, 0x85, 0xfb, 0x21, 0xc7, 0x02, 0x48, 0x79, 0xd4, + 0xef, 0xc4, 0x03, 0xc2, 0x0a, 0x4b, 0x42, 0x1c, 0x73, 0x35, 0xcd, 0x21, + 0x8b, 0xd5, 0xfc, 0xa3, 0xdc, 0xbb, 0x4b, 0xa3, 0x45, 0x04, 0x73, 0xa1, + 0xdb, 0x3a, 0x97, 0x0e, 0xc7, 0x1c, 0xe2, 0x67, 0x04, 0xd4, 0x49, 0x68, + 0x0e, 0x05, 0xcb, 0x52, 0xd4, 0x37, 0x75, 0xd8, 0x2a, 0x17, 0xd3, 0x7a, + 0x93, 0x96, 0x46, 0xfb, 0x07, 0x6d, 0x3b, 0x92, 0x60, 0xf4, 0x35, 0x94, + 0x3b, 0xbd, 0x2e, 0xf6, 0x0b, 0x18, 0xd5, 0x0d, 0x1b, 0xe1, 0xd3, 0x14, + 0xc1, 0x84, 0xd7, 0x67, 0xd7, 0x96, 0x2d, 0xa9, 0xab, 0x59, 0x70, 0x43, + 0x7b, 0xea, 0x25, 0xa3, 0x05, 0x1c, 0x45, 0xf6, 0x34, 0x51, 0x8e, 0xaf, + 0x46, 0x33, 0x90, 0x68, 0x28, 0x4f, 0x38, 0x5b, 0xbb, 0x69, 0xee, 0xbb, + 0x0a, 0x4c, 0x76, 0x1c, 0x3d, 0xfd, 0xea, 0x1f, 0x77, 0x9e, 0xd4, 0xa1, + 0xeb, 0x74, 0x16, 0x60, 0x20, 0xe9, 0x44, 0xc1, 0x90, 0x2c, 0x7b, 0x77, + 0x6f, 0x70, 0xe3, 0x62, 0x0f, 0xc3, 0x20, 0xf6, 0xce, 0xc3, 0xa6, 0x0e, + 0x9c, 0x6d, 0xa3, 0xa0, 0x21, 0x1c, 0x28, 0x7f, 0x44, 0xd7, 0xa9, 0x87, + 0x62, 0x91, 0x4d, 0x2a, 0x93, 0xe2, 0xc7, 0x94, 0x0c, 0x75, 0x1d, 0xf6, + 0xc7, 0xf8, 0x36, 0x09, 0xa8, 0x23, 0xa3, 0x80, 0x52, 0x2d, 0xe7, 0x0b, + 0x44, 0x5d, 0x4b, 0xf5, 0xdc, 0x57, 0xa3, 0x02, 0x40, 0x89, 0xdc, 0x40, + 0xf7, 0x5c, 0xad, 0xea, 0x5c, 0x1a, 0x59, 0xfc, 0xb8, 0xaf, 0xcb, 0x71, + 0xe0, 0x08, 0xdc, 0x80, 0x08, 0x8a, 0x32, 0x85, 0x46, 0xa9, 0x9a, 0x17, + 0x6b, 0x25, 0x9c, 0xfe, 0x7d, 0x90, 0x22, 0x6e, 0x7b, 0x01, 0x24, 0x17, + 0xf6, 0xa7, 0x70, 0x93, 0x03, 0x60, 0xc2, 0x0d, 0x7b, 0x3b, 0xe8, 0x5b, + 0x02, 0xb0, 0x6d, 0x00, 0x62, 0x97, 0x1b, 0x84, 0x86, 0x27, 0x72, 0x2d, + 0x90, 0xee, 0xdc, 0xb6, 0xb8, 0xa5, 0x58, 0x73, 0x29, 0x9b, 0x06, 0x99, + 0xda, 0x4f, 0x12, 0x0c, 0x74, 0x0a, 0xc1, 0x1b, 0x34, 0x20, 0xfa, 0x6d, + 0x01, 0xd2, 0x1b, 0xf2, 0x0f, 0xe3, 0xfe, 0x34, 0x2d, 0x44, 0x4f, 0xa3, + 0x6a, 0xab, 0xaa, 0x7e, 0x1c, 0x35, 0xef, 0xfe, 0xa0, 0xc1, 0x8a, 0xeb, + 0x77, 0x80, 0xd6, 0x57, 0x20, 0x2e, 0x2b, 0xeb, 0x67, 0xa0, 0x82, 0x86, + 0xc8, 0x0e, 0x70, 0x76, 0x74, 0x52, 0x3e, 0x67, 0x96, 0xf0, 0x48, 0x3f, + 0x9b, 0xdc, 0x5f, 0x36, 0xd9, 0xae, 0x3a, 0xcb, 0x57, 0x5d, 0xe0, 0x7c, + 0x03, 0xa9, 0xe8, 0x88, 0x13, 0x6a, 0x70, 0x94, 0x4b, 0xf5, 0x92, 0x8f, + 0xc0, 0x34, 0x49, 0x3f, 0xf7, 0xe1, 0x59, 0xc4, 0xf2, 0xae, 0x7a, 0x88, + 0x58, 0x39, 0x74, 0x39, 0x6d, 0xaf, 0x7a, 0xec, 0xaf, 0x44, 0x0e, 0x11, + 0x7d, 0xa8, 0x3c, 0x50, 0x5b, 0x64, 0x8d, 0x8a, 0x21, 0x59, 0xc6, 0x8c, + 0x6c, 0xce, 0x05, 0xad, 0x1c, 0x2f, 0x5e, 0x4a, 0xa3, 0x2a, 0x46, 0x3a, + 0xaa, 0x12, 0x7e, 0xcc, 0x82, 0xb6, 0x62, 0xba, 0xe6, 0x1a, 0x52, 0xc6, + 0xe3, 0x96, 0x71, 0xf6, 0x81, 0x21, 0x46, 0xd0, 0x3f, 0x5d, 0xa1, 0x37, + 0x8b, 0xf5, 0xc7, 0x8c, 0x28, 0xf0, 0x2e, 0xe8, 0x44, 0x25, 0x48, 0x27, + 0x8e, 0x2f, 0x65, 0x83, 0xed, 0xf5, 0xb6, 0x9f, 0x02, 0xa7, 0x1b, 0x1e, + 0x90, 0x01, 0x55, 0x88, 0xe5, 0xdf, 0x0e, 0x7e, 0x16, 0x66, 0xa1, 0xc6, + 0x07, 0xf6, 0xb5, 0x84, 0x8d, 0x60, 0x6b, 0xe2, 0xad, 0xbd, 0x18, 0x39, + 0xe5, 0xd2, 0xd9, 0xe0, 0xab, 0xc2, 0xac, 0x2f, 0x36, 0x24, 0x03, 0x69, + 0x4c, 0xf9, 0xf3, 0x67, 0x8f, 0xf6, 0x8b, 0xde, 0xf9, 0x7c, 0x14, 0xfa, + 0x97, 0xc3, 0xe5, 0xc1, 0x7d, 0xcf, 0x16, 0x24, 0x26, 0xda, 0xde, 0x5c, + 0x70, 0x96, 0x90, 0xd9, 0x06, 0x2f, 0xf9, 0x61, 0xa3, 0x47, 0x19, 0x50, + 0x5e, 0xe2, 0xb6, 0x74, 0x5e, 0x55, 0xe6, 0x89, 0xaa, 0xde, 0x19, 0x27, + 0x26, 0x47, 0x95, 0x7b, 0xf0, 0x09, 0x21, 0xa9, 0xf3, 0xf2, 0xf0, 0xbc, + 0x1a, 0xa2, 0x25, 0x77, 0x3f, 0x8a, 0x57, 0x20, 0xfc, 0x48, 0x45, 0xd8, + 0x8b, 0xcb, 0x33, 0x04, 0x10, 0x1d, 0xc6, 0x4b, 0x4c, 0xe4, 0x92, 0x1f, + 0xef, 0x27, 0x5e, 0xd5, 0xac, 0xab, 0xcc, 0x69, 0xbe, 0xd6, 0x35, 0x0e, + 0x0d, 0x96, 0x99, 0x3b, 0x67, 0x8d, 0x33, 0xa0, 0xe3, 0x16, 0xcc, 0x4a, + 0x29, 0x80, 0xc8, 0x47, 0xd1, 0x0c, 0xb1, 0xa0, 0xc1, 0xbe, 0xcc, 0x16, + 0xab, 0xf7, 0xee, 0x8a, 0x77, 0xef, 0xca, 0x08, 0x82, 0x0a, 0x9e, 0x11, + 0xcf, 0x3c, 0xbb, 0x1b, 0x44, 0x96, 0xd1, 0x5e, 0x65, 0xf9, 0xe7, 0xc7, + 0xa1, 0x94, 0x42, 0xa9, 0x0e, 0x36, 0x9a, 0x5b, 0x7f, 0xf0, 0x91, 0x95, + 0xeb, 0xd1, 0xb6, 0x1d, 0x18, 0x44, 0x93, 0xa4, 0xc1, 0x31, 0x97, 0x07, + 0x09, 0x9b, 0x50, 0xae, 0xf3, 0x74, 0x7f, 0xbe, 0x0d, 0xc2, 0xc3, 0x11, + 0x8f, 0xa1, 0xea, 0x1f, 0x4e, 0x84, 0x94, 0x18, 0x7e, 0x7c, 0xbd, 0xe6, + 0xc9, 0x78, 0x0e, 0x39, 0x1e, 0x1a, 0x71, 0xc4, 0xbc, 0x5c, 0x99, 0x76, + 0xf7, 0x26, 0x66, 0x9c, 0x8f, 0xd4, 0xad, 0xa9, 0x6e, 0x96, 0xb9, 0x54, + 0x5b, 0xae, 0xa2, 0x0d, 0x94, 0xa8, 0x5a, 0x34, 0xc3, 0xdb, 0x52, 0x59, + 0x3f, 0xdd, 0x53, 0x72, 0xfc, 0xf6, 0x1d, 0x3c, 0xe0, 0x1f, 0x4a, 0xee, + 0xf5, 0x74, 0xa5, 0x95, 0x7a, 0x5d, 0x75, 0xbd, 0x27, 0x4a, 0x49, 0x18, + 0xcf, 0xf0, 0xe5, 0x32, 0x4f, 0x1b, 0xa0, 0xeb, 0x00, 0x19, 0x21, 0xbd, + 0xf7, 0xf5, 0x4b, 0x47, 0x1d, 0x3b, 0x8b, 0xe6, 0xca, 0xdc, 0xb6, 0x52, + 0x41, 0xa7, 0xab, 0x68, 0xb3, 0xfb, 0x8f, 0x40, 0xc3, 0x59, 0xd9, 0x2d, + 0x13, 0x3a, 0x99, 0x93, 0x9f, 0xa6, 0x90, 0xdd, 0x65, 0x17, 0x6c, 0x6f, + 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x64, 0x6b, 0x75, 0x0d, 0x00, 0x00, 0x00, + 0x02, 0x07, 0x57, 0x00, 0x0c, 0xce, 0x07, 0x57, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8a, 0x74, 0x06, 0x23, 0x00, 0x07, 0x07, 0x09, 0x34, + 0x00, 0x09, 0x09, 0x09, 0x34, 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, + 0x08, 0x08, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x93, 0x7c, 0x17, 0x13, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd8, 0xc4, + 0xac, 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd8, 0xc4, 0xac, 0xdb, 0x80, 0x31, + 0x14, 0x76, 0xc0, 0x68, 0x81, 0x87, 0xa3, 0xfd, 0xf3, 0xa2, 0xd6, 0x51, + 0xa9, 0xbf, 0x9e, 0x90, 0x88, 0xfc, 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, + 0xb2, 0x23, 0xc4, 0x27, 0xcd, 0xff, 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, + 0x5c, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, + 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, + 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x08, 0xd8, 0x16, 0x86, 0x7c, 0x84, 0xb6, 0xc0, 0xb3, 0x50, + 0x2d, 0x2a, 0x95, 0x72, 0x8c, 0x1b, 0x64, 0xd9, 0xce, 0xbb, 0x9c, 0xc8, + 0xc6, 0x63, 0x5a, 0xd5, 0x38, 0x7c, 0x27, 0x74, 0xaa, 0x87, 0x88, 0x30, + 0xf3, 0x87, 0x6a, 0x7d, 0x11, 0xc7, 0x6a, 0xf8, 0x5a, 0x6c, 0xd9, 0xaf, + 0xae, 0xb7, 0x3e, 0x35, 0x89, 0x91, 0x11, 0xe7, 0x44, 0x9c, 0xc1, 0xa1, + 0x18, 0x0e, 0x78, 0x20, 0xfe, 0x4a, 0xf9, 0x47, 0x3a, 0xf4, 0x23, 0x28, + 0x3c, 0x45, 0xa2, 0x22, 0xe8, 0x63, 0x71, 0x92, 0xc8, 0xfd, 0x85, 0xf8, + 0x03, 0x28, 0x38, 0xb6, 0x09, 0x66, 0x5b, 0x56, 0xc8, 0xa6, 0x52, 0x03, + 0xea, 0xbf, 0xb5, 0x6f, 0xaf, 0x68, 0xdc, 0xb6, 0x9c, 0xa2, 0x16, 0xa5, + 0x33, 0x1a, 0xb7, 0x13, 0x15, 0x1d, 0x52, 0x29, 0x54, 0x51, 0xc4, 0x3e, + 0xa0, 0x03, 0xf9, 0x73, 0xa9, 0x3e, 0xf6, 0x45, 0xd8, 0xf2, 0x1e, 0xa9, + 0x40, 0x14, 0xc4, 0x5f, 0xbc, 0xce, 0x6f, 0xb5, 0xa2, 0x93, 0x7b, 0xf2, + 0x7c, 0xfa, 0xa5, 0x82, 0x97, 0x64, 0x77, 0x2e, 0x6d, 0x8f, 0x00, 0x71, + 0x64, 0xed, 0xc9, 0x51, 0x61, 0x69, 0x8f, 0x2a, 0xf4, 0x80, 0xd2, 0x24, + 0x6c, 0xc3, 0x53, 0x9f, 0xca, 0x72, 0x9d, 0x22, 0x54, 0x27, 0xd5, 0xba, + 0xae, 0x53, 0xb4, 0x7e, 0xae, 0xa9, 0xe1, 0x48, 0x67, 0xf5, 0x7b, 0xd7, + 0x7e, 0x36, 0x6f, 0xd1, 0xf8, 0x40, 0x8a, 0x9b, 0x07, 0x80, 0x2c, 0x17, + 0x6c, 0x42, 0x2f, 0x7b, 0x8b, 0x98, 0xc4, 0x20, 0xaf, 0x5b, 0x25, 0x73, + 0xb5, 0x5b, 0xa3, 0x4d, 0xe6, 0xeb, 0x66, 0x21, 0x91, 0x9d, 0x85, 0xa3, + 0x8b, 0xfa, 0x40, 0x2d, 0x0b, 0x20, 0x66, 0x47, 0x70, 0x83, 0xe3, 0x02, + 0x0f, 0xc2, 0x56, 0xd6, 0x49, 0x83, 0x3d, 0xad, 0x16, 0x1f, 0x55, 0x33, + 0xcf, 0x79, 0x6d, 0x8d, 0xb1, 0xf7, 0x5d, 0x08, 0x10, 0xd8, 0xe2, 0x0e, + 0xe7, 0xa1, 0x74, 0xdb, 0xef, 0x19, 0xc0, 0xe7, 0xf3, 0xb7, 0x73, 0xf8, + 0x4d, 0x78, 0x98, 0xf0, 0x64, 0xc3, 0xc5, 0x99, 0xb7, 0xf6, 0x07, 0xd4, + 0xae, 0x17, 0xe4, 0xee, 0xd9, 0x35, 0x53, 0xb6, 0x2d, 0xb5, 0xa0, 0xc4, + 0x50, 0x48, 0x3e, 0x16, 0x18, 0xea, 0x20, 0x34, 0x9c, 0xeb, 0xeb, 0xef, + 0xee, 0xb8, 0xf4, 0x32, 0xb1, 0xda, 0x32, 0x35, 0x4e, 0x47, 0x1a, 0x4e, + 0xad, 0x46, 0x53, 0xe6, 0xce, 0x22, 0x7e, 0xe3, 0xf3, 0xbc, 0x34, 0x77, + 0xb0, 0x53, 0x21, 0x81, 0x19, 0x42, 0xb7, 0x1d, 0x0d, 0x81, 0x0f, 0x29, + 0xea, 0x2f, 0x3d, 0xba, 0x40, 0x0c, 0xea, 0x2e, 0xaf, 0x20, 0x88, 0x96, + 0x88, 0xc2, 0xea, 0x3b, 0xec, 0x58, 0x4f, 0x16, 0x66, 0xec, 0x9c, 0xe3, + 0xc8, 0x77, 0x6b, 0xfe, 0xc5, 0xeb, 0x5f, 0xab, 0xbc, 0xc2, 0x6b, 0x03, + 0xdb, 0xbc, 0x0e, 0xd6, 0xd2, 0x8d, 0x3e, 0xd8, 0x63, 0xe7, 0x13, 0xa9, + 0xc3, 0x98, 0xfa, 0xf6, 0xbd, 0xe9, 0x53, 0x33, 0x83, 0x26, 0x2b, 0x78, + 0xa4, 0x91, 0xb5, 0x5b, 0x39, 0xcf, 0x1d, 0x26, 0xc4, 0x05, 0xbe, 0xeb, + 0x8b, 0xa4, 0xee, 0xcd, 0xe0, 0x76, 0xac, 0x41, 0xdf, 0x85, 0x05, 0x60, + 0xe3, 0xc2, 0x5e, 0x57, 0x73, 0x00, 0x48, 0xa2, 0x3f, 0x3c, 0xd2, 0x3c, + 0x78, 0x8e, 0x20, 0xa2, 0xbd, 0xc6, 0xb6, 0x09, 0xdb, 0xdd, 0xf5, 0x39, + 0x8b, 0x5f, 0x2d, 0x13, 0xb9, 0x18, 0x3c, 0x43, 0x55, 0xcc, 0xf6, 0x87, + 0x97, 0xbe, 0x82, 0x03, 0x18, 0xa2, 0xb0, 0xf5, 0x05, 0xec, 0xe3, 0x64, + 0x43, 0x67, 0xef, 0xf7, 0x3c, 0x23, 0xde, 0x2a, 0xa7, 0xff, 0xee, 0xc1, + 0x95, 0x3d, 0xc8, 0x99, 0xea, 0xb7, 0x73, 0x2a, 0x89, 0xc8, 0x1b, 0x2e, + 0x47, 0x25, 0xae, 0x2a, 0x40, 0x77, 0x87, 0x6d, 0xea, 0xa9, 0x71, 0x49, + 0xa0, 0x11, 0xe5, 0x89, 0x0e, 0xd8, 0x01, 0x10, 0xe2, 0x6f, 0xea, 0xb2, + 0xbf, 0x6d, 0x2b, 0x03, 0x92, 0x28, 0x2a, 0xe8, 0x21, 0x70, 0x55, 0x48, + 0xe5, 0x9f, 0xf4, 0xea, 0x37, 0x69, 0x22, 0xb9, 0x3f, 0x48, 0x06, 0xd1, + 0x97, 0x6e, 0x72, 0x13, 0x4b, 0x20, 0xb5, 0x55, 0x64, 0x5c, 0xfc, 0x0b, + 0xec, 0xf9, 0x6f, 0x0d, 0xfa, 0x2d, 0xa4, 0xf9, 0x6a, 0x98, 0x5f, 0xd2, + 0x17, 0x31, 0xbf, 0x86, 0xc4, 0xd8, 0x21, 0x0a, 0x51, 0x62, 0xf1, 0x30, + 0x72, 0xef, 0x39, 0xb5, 0x05, 0x6b, 0xc9, 0x15, 0x1f, 0xbd, 0xb5, 0xfc, + 0xe5, 0x0b, 0x35, 0x13, 0x9b, 0xc5, 0x48, 0x3e, 0xf1, 0x1f, 0x7a, 0x1d, + 0x7f, 0xcb, 0x61, 0xba, 0x58, 0xbb, 0x74, 0xc2, 0x1b, 0xd9, 0xc0, 0x45, + 0x45, 0xe9, 0xbf, 0x3b, 0x56, 0x14, 0x9c, 0xd7, 0xaa, 0xcd, 0x77, 0xc4, + 0x32, 0x6c, 0x7e, 0x5d, 0xc0, 0x1c, 0xde, 0xad, 0xbb, 0xe4, 0x46, 0xca, + 0x6c, 0x13, 0x08, 0x58, 0x07, 0xd6, 0xa7, 0xc5, 0xa1, 0x90, 0xc6, 0x93, + 0x4d, 0xbd, 0xc4, 0xd7, 0x75, 0x02, 0x16, 0x47, 0x38, 0x33, 0x92, 0x11, + 0xb9, 0x6a, 0x85, 0xc4, 0x97, 0x7d, 0xdc, 0x54, 0x31, 0x07, 0xf9, 0xcd, + 0xeb, 0x09, 0x85, 0xae, 0x14, 0x6d, 0x2c, 0xb0, 0xfa, 0xa3, 0x49, 0x26, + 0xb6, 0x98, 0x69, 0xb1, 0x85, 0x52, 0x02, 0x0d, 0x3a, 0x8d, 0x40, 0x3b, + 0x83, 0x05, 0x66, 0x5c, 0xe3, 0xb1, 0x51, 0xe4, 0xc9, 0x59, 0x74, 0x0a, + 0x8a, 0xbb, 0xcb, 0x95, 0xde, 0x81, 0xa4, 0x92, 0x09, 0x63, 0x9d, 0xef, + 0x27, 0xf4, 0xe1, 0x66, 0xf6, 0x4f, 0xe9, 0x6d, 0xce, 0x8d, 0xcb, 0x91, + 0x55, 0xd7, 0xf9, 0xba, 0x49, 0xf2, 0x27, 0x0c, 0x15, 0x68, 0x21, 0x42, + 0x2d, 0x69, 0xe2, 0x0d, 0xee, 0x69, 0x55, 0x68, 0xc3, 0xb5, 0x8d, 0xd7, + 0x37, 0x32, 0xda, 0x6f, 0x78, 0x2b, 0xc8, 0xf9, 0x30, 0x3b, 0xd1, 0xe5, + 0xa5, 0x4c, 0xcb, 0xfe, 0xeb, 0x6f, 0x5d, 0x3c, 0x99, 0xfb, 0x33, 0xc1, + 0x8e, 0xac, 0x48, 0x70, 0x8c, 0x30, 0x85, 0xe1, 0x30, 0x69, 0xde, 0x82, + 0x82, 0x18, 0xe2, 0xc5, 0x6b, 0xb7, 0x1d, 0xdb, 0xce, 0x09, 0x4d, 0x9a, + 0x8e, 0x93, 0x89, 0x46, 0x5f, 0x8c, 0xe9, 0xf5, 0x4c, 0xa1, 0x62, 0xd9, + 0x22, 0x4c, 0xad, 0xbe, 0x77, 0x5c, 0x4f, 0x34, 0xc0, 0x64, 0x23, 0x0d, + 0x9d, 0xed, 0x3e, 0x70, 0x9b, 0x5f, 0x65, 0x84, 0x98, 0x63, 0x1a, 0x0b, + 0xd9, 0x7c, 0xb0, 0x95, 0xee, 0x6a, 0x9a, 0x5c, 0xc3, 0x76, 0x7c, 0x18, + 0x75, 0xba, 0x86, 0xca, 0x43, 0xa5, 0xb5, 0xe1, 0x0b, 0x26, 0xc0, 0xfb, + 0xd6, 0x3a, 0x23, 0x9f, 0xfb, 0xba, 0x68, 0xa3, 0x9b, 0xc0, 0xe5, 0x21, + 0xe3, 0x77, 0x75, 0x84, 0x40, 0x1d, 0x9b, 0xc9, 0xf2, 0x25, 0x6c, 0xba, + 0x6c, 0x8c, 0xb2, 0x2e, 0xec, 0xce, 0x90, 0xb1, 0x4a, 0x90, 0x24, 0xf3, + 0x34, 0x9d, 0xc3, 0x62, 0xb2, 0x11, 0x02, 0xd1, 0xf5, 0x67, 0x95, 0x48, + 0x45, 0x04, 0xe1, 0xd4, 0xb3, 0xdd, 0x1e, 0x00, 0x35, 0x84, 0x7c, 0x41, + 0xea, 0xf9, 0x50, 0xd3, 0x82, 0x14, 0x7d, 0xe7, 0x72, 0xe2, 0xb4, 0x9e, + 0xfc, 0xe7, 0x2e, 0xf7, 0x06, 0xb4, 0x29, 0xfe, 0x7e, 0x72, 0x6a, 0xe1, + 0xde, 0xa8, 0xfa, 0xd9, 0xde, 0xf4, 0xdd, 0xce, 0xff, 0xdb, 0xdc, 0x09, + 0x31, 0x14, 0x1d, 0x09, 0x53, 0xb5, 0x3f, 0x2c, 0x66, 0x74, 0xa8, 0x66, + 0xaa, 0xa2, 0x3d, 0x32, 0x61, 0xed, 0x43, 0xa5, 0x69, 0xf8, 0x6b, 0x0d, + 0x16, 0xe4, 0x67, 0xf5, 0x62, 0xaa, 0x76, 0xac, 0x01, 0x3f, 0x5f, 0x44, + 0x29, 0x34, 0x95, 0x0c, 0x1a, 0x07, 0x96, 0x6b, 0xf4, 0x60, 0x96, 0x5b, + 0xe2, 0x53, 0x2a, 0x87, 0x02, 0xc6, 0xf4, 0x01, 0xf3, 0x7a, 0xdb, 0x82, + 0x5f, 0xc3, 0x85, 0xd4, 0x1a, 0x9b, 0x63, 0xc4, 0x60, 0xb7, 0x82, 0x3c, + 0x9c, 0x70, 0x6f, 0x62, 0x72, 0x10, 0x13, 0xe2, 0xf5, 0x7b, 0x06, 0x41, + 0x48, 0xc7, 0x63, 0xa0, 0xb9, 0xde, 0x56, 0x96, 0x0f, 0x0d, 0x67, 0xd9, + 0x0e, 0x8a, 0x94, 0x3f, 0xca, 0x2f, 0x94, 0x19, 0xff, 0x47, 0xad, 0x59, + 0x3b, 0x9b, 0xb4, 0xc5, 0x4b, 0x51, 0x0d, 0x18, 0x74, 0xc9, 0x53, 0x34, + 0xf0, 0x6c, 0x58, 0x51, 0xbe, 0x4b, 0xfe, 0x24, 0x37, 0xd2, 0x0b, 0x4d, + 0xfa, 0x54, 0xfd, 0x92, 0xc4, 0x25, 0xb3, 0xe8, 0xe2, 0xb5, 0xda, 0xd1, + 0xd1, 0x44, 0x82, 0xb9, 0x2b, 0xb7, 0x03, 0xd9, 0xca, 0x78, 0x71, 0x9c, + 0xc6, 0x8f, 0xb6, 0x59, 0x37, 0xbd, 0x15, 0x02, 0x5e, 0xfb, 0xf5, 0x8c, + 0x7c, 0x46, 0x8e, 0xe2, 0xc8, 0xed, 0xf9, 0x96, 0xdb, 0xa8, 0xbe, 0xe5, + 0x09, 0x70, 0x3f, 0xf4, 0xfb, 0xbf, 0xf4, 0xf5, 0xe1, 0xd4, 0x5e, 0xda, + 0x60, 0x8f, 0x9d, 0xff, 0x94, 0x00, 0xa2, 0xe6, 0x40, 0xd2, 0x47, 0xdb, + 0x2d, 0x0e, 0x82, 0x7c, 0x7f, 0xab, 0x94, 0x2b, 0xc2, 0x6b, 0x46, 0x4d, + 0x55, 0x44, 0x7b, 0xb9, 0x2e, 0x68, 0x89, 0xbb, 0xc0, 0x69, 0x44, 0x77, + 0xa1, 0x41, 0xf8, 0x3b, 0x3f, 0xe5, 0xfb, 0x3c, 0x12, 0x0f, 0x59, 0x78, + 0x6a, 0x52, 0x6e, 0xe1, 0x2a, 0xf7, 0xab, 0xcd, 0xc8, 0xb2, 0x5d, 0x8d, + 0x1c, 0xf6, 0x24, 0xae, 0xb3, 0xda, 0x8a, 0xa7, 0x75, 0x3b, 0x58, 0x77, + 0x08, 0x72, 0xa9, 0x06, 0x0c, 0x7e, 0x4d, 0xad, 0x52, 0x42, 0xc5, 0x9d, + 0x32, 0x10, 0x49, 0xbb, 0xe1, 0x32, 0xc6, 0xb6, 0x2a, 0x68, 0xd3, 0x8d, + 0xba, 0x9e, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, 0x86, 0x2f, + 0x05, 0x23, 0x00, 0x07, 0x07, 0x08, 0x34, 0x00, 0x09, 0x09, 0x09, 0x34, + 0x34, 0x08, 0x01, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x09, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x8a, 0x72, 0x17, 0x13, + 0x41, 0xb7, 0x59, 0x5c, 0x83, 0xd3, 0xa8, 0x82, 0x41, 0xb7, 0x59, 0x5c, + 0x83, 0xd3, 0xa8, 0x82, 0xdb, 0x80, 0x31, 0x14, 0x76, 0xc0, 0x68, 0x81, + 0x87, 0xa3, 0xfd, 0xf3, 0xa2, 0xd6, 0x51, 0xa9, 0xbf, 0x9e, 0x90, 0x88, + 0xfc, 0x9b, 0xff, 0x1a, 0xfd, 0x18, 0x88, 0xb2, 0x23, 0xc4, 0x27, 0xcd, + 0xff, 0x6d, 0xed, 0x99, 0xdb, 0x40, 0x1d, 0x5c, 0xda, 0x39, 0xa3, 0xee, + 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09, 0x2a, 0x05, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0xe1, 0x14, + 0x34, 0xc4, 0xb0, 0x8c, 0x51, 0x96, 0xb8, 0x94, 0xef, 0xe7, 0xf0, 0x5b, + 0x0e, 0x91, 0xf7, 0x07, 0x87, 0x90, 0x3f, 0x8d, 0x5f, 0xf6, 0x59, 0x69, + 0x11, 0x87, 0xdb, 0xaa, 0xdb, 0x60, 0x19, 0xe3, 0x42, 0xdd, 0xd2, 0x2e, + 0xbf, 0xc3, 0x0d, 0x32, 0x66, 0x01, 0xb9, 0xde, 0xce, 0xb5, 0x23, 0xa4, + 0x8e, 0x40, 0x6f, 0xe6, 0xa9, 0xea, 0xc6, 0x1e, 0x64, 0xc9, 0x57, 0x83, + 0x42, 0x36, 0x52, 0x9b, 0xa5, 0x29, 0x32, 0x5f, 0xe9, 0xc2, 0xe3, 0x2d, + 0x5b, 0x00, 0x7b, 0x3e, 0xad, 0xd4, 0x78, 0x7f, 0xfa, 0x02, 0x30, 0xb0, + 0x02, 0xfd, 0xd2, 0xbc, 0xa5, 0xe8, 0x0b, 0x4f, 0x96, 0x16, 0x79, 0x43, + 0x1a, 0xc1, 0x6d, 0xb5, 0xcf, 0x11, 0x35, 0x58, 0x61, 0x08, 0x64, 0x23, + 0xa3, 0x07, 0x76, 0xdb, 0x4d, 0x7d, 0x0e, 0xe0, 0x43, 0x7d, 0xc9, 0x3d, + 0x5e, 0xf4, 0x05, 0x0d, 0xb2, 0xbe, 0x23, 0x13, 0x19, 0x5f, 0x2a, 0xe9, + 0x10, 0xe7, 0x69, 0xed, 0x95, 0x7b, 0x66, 0xb3, 0xe5, 0xa5, 0x8b, 0x6f, + 0xe7, 0xa8, 0x2c, 0xab, 0xed, 0xd1, 0x12, 0xcf, 0xfb, 0xc7, 0x9a, 0xa5, + 0xf0, 0xe9, 0x2a, 0x98, 0x38, 0x96, 0x6a, 0xbb, 0x8d, 0xf2, 0xbf, 0x08, + 0x7f, 0xa7, 0x52, 0xd6, 0x12, 0x3b, 0x00, 0x47, 0xfe, 0xf3, 0x35, 0x63, + 0xf8, 0xc0, 0xec, 0xcf, 0x47, 0x72, 0x45, 0x81, 0x77, 0x4f, 0x23, 0x89, + 0x57, 0x15, 0x3c, 0xd7, 0xf9, 0x51, 0x14, 0xbd, 0x2a, 0x3d, 0xf4, 0x3d, + 0x83, 0xc1, 0xd0, 0x58, 0x07, 0x65, 0x5e, 0xe9, 0x23, 0x9a, 0xb9, 0x76, + 0xd1, 0xe1, 0x5f, 0xfd, 0x7c, 0xfe, 0x31, 0xad, 0xcd, 0xd6, 0x03, 0xb9, + 0x37, 0xe0, 0xae, 0x49, 0x85, 0x6b, 0x3c, 0x03, 0x97, 0x29, 0x99, 0x7c, + 0x1d, 0x36, 0x1a, 0xdd, 0xda, 0x47, 0xa1, 0x38, 0x21, 0xfa, 0x91, 0x4a, + 0x8d, 0xe7, 0x26, 0x9d, 0xaa, 0x44, 0xf7, 0x91, 0x25, 0xca, 0xa8, 0x84, + 0x77, 0x58, 0x2a, 0x50, 0xd6, 0xa4, 0xab, 0x69, 0xd3, 0xd4, 0xac, 0x1e, + 0x08, 0xfc, 0xa2, 0xbd, 0xab, 0x27, 0x72, 0xa4, 0x5a, 0x40, 0x76, 0x15, + 0x24, 0x0e, 0x50, 0x5a, 0x6f, 0x5d, 0x00, 0x75, 0x6c, 0x75, 0x75, 0xbb, + 0x13, 0x85, 0x0e, 0xcf, 0x27, 0x28, 0x94, 0x41, 0x64, 0xf0, 0x76, 0x97, + 0xbb, 0x58, 0x20, 0x12, 0x46, 0xa9, 0xf5, 0x23, 0xc2, 0x6b, 0xf6, 0x9b, + 0xd1, 0x20, 0xc5, 0x98, 0xa5, 0xdb, 0x77, 0xd9, 0x2a, 0xe7, 0xd8, 0x06, + 0xfc, 0x5d, 0xca, 0x85, 0xd8, 0x6e, 0x44, 0xf0, 0x4a, 0x32, 0x37, 0x66, + 0xbf, 0xde, 0x0a, 0x4c, 0xd8, 0xd8, 0xeb, 0x96, 0x0f, 0x6a, 0x37, 0x16, + 0x09, 0x63, 0x48, 0x8d, 0x31, 0xe8, 0x7c, 0xa6, 0x5b, 0xf0, 0xd3, 0x51, + 0xad, 0x5b, 0x12, 0xd5, 0x42, 0x86, 0xbd, 0x46, 0x7c, 0x62, 0x9c, 0x92, + 0x10, 0xeb, 0xdd, 0x5f, 0xc4, 0x16, 0xcc, 0x2d, 0xe1, 0xce, 0x42, 0xb0, + 0x80, 0x26, 0xcf, 0x49, 0x11, 0x0e, 0x4b, 0xe3, 0x63, 0xb4, 0x6f, 0x84, + 0x9b, 0x4d, 0xaf, 0x67, 0x56, 0x5f, 0x51, 0xff, 0xc9, 0xbd, 0xd5, 0xe4, + 0x7d, 0x96, 0x2c, 0x64, 0xe8, 0xa2, 0x42, 0x95, 0x2f, 0xf9, 0xb3, 0xa5, + 0x3c, 0xb2, 0x33, 0xa9, 0x4a, 0x03, 0xfe, 0x2c, 0x56, 0x00, 0xaa, 0xc6, + 0x5b, 0xea, 0x89, 0x0e, 0xa7, 0xae, 0xa0, 0x92, 0x7c, 0x04, 0xe5, 0x91, + 0xf4, 0x91, 0x8e, 0x77, 0xc0, 0x74, 0xd9, 0x85, 0xd6, 0x4f, 0x13, 0x11, + 0xc4, 0xd7, 0xeb, 0xd6, 0xfa, 0xbd, 0x70, 0x09, 0xb2, 0xa5, 0x77, 0x8d, + 0xbe, 0x23, 0x0b, 0xb3, 0x4c, 0xd6, 0x2f, 0xd0, 0x37, 0x62, 0x60, 0x88, + 0xd1, 0xbd, 0xec, 0x1c, 0x98, 0xbb, 0xd4, 0x9b, 0xa8, 0x50, 0x1e, 0xa4, + 0xb3, 0xe1, 0x1f, 0xe2, 0x49, 0x5b, 0x09, 0xc8, 0x3c, 0xb4, 0x38, 0xaf, + 0x5c, 0xec, 0xf8, 0x5d, 0xa1, 0xe1, 0xbf, 0xad, 0x5a, 0x33, 0xc8, 0x65, + 0x6a, 0x21, 0x10, 0x94, 0x70, 0x5c, 0x16, 0xd2, 0x5a, 0xfd, 0x52, 0x13, + 0xb8, 0xb7, 0xdb, 0xc2, 0x26, 0x7f, 0x24, 0xb2, 0xc3, 0x19, 0x19, 0x7c, + 0x7c, 0x5e, 0x70, 0x8a, 0x99, 0x74, 0x27, 0x3e, 0x5a, 0xb3, 0x17, 0x10, + 0xd8, 0x8a, 0x3e, 0xc2, 0x7e, 0x99, 0x67, 0x74, 0xe3, 0x65, 0x32, 0x18, + 0x90, 0x66, 0x7f, 0xe1, 0x74, 0x7d, 0xe7, 0xb8, 0xd1, 0xe2, 0xd3, 0x29, + 0xf1, 0xf2, 0x5d, 0xf1, 0x05, 0xca, 0x11, 0x7b, 0xf7, 0x32, 0xdf, 0x68, + 0x37, 0x84, 0xce, 0x00, 0x16, 0x5f, 0x9d, 0x9a, 0x5e, 0x04, 0xe0, 0xb1, + 0xa8, 0x39, 0x08, 0xfe, 0x75, 0xcc, 0x6b, 0x7c, 0x99, 0x28, 0x8d, 0x4c, + 0x50, 0x81, 0x0a, 0x4a, 0xba, 0x72, 0xbe, 0x90, 0x96, 0xcc, 0xac, 0x36, + 0x11, 0x5e, 0x9f, 0xe3, 0xc8, 0x97, 0x8b, 0x86, 0x87, 0x05, 0x68, 0x59, + 0x4d, 0xfa, 0xf7, 0xb8, 0x83, 0x0b, 0x42, 0xbd, 0xba, 0x63, 0x64, 0x3f, + 0xd6, 0xba, 0x66, 0x65, 0xbb, 0x1c, 0x69, 0x5d, 0xab, 0x22, 0x73, 0xd9, + 0xbc, 0x86, 0x0d, 0x06, 0x69, 0x63, 0x68, 0x61, 0x74, 0x64, 0x6b, 0x75, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x35, 0x1d, 0x3e, 0x1d, 0x24, 0xd4, 0x92, + 0xad, 0x2d, 0xbe, 0xf7, 0x22, 0xa4, 0x69, 0xce, 0x73, 0xef, 0xfc, 0x8d, + 0xfa, 0x05, 0xac, 0xfe, 0xf0, 0xa4, 0xe5, 0xb1, 0x82, 0x82, 0x42, 0xbd, + 0xaf, 0xba, 0xb2, 0x56, 0xf3, 0x3f, 0x14, 0x2c, 0xc6, 0xf5, 0x78, 0xb1, + 0x7f, 0x9e, 0xa5, 0xfb, 0x83, 0x3c, 0x1a, 0xdf, 0x4f, 0x79, 0x59, 0x61, + 0xed, 0xa5, 0x9a, 0x9b, 0x35, 0x8e, 0x10, 0x15, 0xb2, 0x49, 0x4d, 0x07, + 0x88, 0x4f, 0xc6, 0xb2, 0x3e, 0xca, 0x64, 0xae, 0xa3, 0x70, 0x5b, 0x2b, + 0xad, 0x74, 0x05, 0x2b, 0xc7, 0xcb, 0xff, 0x0e, 0x65, 0x85, 0xcc, 0xf3, + 0x4c, 0x85, 0x59, 0xa8, 0x34, 0x86, 0x92, 0xa5, 0xef, 0x3c, 0xdd, 0x52, + 0x13, 0x96, 0x52, 0x18, 0x3b, 0xd2, 0xaf, 0xab, 0x00, 0x17, 0x32, 0x82, + 0x71, 0xee, 0x90, 0x05, 0x81, 0x57, 0x52, 0x4f, 0x24, 0xff, 0xb3, 0xe6, + 0x3b, 0x94, 0xa3, 0x90, 0x7f, 0xd0, 0x26, 0xb0, 0x8b, 0x3e, 0xad, 0x36, + 0x5f, 0xb7, 0x28, 0x67, 0xac, 0xed, 0x35, 0xce, 0x51, 0xee, 0x78, 0xd5, + 0x99, 0x36, 0xea, 0x49, 0x22, 0x60, 0xc0, 0x75, 0x30, 0x7e, 0x96, 0x9d, + 0x60, 0x6e, 0x6a, 0xfb, 0x82, 0xb7, 0xa6, 0x41, 0xdf, 0x0c, 0x36, 0x9d, + 0xd2, 0xf7, 0xb7, 0xd1, 0x89, 0x95, 0x07, 0xac, 0x41, 0xa4, 0x60, 0x0a, + 0x6e, 0x4f, 0x41, 0xc3, 0x26, 0xed, 0xa0, 0x48, 0x91, 0xdd, 0xff, 0xc2, + 0xe9, 0x65, 0x2f, 0x76, 0x53, 0x05, 0xc3, 0x6f, 0x6a, 0x51, 0x27, 0xf8, + 0x55, 0xdf, 0xd7, 0xc3, 0x13, 0x25, 0x2d, 0x6b, 0xf1, 0x99, 0xd2, 0xda, + 0x9a, 0xed, 0x6d, 0x4f, 0xd0, 0x40, 0x73, 0xc2, 0x35, 0xeb, 0x8d, 0xa7, + 0x0f, 0x78, 0xc7, 0x43, 0x04, 0x53, 0x8d, 0x20, 0x6d, 0xb4, 0xd1, 0x18, + 0xf8, 0xd9, 0x5e, 0x92, 0x98, 0x0a, 0xa1, 0x16, 0xe8, 0x9f, 0x5a, 0x2a, + 0x2a, 0x89, 0x50, 0xda, 0xa3, 0xd6, 0xb1, 0xea, 0x50, 0x0c, 0x84, 0x7a, + 0xd9, 0xd8, 0x10, 0x75, 0x9d, 0x04, 0x3e, 0x4a, 0x5a, 0x8d, 0x9f, 0xf4, + 0xf9, 0xc4, 0x11, 0x6b, 0x76, 0x80, 0xf0, 0x56, 0x28, 0x13, 0xe3, 0x05, + 0x6b, 0x78, 0x23, 0x79, 0x88, 0x16, 0x51, 0x0c, 0x9b, 0xde, 0x4e, 0x90, + 0xd0, 0x2c, 0x53, 0x1c, 0x70, 0x41, 0xe7, 0xad, 0x73, 0xa3, 0xed, 0xc2, + 0x91, 0xc2, 0xb3, 0x3e, 0x99, 0xf2, 0x57, 0xf9, 0x7d, 0xc7, 0xc9, 0xe5, + 0x3e, 0xe2, 0x0b, 0x4b, 0xb6, 0xee, 0x29, 0x5b, 0xc9, 0xc5, 0xa6, 0x70, + 0x77, 0xe5, 0xbc, 0x43, 0x9e, 0xa2, 0x01, 0x22, 0x32, 0xb5, 0xdd, 0x1f, + 0x35, 0xd5, 0x3c, 0xdc, 0x7a, 0x4e, 0x85, 0x5f, 0xe2, 0x8f, 0x48, 0x28, + 0x70, 0x46, 0x89, 0x38, 0x5f, 0x72, 0x00, 0x65, 0x96, 0xfd, 0xc4, 0x36, + 0x01, 0xd6, 0x64, 0x70, 0xcc, 0xda, 0xd0, 0xc1, 0xee, 0x5b, 0x5a, 0xde, + 0x27, 0x1e, 0x35, 0xda, 0xae, 0x3c, 0xaf, 0xd3, 0x1c, 0x1a, 0x57, 0x24, + 0x0a, 0xf0, 0x79, 0xf0, 0xc1, 0xd7, 0x04, 0xcb, 0x21, 0xb2, 0xf4, 0x1e, + 0x1a, 0xa8, 0xc7, 0x89, 0xca, 0x1e, 0x68, 0x55, 0x71, 0x96, 0x68, 0x16, + 0x19, 0xb9, 0x9c, 0x96, 0xfa, 0xab, 0x34, 0xbb, 0xe0, 0x21, 0xb1, 0xae, + 0xb5, 0x8d, 0xf2, 0xd6, 0xce, 0x69, 0xc4, 0x58, 0x3f, 0x3c, 0xec, 0x28, + 0xcd, 0x9f, 0xfa, 0x97, 0xb3, 0xb0, 0xa4, 0x80, 0x7b, 0x07, 0x51, 0x0b, + 0x01, 0x23, 0x09, 0xcc, 0x7d, 0x94, 0x5d, 0xb4, 0xe9, 0x81, 0x5c, 0x3a, + 0x6b, 0xc4, 0x52, 0xc1, 0x86, 0xcc, 0xdf, 0x24, 0xcb, 0x3e, 0xbe, 0xc7, + 0xeb, 0xd7, 0xe0, 0x3a, 0xfc, 0xa1, 0x4d, 0x17, 0x8b, 0x41, 0x82, 0xeb, + 0x79, 0x2b, 0x87, 0x4d, 0xea, 0x27, 0xfb, 0x9e, 0x03, 0x75, 0xfc, 0x29, + 0x05, 0x4e, 0x76, 0xf3, 0x0f, 0x6d, 0xf2, 0x0f, 0xf6, 0x33, 0x58, 0x58, + 0xce, 0x67, 0xe7, 0x18, 0x97, 0x3a, 0x21, 0x4c, 0xaf, 0x64, 0x55, 0xd9, + 0x84, 0x53, 0xfd, 0x8b, 0x84, 0xad, 0x1a, 0xa5, 0x1c, 0x22, 0xac, 0xa5, + 0x21, 0xfb, 0xa2, 0x26, 0x69, 0x85, 0x24, 0xa3, 0x50, 0x24, 0x62, 0xe2, + 0xf8, 0x6c, 0x45, 0x97, 0xf6, 0xca, 0xe3, 0xbb, 0xb3, 0x02, 0x73, 0x7d, + 0x8b, 0x86, 0x69, 0xe6, 0x3a, 0x0c, 0x38, 0xa1, 0x85, 0xf5, 0xc8, 0xe6, + 0xbf, 0xce, 0x67, 0xeb, 0x68, 0xea, 0xe1, 0x05, 0x28, 0x48, 0xa6, 0xd5, + 0x2a, 0x35, 0xb5, 0x81, 0xaf, 0x3c, 0x47, 0xbb, 0x10, 0x4a, 0xc1, 0x29, + 0x9b, 0xa3, 0x16, 0x2b, 0x34, 0x18, 0x44, 0x2a, 0x1d, 0x43, 0x57, 0x1b, + 0x14, 0xea, 0x25, 0xbf, 0x1c, 0x95, 0x3e, 0x1e, 0x0d, 0x65, 0x50, 0x5a, + 0xe1, 0xd7, 0x14, 0x3f, 0xbb, 0xe2, 0xdd, 0x6f, 0x53, 0x5f, 0xd3, 0xc2, + 0x68, 0xa6, 0x14, 0xb2, 0x70, 0x36, 0x60, 0x99, 0x9d, 0x12, 0x9f, 0xee, + 0xcd, 0x99, 0x50, 0xbd, 0x41, 0x6f, 0x1b, 0xd4, 0x0d, 0x3b, 0xde, 0x00, + 0x20, 0xfd, 0x4c, 0x49, 0x80, 0x2e, 0x99, 0x4e, 0x23, 0xa8, 0x50, 0x14, + 0x42, 0x80, 0xb1, 0x4b, 0xe1, 0x97, 0x01, 0x1f, 0x8f, 0xf8, 0x05, 0x15, + 0xe6, 0x0e, 0x92, 0xdb, 0x10, 0xa2, 0x24, 0xf7, 0x4f, 0xc2, 0xf2, 0xe5, + 0xd8, 0xbc, 0xcc, 0x43, 0x10, 0xa0, 0x94, 0xff, 0x75, 0xee, 0xc2, 0x35, + 0x62, 0x2d, 0x9c, 0xe1, 0xd0, 0x0c, 0x02, 0x5b, 0xf0, 0x78, 0x32, 0xfe, + 0xf2, 0xf8, 0xdf, 0xd6, 0x7a, 0xdc, 0xc5, 0x82, 0xcd, 0xd4, 0x46, 0xd4, + 0x80, 0x99, 0xd6, 0x68, 0xb0, 0x60, 0xb2, 0x27, 0xdf, 0xbb, 0x41, 0x7f, + 0x49, 0x53, 0x93, 0x25, 0x05, 0x9a, 0xce, 0xc0, 0xd6, 0xc6, 0x46, 0xff, + 0xd7, 0xaa, 0x2d, 0xfa, 0x6b, 0x45, 0x09, 0xb0, 0xd2, 0x35, 0xfa, 0x8a, + 0xb4, 0xbb, 0xc2, 0x76, 0xe9, 0xd1, 0x91, 0x18, 0xde, 0x65, 0xd7, 0x81, + 0xa5, 0xbd, 0xd8, 0xf9, 0x89, 0xc6, 0x6f, 0xd9, 0xd3, 0xe4, 0x03, 0x4f, + 0x83, 0xf2, 0xd4, 0xd7, 0x41, 0x74, 0x5e, 0xe3, 0xcc, 0x8b, 0xf2, 0x22, + 0xb3, 0x89, 0xbc, 0xd5, 0x42, 0x43, 0x06, 0x76, 0xee, 0x0e, 0x79, 0x05, + 0xbd, 0xb2, 0x1e, 0xf6, 0x76, 0x12, 0x30, 0x2b, 0xd1, 0x9c, 0xe0, 0xd4, + 0xc9, 0x44, 0x09, 0x0a, 0xed, 0xae, 0x16, 0xdc, 0x9a, 0x26, 0xf4, 0xbb, + 0x37, 0xec, 0xc8, 0xa3, 0x7b, 0x12, 0x09, 0xcf, 0x17, 0x5c, 0x17, 0x74, + 0x0a, 0xa7, 0x71, 0x7c, 0xb0, 0x88, 0x15, 0xac, 0x98, 0xea, 0xfb, 0x3d, + 0x73, 0x3b, 0x46, 0xe9, 0xb0, 0x29, 0x73, 0xac, 0xe9, 0xdd, 0x1d, 0x8e, + 0xff, 0x79, 0xb9, 0x87, 0xf6, 0x07, 0x24, 0x49, 0xbf, 0xf6, 0x97, 0x71, + 0xbc, 0x5d, 0x14, 0x3f, 0x0f, 0x81, 0x6f, 0xcb, 0x49, 0x09, 0x51, 0x9e, + 0x4f, 0x24, 0x19, 0x7a, 0x00, 0x22, 0x9a, 0xa0, 0x52, 0xe3, 0x5b, 0x4a, + 0x9d, 0xe5, 0xb0, 0x96, 0xfc, 0x40, 0x15, 0xeb, 0x48, 0x1c, 0x4f, 0x25, + 0x64, 0xe9, 0x79, 0xbf, 0xb5, 0xef, 0x5f, 0xc3, 0x29, 0xbe, 0x7c, 0x6e, + 0x14, 0xe5, 0xe4, 0x36, 0xeb, 0x66, 0x27, 0x07, 0xbc, 0x2d, 0x1c, 0x2e, + 0x71, 0x51, 0x67, 0x60, 0x4d, 0xfc, 0x6c, 0x74, 0x8f, 0xc7, 0x84, 0x3e, + 0xe3, 0x8a, 0xfb, 0x34, 0xe3, 0x8e, 0x84, 0x5c, 0xdd, 0xc9, 0x0c, 0x3a, + 0xf4, 0x8c, 0xac, 0x40, 0xb0, 0x6b, 0x08, 0xe7, 0x4e, 0xa3, 0x92, 0xe3, + 0x57, 0xfc, 0x25, 0x08, 0x82, 0xd5, 0xf6, 0x35, 0x35, 0x41, 0x6a, 0xd9, + 0xf6, 0x78, 0x81, 0xca, 0x81, 0xe7, 0x5b, 0x58, 0x15, 0x5c, 0x57, 0x6e, + 0x5e, 0xe1, 0x65, 0xe5, 0xfc, 0xb1, 0xe9, 0x1a, 0x97, 0x9d, 0x86, 0xb9, + 0xb1, 0xa1, 0xb0, 0xbd, 0x3e, 0xb8, 0x0d, 0xc6, 0x33, 0x7e, 0xb5, 0x47, + 0xcc, 0x0a, 0x29, 0xcb, 0xf9, 0xaa, 0xff, 0x14, 0x33, 0x01, 0xd0, 0x3d, + 0x12, 0xb6, 0xc9, 0x33, 0x5d, 0xa8, 0x99, 0x30, 0x38, 0x38, 0xe3, 0x35, + 0x5a, 0x36, 0xf9, 0xca, 0xaf, 0x1d, 0xfe, 0x8c, 0x6a, 0xb7, 0xce, 0x67, + 0x0c, 0x6d, 0xc2, 0x29, 0xcd, 0x9e, 0x32, 0x46, 0xe8, 0xf4, 0x23, 0xa3, + 0xf3, 0xff, 0xf5, 0x74, 0xa6, 0xeb, 0xbd, 0xc3, 0x3e, 0xe2, 0x14, 0xd9, + 0xa5, 0xe8, 0x0e, 0xf6, 0x6f, 0xbd, 0xc3, 0x08, 0x56, 0x0a, 0xf0, 0x8a, + 0x14, 0xa1, 0xd6, 0x2d, 0xaf, 0xf7, 0x03, 0xff, 0xdc, 0x1c, 0x85, 0xdb, + 0xc9, 0x10, 0x33, 0xa2, 0x8d, 0x46, 0x69, 0x51, 0x70, 0x59, 0xc9, 0x4d, + 0x38, 0xb2, 0x69, 0x0e, 0xa8, 0xf4, 0xef, 0xdf, 0xb6, 0x34, 0xcf, 0x3d, + 0xec, 0xe8, 0x37, 0xea, 0xb3, 0x8e, 0x70, 0xb6, 0xf8, 0x5a, 0xa5, 0x13, + 0xde, 0x4c, 0x18, 0x6d, 0x04, 0xc5, 0xfd, 0xa4, 0x28, 0x15, 0x1b, 0x49, + 0xb3, 0x39, 0xfe, 0x9b, 0x54, 0xc1, 0x1e, 0x7f, 0x86, 0xe8, 0x3c, 0xe7, + 0xd5, 0x55, 0xa8, 0x89, 0xe1, 0xf4, 0xb5, 0x94, 0x0b, 0xff, 0xa8, 0xc2, + 0x56, 0xaa, 0xba, 0x6d, 0xb9, 0xc7, 0x54, 0xea, 0xbb, 0x1a, 0x17, 0x2a, + 0x3e, 0xae, 0x10, 0x2b, 0x89, 0xa8, 0x5d, 0xb1, 0x13, 0x46, 0xb1, 0x1c, + 0x6c, 0x7c, 0x58, 0x27, 0xc6, 0xf8, 0xfb, 0x9b, 0xca, 0x6b, 0x12, 0xd4, + 0x14, 0xbf, 0x3b, 0xb8, 0xea, 0xa7, 0xfa, 0x76, 0x55, 0x16, 0x0b, 0x2c, + 0xbb, 0x94, 0xd1, 0x12, 0x47, 0x0f, 0x3f, 0x89, 0xf4, 0xc2, 0xc3, 0x8d, + 0x03, 0x11, 0x0c, 0xe8, 0xe3, 0x96, 0x8f, 0x89, 0x25, 0x90, 0xa5, 0xe1, + 0xf4, 0x20, 0xf4, 0xfc, 0x24, 0xfe, 0xf0, 0x28, 0x11, 0x2a, 0x74, 0x10, + 0x9e, 0x20, 0x79, 0x11, 0xd4, 0x8b, 0x4b, 0x26, 0x75, 0x4f, 0x82, 0xd8, + 0x17, 0x64, 0xdf, 0x21, 0x73, 0x85, 0xa7, 0x57, 0x35, 0x8d, 0x67, 0x37, + 0x4a, 0x9a, 0xfe, 0x87, 0xa7, 0x45, 0x87, 0x51, 0xf3, 0x19, 0x3b, 0x1a, + 0xd4, 0x39, 0x37, 0x45, 0x99, 0xe9, 0x71, 0x96, 0x8b, 0x3e, 0xd8, 0xa6, + 0x8e, 0xc7, 0xf5, 0x62, 0x14, 0x1c, 0x8c, 0x4c, 0xfa, 0x60, 0x48, 0x35, + 0xb1, 0xba, 0xcd, 0xf5, 0xba, 0xf5, 0x67, 0xb6, 0xa2, 0x38, 0xf9, 0xd2, + 0xa3, 0xde, 0xbc, 0xfb, 0x58, 0xb2, 0xd2, 0x3d, 0x10, 0x63, 0x12, 0xed, + 0x23, 0xfd, 0xab, 0x65, 0x18, 0x6d, 0x94, 0x61, 0x06, 0xaa, 0x0b, 0xcc, + 0x3c, 0xd2, 0x91, 0xc9, 0x1b, 0x1e, 0x66, 0x38, 0x26, 0x0b, 0x0a, 0xb8, + 0x15, 0x88, 0xaf, 0x93, 0x03, 0x41, 0x2f, 0x0c, 0x2b, 0x68, 0x94, 0x1f, + 0xa7, 0x8d, 0xed, 0x3d, 0xa1, 0xca, 0x53, 0x93, 0xf8, 0x81, 0x95, 0x07, + 0xc5, 0x92, 0xf0, 0xa4, 0x74, 0x76, 0x1b, 0x14, 0x6e, 0xe6, 0x2f, 0x71, + 0x43, 0x8e, 0x79, 0x4c, 0x91, 0x71, 0xd7, 0x1e, 0x63, 0x94, 0xbd, 0xba, + 0x40, 0xb2, 0x86, 0x95, 0x90, 0x8c, 0xad, 0x22, 0x65, 0xfa, 0x65, 0x4c, + 0x65, 0xc4, 0x78, 0x7c, 0xef, 0x7a, 0x46, 0x25, 0xad, 0xac, 0xfc, 0x9c, + 0x6f, 0x24, 0xdf, 0xe4, 0xfe, 0x5f, 0x67, 0x31, 0x4e, 0xb9, 0x2a, 0xdb, + 0xfd, 0xfc, 0x9b, 0x99, 0xe4, 0xc3, 0x7b, 0x61, 0x04, 0x76, 0x0f, 0x4d, + 0x21, 0xcb, 0x27, 0xd9, 0x6d, 0x62, 0x42, 0x4f, 0x6c, 0xd8, 0x0a, 0xbc, + 0xa9, 0xbb, 0xc6, 0x61, 0x4b, 0xc3, 0xec, 0x82, 0x8b, 0xcc, 0x7b, 0x55, + 0xdd, 0xaa, 0xc1, 0x9e, 0x93, 0xd8, 0x77, 0xae, 0x34, 0x83, 0xbc, 0x90, + 0x85, 0x73, 0x4f, 0xba, 0x55, 0xa6, 0x66, 0x31, 0xe3, 0x8b, 0x11, 0x6b, + 0xce, 0xdf, 0x6a, 0xa3, 0x6e, 0xca, 0xe5, 0x65, 0x77, 0xd6, 0x08, 0x22, + 0x20, 0x20, 0x44, 0x04, 0xc7, 0x2a, 0x46, 0x4f, 0x17, 0xc7, 0xf6, 0x6f, + 0x45, 0x6a, 0xd3, 0xfc, 0xce, 0xa0, 0x9c, 0x43, 0xe3, 0x68, 0x83, 0x9b, + 0x70, 0x7f, 0x74, 0x1e, 0x8f, 0x9b, 0x61, 0x2d, 0x7f, 0x1f, 0x45, 0xd1, + 0xef, 0x92, 0xfb, 0x5f, 0xfa, 0x7a, 0x7f, 0x20, 0x0d, 0x86, 0xc6, 0x6f, + 0x5d, 0x8a, 0x0a, 0xd2, 0xb7, 0xe6, 0x82, 0xc9, 0x66, 0xb7, 0x54, 0x20, + 0x80, 0x19, 0xc9, 0x09, 0x10, 0x7e, 0x81, 0x92, 0x93, 0xab, 0x4e, 0xc9, + 0x49, 0x2d, 0xf4, 0xef, 0x5d, 0x08, 0x37, 0x6e, 0x0c, 0xfa, 0xfc, 0xd3, + 0xe0, 0xc4, 0x43, 0x04, 0x15, 0x47, 0x51, 0x9b, 0xc3, 0x9b, 0x6b, 0x80, + 0x03, 0xc6, 0x8b, 0x9a, 0x0d, 0x3c, 0xf1, 0x49, 0x0b, 0xd6, 0x39, 0x36, + 0x42, 0xd4, 0x81, 0xb2, 0x63, 0xe0, 0xa0, 0x8a, 0x34, 0xc0, 0x8a, 0xd0, + 0x67, 0xed, 0x3f, 0xed, 0x5f, 0x46, 0xa6, 0x04, 0x6b, 0x07, 0x81, 0xaa, + 0xc6, 0xc5, 0x0f, 0x17, 0x82, 0x28, 0xe9, 0xc7, 0xcd, 0xe5, 0xfc, 0xc3, + 0xb6, 0x45, 0xce, 0xe9, 0xd5, 0xe6, 0xe1, 0xc3, 0x92, 0x88, 0xe3, 0x22, + 0x3d, 0x63, 0x99, 0x47, 0x00, 0x3c, 0x21, 0x71, 0x02, 0x84, 0xd5, 0xb0, + 0x05, 0x9d, 0x19, 0x71, 0x5c, 0x9c, 0xea, 0x21, 0x64, 0x59, 0x0c, 0xa2, + 0x33, 0xdd, 0xcb, 0xcc, 0x5d, 0xcf, 0xd3, 0xc5, 0xc5, 0x38, 0xfc, 0xe1, + 0x9d, 0xd7, 0xff, 0xe4, 0x13, 0x76, 0x9d, 0xe7, 0xa5, 0xa1, 0x76, 0xc5, + 0xd3, 0xa6, 0xfa, 0x62, 0x5e, 0xb0, 0xf9, 0x8c, 0x1d, 0x8a, 0x75, 0x7f, + 0xef, 0x5b, 0x73, 0x76, 0xb6, 0x0a, 0x0e, 0xca, 0x34, 0x77, 0x7c, 0x42, + 0xcb, 0xe3, 0x62, 0x34, 0xda, 0xf2, 0x5a, 0x83, 0x37, 0xdd, 0xba, 0x06, + 0x4c, 0xa6, 0xf2, 0x80, 0x87, 0xfe, 0x61, 0x0b, 0xa3, 0x27, 0x84, 0x28, + 0x80, 0x81, 0x9a, 0x07, 0x4f, 0x77, 0xbf, 0x56, 0x7c, 0xe9, 0x24, 0xdc, + 0xa0, 0xe7, 0x1c, 0x0a, 0x32, 0x67, 0x22, 0x64, 0x47, 0x1c, 0x41, 0x06, + 0xac, 0x0a, 0x1f, 0x34, 0xa2, 0x08, 0xd9, 0x94, 0x02, 0x91, 0x79, 0x73, + 0x1e, 0x86, 0xd2, 0x21, 0x71, 0x02, 0x8d, 0xf3, 0xef, 0x9f, 0x17, 0xac, + 0xe2, 0x74, 0xec, 0x11, 0xbb, 0xe4, 0x62, 0xfc, 0x17, 0x38, 0x7d, 0x57, + 0x21, 0x0d, 0x5a, 0x4e, 0x8d, 0xa5, 0x8b, 0xc6, 0x44, 0xd9, 0xfb, 0x42, + 0xd5, 0x0b, 0x18, 0xdd, 0xf1, 0x7d, 0xca, 0x3b, 0x02, 0x00, 0x23, 0x38, + 0xd6, 0xa9, 0xb8, 0x4b, 0x1f, 0x7a, 0xe8, 0x55, 0x4a, 0xb3, 0xaf, 0xf8, + 0x0a, 0x57, 0xe5, 0xd7, 0xff, 0xee, 0x2b, 0xbc, 0xb5, 0x1f, 0xb5, 0xf1, + 0x43, 0xd0, 0x6f, 0xcf, 0xf1, 0x4e, 0x22, 0xe0, 0x01, 0x79, 0xc1, 0xbd, + 0x1e, 0xdb, 0x48, 0xb6, 0x9c, 0x26, 0xc2, 0xa9, 0x91, 0xee, 0x89, 0x1b, + 0xd5, 0x23, 0x08, 0x8c, 0x62, 0xc9, 0x86, 0x3e, 0x33, 0x6a, 0xb9, 0x7f, + 0x63, 0x51, 0x28, 0xab, 0xba, 0x60, 0x2c, 0x12, 0xcf, 0x66, 0x43, 0x38, + 0x0d, 0xc5, 0x3b, 0x2f, 0xf0, 0x70, 0x9c, 0xeb, 0x39, 0xe0, 0x8f, 0xcd, + 0x4c, 0x73, 0x1c, 0x70, 0x01, 0xfa, 0x78, 0xd3, 0x16, 0x1a, 0xae, 0x27, + 0x2d, 0x02, 0xdc, 0xdb, 0xba, 0x4b, 0xed, 0xae, 0x61, 0x1f, 0x55, 0x77, + 0xf5, 0xff, 0x88, 0xdb, 0x8b, 0xfc, 0x18, 0xc4, 0x9b, 0x41, 0xf1, 0x0e, + 0x6f, 0x6e, 0xc6, 0x77, 0x05, 0x8c, 0x6a, 0x7d, 0xbd, 0x69, 0xb8, 0x26, + 0x68, 0xd1, 0x55, 0x93, 0x9b, 0x4c, 0x66, 0xd6, 0xcf, 0xb4, 0x33, 0x5e, + 0x6a, 0xc1, 0x96, 0xca, 0xe6, 0x8b, 0x2d, 0xdf, 0xd6, 0x1d, 0xa6, 0x67, + 0xfc, 0x26, 0x96, 0xfc, 0xfa, 0xcd, 0x65, 0x77, 0x43, 0x44, 0x10, 0x01, + 0x08, 0x93, 0xa6, 0xb2, 0x1a, 0x27, 0x9c, 0x50, 0xde, 0xc0, 0xcf, 0xba, + 0x8d, 0x35, 0x6c, 0x57, 0x5b, 0x0e, 0x11, 0x7c, 0x89, 0x74, 0xca, 0x7e, + 0xf5, 0x08, 0xaf, 0xe4, 0x9f, 0x78, 0x14, 0x8d, 0x2e, 0x1f, 0x47, 0x0a, + 0x18, 0x26, 0xb0, 0x7d, 0xce, 0x36, 0x63, 0x30, 0xa5, 0x63, 0x5e, 0x10, + 0x98, 0xf9, 0xe2, 0x57, 0xe2, 0x0c, 0x17, 0x34, 0xfd, 0x4c, 0x35, 0xe5, + 0x44, 0xbf, 0xf1, 0xa1, 0x9f, 0x07, 0x4c, 0x5f, 0xb1, 0xff, 0x57, 0xd3, + 0xf9, 0xe8, 0xd6, 0x76, 0xae, 0xda, 0xd0, 0xd8, 0x49, 0x44, 0x65, 0x76, + 0xd1, 0xa3, 0x1b, 0xe5, 0x5e, 0x86, 0x12, 0xd2, 0x77, 0x6c, 0x19, 0xfa, + 0x32, 0x9b, 0xe6, 0xf8, 0x6d, 0xc8, 0x87, 0x52, 0xad, 0x80, 0xcd, 0xbd, + 0x83, 0xa7, 0x94, 0x68, 0x39, 0x01, 0x32, 0xa4, 0x91, 0x20, 0xe9, 0xb8, + 0xcc, 0x49, 0x8a, 0xad, 0x9f, 0x59, 0x11, 0x2a, 0x8a, 0x8c, 0xaa, 0x54, + 0x82, 0x58, 0x97, 0xc9, 0x4e, 0x2e, 0x99, 0xa0, 0xc6, 0x29, 0xc3, 0x3b, + 0x61, 0x51, 0xf8, 0x65, 0xa5, 0x76, 0x33, 0xf5, 0xa4, 0x5d, 0x3e, 0x3f, + 0xdc, 0xfc, 0x4d, 0xa9, 0x78, 0x16, 0x29, 0x61, 0x5f, 0x2b, 0x1d, 0x82, + 0x61, 0x8e, 0x5e, 0xb6, 0x10, 0xfc, 0x6c, 0x07, 0x9d, 0xe8, 0x34, 0x5d, + 0xe0, 0xad, 0x81, 0x19, 0x4c, 0x32, 0x9b, 0x1c, 0x5d, 0xae, 0xe6, 0x4e, + 0xaf, 0xba, 0xf3, 0x0d, 0x54, 0x7a, 0x9f, 0x84, 0x5b, 0xc0, 0x6c, 0xba, + 0x21, 0x14, 0x19, 0x57, 0x09, 0x63, 0x48, 0x92, 0xdb, 0x8b, 0x02, 0xff, + 0xf9, 0x3b, 0xd5, 0xe7, 0xa1, 0x97, 0x57, 0x88, 0x95, 0xc9, 0xf7, 0x99, + 0xc8, 0xab, 0x28, 0x6f, 0x89, 0x06, 0xde, 0x54, 0x2e, 0xe5, 0xeb, 0x51, + 0x0f, 0x36, 0xfd, 0xcf, 0x37, 0x43, 0x67, 0x21, 0xd8, 0xeb, 0xa4, 0xeb, + 0x5d, 0xf4, 0x64, 0xd5, 0xb7, 0x1d, 0xf6, 0xea, 0x0a, 0xe9, 0x75, 0x77, + 0xe5, 0x4e, 0xa4, 0x28, 0xdc, 0xc4, 0x09, 0xce, 0xf0, 0x66, 0x8f, 0x8c, + 0xa0, 0x28, 0x81, 0xc5, 0x87, 0x00, 0x61, 0x6b, 0xd3, 0x15, 0x3b, 0x81, + 0x9b, 0x72, 0xc5, 0xfc, 0x04, 0x22, 0x4c, 0x29, 0xfa, 0x42, 0x41, 0x0b, + 0x7c, 0xe5, 0xd9, 0xf6, 0xcd, 0x0d, 0xd5, 0x98, 0x05, 0x3c, 0x5e, 0x4c, + 0x0d, 0x4d, 0x1b, 0x8c, 0x8e, 0xb2, 0x13, 0xa9, 0xf7, 0x46, 0x38, 0xa1, + 0x52, 0x20, 0x67, 0x96, 0xa9, 0x50, 0x33, 0x7f, 0xb3, 0x00, 0x21, 0x3e, + 0x4e, 0x47, 0xd9, 0x9c, 0x53, 0x8d, 0xf7, 0xb6, 0xfa, 0x45, 0x19, 0x57, + 0x56, 0xfa, 0x4e, 0x75, 0x07, 0x9f, 0xe4, 0x5e, 0x13, 0xa9, 0x2b, 0xd7, + 0x70, 0x3b, 0xca, 0x2b, 0xd4, 0x65, 0xb1, 0xbc, 0xb6, 0xc0, 0xbc, 0xfa, + 0x58, 0x3a, 0x09, 0x9e, 0x4e, 0x8c, 0x08, 0xd0, 0x3c, 0xd1, 0xb0, 0x1c, + 0xd2, 0x60, 0xdd, 0x4e, 0xaf, 0xef, 0x62, 0x97, 0x01, 0x80, 0xb8, 0xab, + 0x22, 0x74, 0x2e, 0x0f, 0xd2, 0x34, 0x1b, 0x88, 0x86, 0x9a, 0xa1, 0x5f, + 0xf1, 0x2a, 0x4b, 0x90, 0xd4, 0x1c, 0x68, 0x7a, 0xb0, 0xb8, 0x6a, 0x2c, + 0xeb, 0x80, 0xdf, 0x6d, 0x4c, 0xf6, 0x43, 0x0e, 0x52, 0x91, 0x89, 0x10, + 0x6d, 0x71, 0xec, 0x03, 0xe9, 0x27, 0x2a, 0xa6, 0x31, 0xbb, 0xaa, 0x39, + 0x40, 0xef, 0x97, 0xe3, 0xec, 0x88, 0xb8, 0x47, 0x98, 0x4e, 0xc6, 0xf7, + 0xa3, 0x98, 0x6d, 0xc7, 0x1c, 0x12, 0x55, 0xf2, 0x4f, 0x8e, 0x61, 0xad, + 0x68, 0xb3, 0xf2, 0xf2, 0x1f, 0x20, 0x85, 0xba, 0x9f, 0x8a, 0x7d, 0x91, + 0xe2, 0x3f, 0xf7, 0xa6, 0x7f, 0x3f, 0xee, 0x09, 0x47, 0xf9, 0x7f, 0x68, + 0xcf, 0x83, 0xaf, 0x01, 0xda, 0x33, 0x0b, 0x88, 0xf0, 0xf7, 0xcb, 0x7a, + 0xa5, 0x92, 0x42, 0x0f, 0xd6, 0xc8, 0x25, 0xc1, 0xff, 0x8e, 0x32, 0xc0, + 0xbc, 0x72, 0x92, 0xc9, 0xf4, 0xf5, 0xfa, 0x15, 0x9b, 0x00, 0x46, 0x25, + 0x6e, 0x24, 0xf6, 0x10, 0x95, 0xea, 0x1c, 0xb0, 0x96, 0x0e, 0x8f, 0xb5, + 0x70, 0x68, 0xa7, 0x8f, 0x60, 0x23, 0xc7, 0xeb, 0x26, 0x09, 0xc9, 0x45, + 0x6a, 0xdc, 0x6e, 0xde, 0x82, 0x0f, 0xac, 0xea, 0x22, 0x5d, 0x47, 0x26, + 0xee, 0x9a, 0x6e, 0x0a, 0x42, 0xf2, 0xda, 0x18, 0x3c, 0x7d, 0xd8, 0x68, + 0x7e, 0x4a, 0x4c, 0xbd, 0xb0, 0x00, 0x73, 0x2c, 0x5c, 0x33, 0xf8, 0xb3, + 0x3e, 0x5c, 0xc7, 0x3b, 0xf4, 0x8d, 0xee, 0xee, 0x83, 0x21, 0x5c, 0x42, + 0x24, 0xb3, 0x13, 0xb3, 0x28, 0x1b, 0x85, 0xf5, 0xaa, 0x1c, 0xf9, 0xd8, + 0x90, 0x91, 0xaf, 0x98, 0x40, 0x7c, 0xce, 0x8c, 0x12, 0x5c, 0x68, 0x86, + 0xd4, 0x55, 0xd8, 0x80, 0x93, 0x01, 0x64, 0x34, 0x98, 0x8b, 0x9a, 0x7a, + 0x85, 0x62, 0xc0, 0x76, 0x92, 0xa3, 0x98, 0x11, 0x13, 0x60, 0xc3, 0x72, + 0xb4, 0xb1, 0x8b, 0xf4, 0xf8, 0xc6, 0x23, 0xf6, 0xe6, 0x98, 0x5a, 0xde, + 0x48, 0xff, 0x86, 0x28, 0x41, 0x6c, 0xcb, 0xc7, 0x70, 0x90, 0x17, 0xb9, + 0x61, 0x0f, 0x26, 0x2f, 0x8f, 0xb9, 0x56, 0x49, 0x79, 0x09, 0x88, 0xf2, + 0x3e, 0xff, 0x06, 0x90, 0xb5, 0x78, 0x8e, 0xb1, 0xac, 0x89, 0xe8, 0x8b, + 0x26, 0x4b, 0x6e, 0x7c, 0xbd, 0x54, 0x76, 0xdb, 0x6f, 0x78, 0xfc, 0xdd, + 0x9d, 0x31, 0x17, 0x15, 0xb7, 0x65, 0xc7, 0x9f, 0x55, 0x76, 0x5e, 0xa0, + 0xb9, 0x8e, 0xd9, 0xa1, 0x93, 0x23, 0x6c, 0x18, 0x47, 0x31, 0xee, 0x73, + 0x77, 0xa1, 0x44, 0xb2, 0x53, 0xd8, 0xd6, 0x82, 0x07, 0x0e, 0x1b, 0x86, + 0x2d, 0xb0, 0xe2, 0x22, 0x9f, 0xac, 0xb6, 0xb7, 0x88, 0xa0, 0x03, 0x07, + 0xe6, 0xbd, 0x45, 0x4d, 0x50, 0xec, 0xce, 0x4d, 0xe9, 0x43, 0x90, 0x8e, + 0xaf, 0xdf, 0xc0, 0x4d, 0xe8, 0x3d, 0xfe, 0xb8, 0x34, 0x2b, 0x81, 0xbf, + 0x02, 0x50, 0x87, 0x40, 0xaa, 0x70, 0x43, 0xc8, 0xda, 0x8e, 0xc0, 0xa6, + 0x7a, 0xab, 0xe7, 0x5a, 0x4d, 0xf2, 0x44, 0x9d, 0xbd, 0x7e, 0x76, 0x63, + 0xd8, 0x00, 0x45, 0xb2, 0x1e, 0x20, 0xb7, 0x96, 0x08, 0xb9, 0x4c, 0x06, + 0x81, 0x43, 0x26, 0xd4, 0x5b, 0x90, 0x3c, 0x39, 0xc3, 0x3b, 0xee, 0x27, + 0x7a, 0x4e, 0x1d, 0x5f, 0x9e, 0xeb, 0xe1, 0x2f, 0x10, 0xf0, 0xd9, 0x2e, + 0x61, 0x8a, 0x67, 0xca, 0xbb, 0xbf, 0x17, 0xe3, 0xf6, 0x58, 0xaa, 0xeb, + 0x5f, 0xd7, 0xda, 0xfb, 0x81, 0x63, 0x0e, 0xe0, 0xac, 0x93, 0xe8, 0x1b, + 0x11, 0x3a, 0x1f, 0x51, 0x26, 0x99, 0xea, 0xf3, 0x73, 0x99, 0x2a, 0xd0, + 0xaf, 0x76, 0xd1, 0xda, 0xcc, 0xfe, 0xce, 0x82, 0x69, 0x6d, 0xe4, 0xc3, + 0x44, 0xa6, 0x7a, 0x8e, 0xda, 0x44, 0xdf, 0x07, 0xaf, 0xf0, 0x6d, 0x33, + 0x90, 0x8a, 0xc4, 0x8c, 0x68, 0xa6, 0x86, 0xa8, 0x59, 0x00, 0x62, 0x36, + 0x0c, 0x55, 0x7d, 0x63, 0xd2, 0xea, 0x3a, 0x2b, 0x6a, 0x5b, 0x76, 0x9d, + 0xab, 0x26, 0xb6, 0x25, 0xe7, 0x95, 0x42, 0x54, 0x11, 0xf5, 0x05, 0x33, + 0x7f, 0x6e, 0x8a, 0xa0, 0x4c, 0x25, 0x63, 0x3f, 0x13, 0xfe, 0x81, 0x54, + 0x7b, 0x86, 0x45, 0x9b, 0xba, 0x6b, 0x34, 0x4a, 0x1e, 0xeb, 0x92, 0x67, + 0x9e, 0x13, 0x30, 0xc1, 0x3c, 0xfd, 0xe1, 0xe8, 0xbe, 0xe2, 0x5c, 0x93, + 0xf5, 0xd9, 0xf6, 0x9d, 0x42, 0x88, 0x59, 0x2f, 0x76, 0x77, 0x6a, 0x4a, + 0x4c, 0x8e, 0xed, 0x0e, 0x49, 0x7e, 0xdc, 0x08, 0xef, 0x84, 0x74, 0x1e, + 0x27, 0x37, 0x53, 0xd4, 0x7e, 0xbf, 0xac, 0x32, 0x94, 0x00, 0x06, 0xf4, + 0x57, 0x0f, 0xa6, 0xe7, 0xa6, 0x70, 0x25, 0x3a, 0x2e, 0x8d, 0x83, 0xa0, + 0x1c, 0xa8, 0x08, 0x2c, 0xbd, 0x14, 0x71, 0xad, 0x57, 0xd1, 0xb1, 0xed, + 0x49, 0x91, 0x1f, 0x72, 0xe8, 0xab, 0x46, 0x83, 0x89, 0xb8, 0x16, 0xe4, + 0xf5, 0x7f, 0x73, 0x1f, 0x44, 0x01, 0xc9, 0x88, 0x9c, 0xdc, 0x65, 0xb4, + 0x44, 0xbd, 0x47, 0x8b, 0x52, 0x48, 0x5c, 0x30, 0xf9, 0x73, 0xa0, 0x8c, + 0x72, 0xa3, 0x4c, 0x93, 0x0f, 0xb1, 0xda, 0x0b, 0x8c, 0x02, 0xb4, 0x07, + 0x06, 0xda, 0x78, 0xed, 0x7a, 0x4c, 0x4a, 0xb2, 0x21, 0xee, 0x23, 0xe8, + 0x56, 0x4c, 0x6d, 0x03, 0xa0, 0x71, 0x2c, 0xdf, 0x6a, 0xc4, 0x68, 0xa4, + 0xf0, 0x18, 0x49, 0xcd, 0x7e, 0x66, 0xef, 0x62, 0x1e, 0xe7, 0x23, 0x3b, + 0x87, 0x19, 0x54, 0x12, 0x67, 0x63, 0xb7, 0x5f, 0xa6, 0xd2, 0x26, 0xed, + 0x33, 0x09, 0xfe, 0x58, 0xae, 0x78, 0x48, 0x03, 0x17, 0x00, 0x01, 0x7f, + 0x70, 0xe2, 0xde, 0xc0, 0x1d, 0x4c, 0x32, 0x66, 0xec, 0xe0, 0x8f, 0x00, + 0x3e, 0xf3, 0x57, 0x77, 0xe3, 0x9b, 0x8d, 0x70, 0xac, 0x3c, 0x36, 0x0e, + 0x7b, 0x67, 0xc6, 0x1d, 0xc5, 0x64, 0x9c, 0x0a, 0xfb, 0xdb, 0x40, 0xf9, + 0x85, 0x42, 0x1a, 0x01, 0x4b, 0x86, 0xb2, 0x60, 0xc3, 0xc6, 0x69, 0x48, + 0xff, 0x22, 0xf8, 0xcb, 0xc2, 0x4a, 0xb2, 0x36, 0x62, 0xdb, 0xaa, 0x1f, + 0xe5, 0xdc, 0x2c, 0xa5, 0x2c, 0x33, 0x42, 0xf0, 0xe3, 0x9b, 0x48, 0xa7, + 0x50, 0xaa, 0x0f, 0x3e, 0x6c, 0xfb, 0xed, 0x4b, 0xbd, 0xd1, 0x1b, 0x5d, + 0x96, 0xa2, 0x9c, 0x1a, 0xe3, 0xb6, 0x32, 0xf0, 0xcb, 0x08, 0x60, 0xdf, + 0x48, 0xde, 0x04, 0x62, 0xfc, 0x01, 0x30, 0x29, 0x9e, 0x39, 0x4a, 0x0c, + 0x4f, 0x79, 0x3b, 0xc9, 0xce, 0xd8, 0xc4, 0xee, 0xcc, 0xdc, 0x63, 0x50, + 0xe5, 0xa4, 0x6c, 0x95, 0x66, 0xc0, 0x47, 0x0f, 0xbe, 0xa2, 0x02, 0x6d, + 0xcd, 0x32, 0xc3, 0x14, 0x0e, 0x95, 0x21, 0xbc, 0x61, 0xee, 0x25, 0x65, + 0xfc, 0x4c, 0x23, 0xe0, 0xa5, 0x0a, 0x65, 0xc0, 0xe3, 0xe8, 0x56, 0x10, + 0xb3, 0xb1, 0x6a, 0xd1, 0xd3, 0x71, 0xb2, 0xb5, 0x90, 0x74, 0x32, 0x24, + 0xe5, 0xa7, 0x04, 0x37, 0xde, 0x71, 0xef, 0x08, 0x4c, 0x1c, 0x80, 0x6b, + 0x99, 0x17, 0x47, 0x72, 0x44, 0x31, 0x22, 0xd9, 0xce, 0xff, 0x61, 0x2d, + 0x72, 0xe0, 0xbd, 0x48, 0x3e, 0xfd, 0x5a, 0xc5, 0x7b, 0x16, 0x96, 0xbd, + 0x47, 0x60, 0x6d, 0xa1, 0x6a, 0x34, 0xe9, 0xaa, 0xd5, 0xfe, 0x09, 0x1d, + 0xfa, 0x94, 0xb8, 0xc0, 0x63, 0xa9, 0x1d, 0x8a, 0x27, 0x7b, 0xf0, 0xd2, + 0xe7, 0x3e, 0x5e, 0x6e, 0x6a, 0x8e, 0xe3, 0x4b, 0xa8, 0x0c, 0xac, 0xc4, + 0x50, 0x1c, 0xa0, 0xfc, 0x48, 0x42, 0x53, 0x54, 0x08, 0x64, 0xae, 0x9f, + 0x19, 0xd6, 0xd3, 0xc9, 0x55, 0x0e, 0x72, 0x18, 0x53, 0xef, 0x02, 0xd1, + 0x14, 0x81, 0xa9, 0xa8, 0xb6, 0xf5, 0x93, 0x56, 0xcb, 0xd0, 0x63, 0xbc, + 0xb9, 0xfd, 0x77, 0xa4, 0x1d, 0x3f, 0x29, 0xba, 0x97, 0xb5, 0xed, 0x7c, + 0xe5, 0x35, 0xe5, 0x74, 0x6b, 0x08, 0xe8, 0x3f, 0x6d, 0xc4, 0x70, 0x06, + 0x3b, 0xd1, 0x92, 0xcc, 0xab, 0x7a, 0x22, 0x13, 0x96, 0x41, 0xfc, 0x92, + 0x81, 0xb7, 0x39, 0xdf, 0x68, 0xaa, 0x77, 0x21, 0x87, 0xff, 0x78, 0x83, + 0xf5, 0xca, 0x8b, 0x08, 0xa9, 0xcd, 0xc0, 0xa0, 0xb8, 0x7c, 0x52, 0x93, + 0xec, 0x93, 0x5c, 0xe6, 0xd9, 0xc9, 0x49, 0x94, 0x60, 0xac, 0x1c, 0x9e, + 0x1e, 0x19, 0xac, 0xc3, 0xfa, 0x3f, 0xe0, 0x36, 0x1d, 0x99, 0x8f, 0xea, + 0xc7, 0xe6, 0x1e, 0x0b, 0x7f, 0x02, 0x73, 0x3c, 0xda, 0x49, 0x68, 0x44, + 0x91, 0x76, 0x3c, 0x4d, 0x53, 0xfc, 0xda, 0x99, 0x8d, 0x13, 0xcf, 0xd3, + 0x88, 0xbb, 0xdf, 0x3f, 0xab, 0x42, 0x08, 0x9b, 0xeb, 0x1f, 0x93, 0x09, + 0x59, 0x39, 0x21, 0x2c, 0x91, 0xe5, 0xef, 0x97, 0xf7, 0x8c, 0x56, 0x34, + 0x66, 0x94, 0x05, 0x18, 0x1b, 0x50, 0x41, 0xf3, 0xa6, 0xca, 0x82, 0xdf, + 0xa3, 0x8e, 0xa9, 0x3f, 0x6d, 0xa0, 0xfb, 0x74, 0x2b, 0x35, 0x2c, 0x02, + 0xc3, 0xd3, 0xba, 0x21, 0x0e, 0xef, 0x23, 0x35, 0x06, 0xcd, 0xc7, 0x5e, + 0x44, 0x6f, 0xa5, 0x5d, 0xee, 0x9a, 0x42, 0x54, 0x47, 0x78, 0xbe, 0x47, + 0x9e, 0x17, 0x56, 0x94, 0xf7, 0xb2, 0x6c, 0x97, 0x45, 0x16, 0xea, 0xa0, + 0xe4, 0xb4, 0x84, 0xf0, 0xda, 0xb6, 0x3a, 0xb6, 0xee, 0x1d, 0x5f, 0x87, + 0x0d, 0xa4, 0x13, 0x19, 0xa3, 0x4b, 0x27, 0x4c, 0xec, 0x9e, 0x66, 0x2b, + 0x6f, 0x91, 0x85, 0x22, 0xee, 0x2e, 0x55, 0xa2, 0xe5, 0x52, 0x09, 0x78, + 0x05, 0x39, 0x32, 0x27, 0xda, 0x7c, 0xe2, 0xcc, 0x78, 0x40, 0xfc, 0x11, + 0xab, 0x95, 0xbc, 0xb6, 0x3f, 0x26, 0x90, 0x15, 0xcb, 0x59, 0xd5, 0x10, + 0x36, 0xeb, 0x03, 0x25, 0x8e, 0x46, 0xcf, 0x63, 0x1d, 0x34, 0x76, 0xda, + 0x61, 0xef, 0xfd, 0x86, 0x66, 0x7a, 0x23, 0x9a, 0xff, 0xcb, 0xe1, 0x61, + 0xc7, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6b, 0x75, 0xd3, 0x13, 0xc6, + 0x7f, 0x6c, 0x2b, 0xef, 0x9b, 0xbf, 0x66, 0x14, 0xe8, 0x6f, 0xb2, 0xaf, + 0xf4, 0x61, 0x91, 0x3f, 0x7b, 0xf7, 0x9b, 0xb5, 0x34, 0x6b, 0x8f, 0xca, + 0xcf, 0x32, 0x6c, 0xe0, 0xb4, 0xea, 0x51, 0xff, 0x01, 0x8b, 0xd7, 0x80, + 0x95, 0x46, 0xb9, 0xbc, 0xe3, 0x92, 0x52, 0x3b, 0xec, 0x63, 0xc3, 0x6e, + 0x34, 0xef, 0xc7, 0xb1, 0x52, 0x41, 0x87, 0x21, 0xa5, 0xf1, 0xe5, 0x37, + 0xc5, 0x7c, 0x9d, 0xa3, 0x14, 0xb8, 0xee, 0x35, 0x63, 0xed, 0x00, 0xce, + 0x91, 0xf8, 0xc7, 0x88, 0x41, 0xf6, 0xbf, 0x5a, 0x6c, 0x73, 0xca, 0x0b, + 0x1a, 0xde, 0x7e, 0x49, 0x7c, 0xc1, 0xe8, 0xeb, 0xe3, 0xba, 0xf2, 0x8a, + 0x98, 0xce, 0x19, 0x98, 0xdb, 0x62, 0x03, 0x15, 0x08, 0x33, 0x83, 0x77, + 0x3f, 0x7c, 0xc8, 0x27, 0xef, 0x2d, 0x4b, 0x4b, 0x7f, 0x80, 0xfc, 0x12, + 0x41, 0x4b, 0x89, 0x88, 0x32, 0x19, 0xaa, 0xf4, 0xff, 0x39, 0x61, 0xc9, + 0x06, 0xfd, 0x78, 0x79, 0xc0, 0x52, 0x7e, 0xe6, 0x79, 0x7d, 0x50, 0x43, + 0xb3, 0xf2, 0x86, 0xb2, 0xf3, 0x38, 0x35, 0x72, 0xbf, 0xb7, 0x35, 0x45, + 0x34, 0xb3, 0x05, 0x67, 0x3e, 0xb7, 0x71, 0x5e, 0x55, 0x36, 0xc7, 0xbf, + 0x3b, 0x6d, 0xc3, 0xf9, 0x9c, 0x94, 0x4f, 0x63, 0x3e, 0x34, 0x44, 0x9e, + 0x5f, 0x2b, 0x65, 0xc2, 0xeb, 0x5b, 0x5c, 0x61, 0x20, 0x6a, 0x3e, 0xb5, + 0x38, 0xf0, 0x5b, 0xde, 0x45, 0xa7, 0x1f, 0xa7, 0xad, 0xd0, 0xb5, 0x0d, + 0x2d, 0x15, 0x9f, 0x7c, 0x62, 0x7a, 0xf1, 0x2a, 0xb8, 0x6c, 0xeb, 0x0f, + 0xd5, 0x84, 0xa9, 0xfa, 0x5f, 0xc6, 0x39, 0x66, 0xd7, 0xaa, 0x8c, 0x4b, + 0xbe, 0xaf, 0x26, 0xc1, 0x7b, 0xbb, 0xbb, 0x45, 0xa9, 0x58, 0xb7, 0x62, + 0x6b, 0x96, 0x3a, 0xe9, 0xb0, 0x87, 0x1b, 0x5d, 0x8b, 0x77, 0xe0, 0xcc, + 0x9c, 0xad, 0x3b, 0xfb, 0xe9, 0x53, 0x85, 0x1c, 0xae, 0xf8, 0x70, 0x06, + 0x66, 0x88, 0x30, 0x12, 0x44, 0xa5, 0x31, 0xd8, 0x23, 0xdc, 0x4f, 0x80, + 0x36, 0x02, 0x9c, 0x9e, 0x36, 0x09, 0x70, 0xd5, 0xa4, 0x41, 0xa6, 0x48, + 0xfd, 0xd3, 0x39, 0x19, 0xa0, 0x43, 0x7e, 0x8d, 0xe9, 0x41, 0x3b, 0x1b, + 0x58, 0x6b, 0xb0, 0xe2, 0x28, 0x21, 0x21, 0xe3, 0x6d, 0xa1, 0x84, 0x29, + 0x1e, 0xcf, 0x5f, 0xeb, 0x81, 0xf9, 0xc6, 0x07, 0x09, 0xc9, 0xe1, 0x6d, + 0x53, 0x47, 0x59, 0xf7, 0x14, 0x23, 0x5d, 0x39, 0x12, 0x4b, 0xbe, 0x7e, + 0x28, 0xb9, 0x9c, 0x23 +}; +unsigned int ios6_1_keychain_2_db_len = 126976; + diff --git a/keychain/securityd/Regressions/ios8-inet-keychain-2.h b/keychain/securityd/Regressions/ios8-inet-keychain-2.h new file mode 100644 index 00000000..4c531164 --- /dev/null +++ b/keychain/securityd/Regressions/ios8-inet-keychain-2.h @@ -0,0 +1,9902 @@ +unsigned char ios8_inet_keychain_2_db[] = { + 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x20, 0x33, 0x00, 0x10, 0x00, 0x02, 0x02, 0x00, 0x40, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x2d, 0xe6, 0x08, 0x0d, 0x0f, 0xfc, 0x00, 0x1b, 0x02, 0x81, 0x00, + 0x0e, 0x23, 0x0f, 0xd3, 0x0d, 0xd1, 0x0b, 0x4f, 0x0d, 0xa8, 0x09, 0x9c, + 0x0b, 0x26, 0x06, 0x6c, 0x09, 0x73, 0x06, 0x28, 0x05, 0xf1, 0x05, 0xba, + 0x05, 0x83, 0x05, 0x4c, 0x05, 0x15, 0x04, 0xde, 0x04, 0xa7, 0x04, 0x70, + 0x04, 0x39, 0x04, 0x02, 0x03, 0xcb, 0x03, 0x94, 0x03, 0x5d, 0x03, 0x26, + 0x02, 0xef, 0x02, 0xb8, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1b, 0x06, 0x17, 0x17, 0x15, 0x01, + 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x6b, + 0x65, 0x79, 0x73, 0x1d, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, + 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x75, 0x6e, 0x77, 0x70, 0x20, 0x4f, + 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x75, 0x6e, 0x77, 0x70, 0x29, + 0x35, 0x1a, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x69, 0x77, 0x72, 0x61, 0x70, 0x6b, 0x65, 0x79, 0x73, 0x1c, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, + 0x69, 0x77, 0x72, 0x61, 0x70, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, + 0x73, 0x28, 0x77, 0x72, 0x61, 0x70, 0x29, 0x35, 0x19, 0x06, 0x17, 0x17, + 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x76, 0x72, 0x66, + 0x79, 0x6b, 0x65, 0x79, 0x73, 0x1b, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x76, 0x72, 0x66, 0x79, + 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x76, 0x72, 0x66, + 0x79, 0x29, 0x35, 0x18, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x6b, 0x65, 0x79, 0x73, + 0x1a, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, + 0x58, 0x20, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x4e, 0x20, 0x6b, + 0x65, 0x79, 0x73, 0x28, 0x73, 0x69, 0x67, 0x6e, 0x29, 0x35, 0x17, 0x06, + 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, + 0x72, 0x76, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x19, 0x43, 0x52, 0x45, 0x41, + 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x72, + 0x76, 0x65, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, + 0x72, 0x76, 0x65, 0x29, 0x35, 0x16, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x64, 0x65, 0x63, 0x72, 0x6b, 0x65, + 0x79, 0x73, 0x18, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, + 0x44, 0x45, 0x58, 0x20, 0x69, 0x64, 0x65, 0x63, 0x72, 0x20, 0x4f, 0x4e, + 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x64, 0x65, 0x63, 0x72, 0x29, 0x35, + 0x15, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x69, 0x65, 0x6e, 0x63, 0x72, 0x6b, 0x65, 0x79, 0x73, 0x17, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, + 0x65, 0x6e, 0x63, 0x72, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, + 0x28, 0x65, 0x6e, 0x63, 0x72, 0x29, 0x35, 0x14, 0x06, 0x17, 0x17, 0x15, + 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x6b, 0x6c, 0x62, 0x6c, + 0x6b, 0x65, 0x79, 0x73, 0x16, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, + 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x6b, 0x6c, 0x62, 0x6c, 0x20, + 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x6b, 0x6c, 0x62, 0x6c, + 0x29, 0x35, 0x13, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x69, 0x6b, 0x63, 0x6c, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x15, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, + 0x20, 0x69, 0x6b, 0x63, 0x6c, 0x73, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, + 0x79, 0x73, 0x28, 0x6b, 0x63, 0x6c, 0x73, 0x29, 0x35, 0x12, 0x06, 0x17, + 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x70, 0x6b, + 0x68, 0x68, 0x63, 0x65, 0x72, 0x74, 0x14, 0x43, 0x52, 0x45, 0x41, 0x54, + 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x70, 0x6b, 0x68, + 0x68, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x70, 0x6b, + 0x68, 0x68, 0x29, 0x35, 0x11, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x69, 0x73, 0x6b, 0x69, 0x64, 0x63, 0x65, 0x72, + 0x74, 0x13, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, + 0x45, 0x58, 0x20, 0x69, 0x73, 0x6b, 0x69, 0x64, 0x20, 0x4f, 0x4e, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x6b, 0x69, 0x64, 0x29, 0x35, 0x10, + 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, + 0x73, 0x75, 0x62, 0x6a, 0x63, 0x65, 0x72, 0x74, 0x12, 0x43, 0x52, 0x45, + 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x73, + 0x75, 0x62, 0x6a, 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, + 0x73, 0x75, 0x62, 0x6a, 0x29, 0x35, 0x0f, 0x06, 0x17, 0x17, 0x15, 0x01, + 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x63, + 0x65, 0x72, 0x74, 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, + 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x4f, + 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x61, 0x6c, 0x69, 0x73, 0x29, + 0x35, 0x0e, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x69, 0x6b, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x79, 0x73, 0x10, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, + 0x69, 0x6b, 0x73, 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x6b, 0x65, 0x79, + 0x73, 0x28, 0x73, 0x68, 0x61, 0x31, 0x29, 0x35, 0x0d, 0x06, 0x17, 0x17, + 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x63, 0x73, 0x68, + 0x61, 0x63, 0x65, 0x72, 0x74, 0x0f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x63, 0x73, 0x68, 0x61, + 0x20, 0x4f, 0x4e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x73, 0x68, 0x61, + 0x31, 0x29, 0x35, 0x0c, 0x06, 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x69, 0x69, 0x73, 0x68, 0x61, 0x69, 0x6e, 0x65, 0x74, + 0x0e, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, + 0x58, 0x20, 0x69, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x69, + 0x6e, 0x65, 0x74, 0x28, 0x73, 0x68, 0x61, 0x31, 0x29, 0x35, 0x0b, 0x06, + 0x17, 0x17, 0x15, 0x01, 0x4d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x69, 0x67, + 0x73, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x70, 0x0d, 0x43, 0x52, 0x45, 0x41, + 0x54, 0x45, 0x20, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x20, 0x69, 0x67, 0x73, + 0x68, 0x61, 0x20, 0x4f, 0x4e, 0x20, 0x67, 0x65, 0x6e, 0x70, 0x28, 0x73, + 0x68, 0x61, 0x31, 0x29, 0x42, 0x0a, 0x06, 0x17, 0x1d, 0x1d, 0x01, 0x59, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x74, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0c, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x74, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x29, + 0x86, 0x04, 0x08, 0x07, 0x17, 0x15, 0x15, 0x01, 0x8b, 0x6b, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x6b, 0x65, 0x79, 0x73, 0x6b, 0x65, 0x79, 0x73, 0x0a, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, + 0x20, 0x6b, 0x65, 0x79, 0x73, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, + 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, + 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, + 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, + 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6b, 0x63, 0x6c, 0x73, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x30, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, + 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x65, + 0x72, 0x6d, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, + 0x72, 0x69, 0x76, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x6d, 0x6f, 0x64, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, + 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, + 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x61, 0x74, 0x61, 0x67, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, + 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, + 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x79, 0x70, + 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, + 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x62, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, + 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, + 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x64, 0x61, + 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x30, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x20, + 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x65, 0x6e, 0x73, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x61, 0x73, 0x65, 0x6e, + 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x65, 0x78, 0x74, + 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, + 0x78, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x65, + 0x6e, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x64, 0x65, 0x63, 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x2c, 0x64, 0x72, 0x76, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x2c, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x2c, 0x76, 0x72, 0x66, 0x79, 0x20, 0x49, 0x4e, 0x54, 0x45, + 0x47, 0x45, 0x52, 0x2c, 0x73, 0x6e, 0x72, 0x63, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x76, 0x79, 0x72, 0x63, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x77, 0x72, 0x61, 0x70, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x75, 0x6e, 0x77, 0x70, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, + 0x45, 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, + 0x54, 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, + 0x6d, 0x62, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, + 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, + 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x6b, + 0x63, 0x6c, 0x73, 0x2c, 0x6b, 0x6c, 0x62, 0x6c, 0x2c, 0x61, 0x74, 0x61, + 0x67, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x2c, + 0x62, 0x73, 0x69, 0x7a, 0x2c, 0x65, 0x73, 0x69, 0x7a, 0x2c, 0x73, 0x64, + 0x61, 0x74, 0x2c, 0x65, 0x64, 0x61, 0x74, 0x2c, 0x61, 0x67, 0x72, 0x70, + 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x09, 0x06, 0x17, 0x3b, + 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, + 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x5f, 0x31, 0x6b, 0x65, 0x79, 0x73, 0x0b, + 0x83, 0x07, 0x06, 0x07, 0x17, 0x15, 0x15, 0x01, 0x85, 0x71, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x63, 0x65, 0x72, 0x74, 0x63, 0x65, 0x72, 0x74, 0x08, + 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, + 0x20, 0x63, 0x65, 0x72, 0x74, 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, + 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, + 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, + 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, + 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x63, 0x74, 0x79, 0x70, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x30, 0x2c, 0x63, 0x65, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, + 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x73, + 0x75, 0x62, 0x6a, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x73, 0x73, + 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x27, 0x27, 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x20, 0x42, 0x4c, 0x4f, 0x42, + 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, + 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x6b, 0x69, + 0x64, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x70, 0x6b, 0x68, 0x68, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, + 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x73, + 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, + 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, 0x62, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, + 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, + 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, 0x4f, 0x42, + 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x63, 0x74, 0x79, 0x70, + 0x2c, 0x69, 0x73, 0x73, 0x72, 0x2c, 0x73, 0x6c, 0x6e, 0x72, 0x2c, 0x61, + 0x67, 0x72, 0x70, 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x07, + 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, + 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x31, 0x63, 0x65, + 0x72, 0x74, 0x09, 0x84, 0x56, 0x04, 0x07, 0x17, 0x15, 0x15, 0x01, 0x89, + 0x0f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x69, 0x6e, 0x65, 0x74, 0x69, 0x6e, + 0x65, 0x74, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, 0x54, 0x41, + 0x42, 0x4c, 0x45, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x28, 0x72, 0x6f, 0x77, + 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x50, + 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x20, 0x41, + 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, + 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x6d, + 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, 0x2c, 0x64, 0x65, 0x73, + 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x63, 0x6d, 0x74, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, 0x72, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, 0x70, 0x65, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, 0x63, 0x72, 0x70, 0x20, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6c, 0x61, 0x62, 0x6c, + 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x42, + 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, 0x20, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, 0x61, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, 0x73, 0x69, 0x20, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, 0x74, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, + 0x64, 0x6d, 0x6e, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, + 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x20, 0x27, 0x27, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x70, + 0x74, 0x63, 0x6c, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, + 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, + 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, + 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x70, 0x61, 0x74, + 0x68, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x27, 0x27, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, + 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x70, + 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, 0x2c, 0x73, 0x79, 0x6e, + 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, + 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, 0x62, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, + 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, + 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x55, + 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, 0x63, 0x74, 0x2c, 0x73, + 0x64, 0x6d, 0x6e, 0x2c, 0x73, 0x72, 0x76, 0x72, 0x2c, 0x70, 0x74, 0x63, + 0x6c, 0x2c, 0x61, 0x74, 0x79, 0x70, 0x2c, 0x70, 0x6f, 0x72, 0x74, 0x2c, + 0x70, 0x61, 0x74, 0x68, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x2c, 0x73, 0x79, + 0x6e, 0x63, 0x29, 0x29, 0x27, 0x05, 0x06, 0x17, 0x3b, 0x15, 0x01, 0x00, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, + 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x6e, + 0x65, 0x74, 0x5f, 0x31, 0x69, 0x6e, 0x65, 0x74, 0x07, 0x50, 0x03, 0x06, + 0x17, 0x2b, 0x2b, 0x01, 0x59, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x71, + 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x05, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x20, + 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, + 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x28, 0x6e, 0x61, + 0x6d, 0x65, 0x2c, 0x73, 0x65, 0x71, 0x29, 0x83, 0x2d, 0x01, 0x07, 0x17, + 0x15, 0x15, 0x01, 0x86, 0x3d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x67, 0x65, + 0x6e, 0x70, 0x67, 0x65, 0x6e, 0x70, 0x03, 0x43, 0x52, 0x45, 0x41, 0x54, + 0x45, 0x20, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x20, 0x67, 0x65, 0x6e, 0x70, + 0x28, 0x72, 0x6f, 0x77, 0x69, 0x64, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x45, 0x52, 0x20, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, + 0x45, 0x59, 0x20, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, + 0x4d, 0x45, 0x4e, 0x54, 0x2c, 0x63, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, + 0x41, 0x4c, 0x2c, 0x6d, 0x64, 0x61, 0x74, 0x20, 0x52, 0x45, 0x41, 0x4c, + 0x2c, 0x64, 0x65, 0x73, 0x63, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, + 0x63, 0x6d, 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x63, 0x72, 0x74, + 0x72, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x74, 0x79, + 0x70, 0x65, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x73, + 0x63, 0x72, 0x70, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, + 0x6c, 0x61, 0x62, 0x6c, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x6c, + 0x69, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x69, 0x6e, 0x76, 0x69, + 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x6e, 0x65, 0x67, + 0x61, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x63, 0x75, + 0x73, 0x69, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x2c, 0x70, + 0x72, 0x6f, 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x63, 0x63, + 0x74, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, + 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, + 0x27, 0x27, 0x2c, 0x73, 0x76, 0x63, 0x65, 0x20, 0x42, 0x4c, 0x4f, 0x42, + 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, + 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x27, 0x27, 0x2c, 0x67, 0x65, 0x6e, + 0x61, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x20, + 0x42, 0x4c, 0x4f, 0x42, 0x2c, 0x61, 0x67, 0x72, 0x70, 0x20, 0x54, 0x45, + 0x58, 0x54, 0x2c, 0x70, 0x64, 0x6d, 0x6e, 0x20, 0x54, 0x45, 0x58, 0x54, + 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, + 0x52, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x74, 0x6f, 0x6d, + 0x62, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x20, 0x4e, 0x4f, + 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x20, 0x30, 0x2c, 0x73, 0x68, 0x61, 0x31, 0x20, 0x42, 0x4c, + 0x4f, 0x42, 0x2c, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x28, 0x61, 0x63, + 0x63, 0x74, 0x2c, 0x73, 0x76, 0x63, 0x65, 0x2c, 0x61, 0x67, 0x72, 0x70, + 0x2c, 0x73, 0x79, 0x6e, 0x63, 0x29, 0x29, 0x27, 0x02, 0x06, 0x17, 0x3b, + 0x15, 0x01, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x73, 0x71, 0x6c, 0x69, + 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x5f, 0x67, 0x65, 0x6e, 0x70, 0x5f, 0x31, 0x67, 0x65, 0x6e, 0x70, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xd7, 0x00, + 0x0f, 0xf5, 0x0f, 0xeb, 0x0f, 0xe1, 0x0f, 0xd7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x03, 0x15, 0x01, 0x69, 0x6e, 0x65, 0x74, + 0x77, 0x08, 0x03, 0x03, 0x15, 0x01, 0x63, 0x65, 0x72, 0x74, 0x05, 0x08, + 0x02, 0x03, 0x15, 0x01, 0x6b, 0x65, 0x79, 0x73, 0x0e, 0x09, 0x01, 0x03, + 0x15, 0x02, 0x67, 0x65, 0x6e, 0x70, 0x00, 0xd6, 0x0d, 0x00, 0x00, 0x00, + 0x02, 0x0a, 0xdc, 0x00, 0x0d, 0x6e, 0x0a, 0xdc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x85, 0x0f, 0x09, 0x1d, 0x00, 0x07, 0x07, 0x34, + 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, + 0x34, 0x15, 0x34, 0x08, 0x34, 0x86, 0x36, 0x33, 0x11, 0x09, 0x08, 0x34, + 0x41, 0xb8, 0x54, 0x5c, 0xc8, 0xd9, 0xbb, 0x38, 0x41, 0xb8, 0x54, 0x5c, + 0xc8, 0xd9, 0xbb, 0x38, 0x3e, 0x72, 0xab, 0x36, 0x98, 0xa6, 0xab, 0x50, + 0x6e, 0xf3, 0x74, 0x41, 0xd3, 0xda, 0x7d, 0xb4, 0x6b, 0x01, 0xe8, 0xcf, + 0x75, 0x05, 0xd6, 0x4a, 0x54, 0xe0, 0x61, 0xb7, 0xac, 0xd5, 0x4c, 0xcd, + 0x58, 0xb4, 0x9d, 0xc4, 0x35, 0x00, 0xb6, 0x35, 0x44, 0x87, 0x31, 0x70, + 0x51, 0x1a, 0x23, 0xb6, 0x21, 0x60, 0x8c, 0x6c, 0x65, 0xbf, 0xf1, 0xd1, + 0x7e, 0x07, 0x56, 0x8a, 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, + 0x7c, 0xca, 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, + 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, + 0xc0, 0x39, 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, + 0xc5, 0x1c, 0xff, 0xec, 0x68, 0x74, 0x70, 0x73, 0xd0, 0x0b, 0x39, 0x81, + 0x5c, 0x18, 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, + 0x07, 0x28, 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x17, 0xf9, 0xcd, 0x4d, 0xa5, 0x0e, 0x24, 0x36, 0x1a, 0x8e, 0x43, 0x7e, + 0x1a, 0x0c, 0xe6, 0xa1, 0xe7, 0x70, 0x86, 0x1e, 0x6e, 0x14, 0x98, 0xd3, + 0x70, 0x37, 0x04, 0xda, 0x23, 0x9c, 0x19, 0x25, 0xb3, 0x56, 0x67, 0x5d, + 0x6f, 0xa1, 0x14, 0xbd, 0x6e, 0xc5, 0xfc, 0x34, 0x80, 0x39, 0xc0, 0x98, + 0x8b, 0x0b, 0xc9, 0xe9, 0x12, 0xe2, 0x33, 0xbc, 0x33, 0xae, 0x57, 0xc1, + 0x5b, 0xc2, 0xa8, 0x09, 0xf2, 0xc6, 0xd2, 0xbf, 0x6c, 0x3a, 0xd7, 0x36, + 0xa5, 0x47, 0x0a, 0x21, 0x43, 0x09, 0xaa, 0x0d, 0x4a, 0x57, 0x3c, 0xd1, + 0xa5, 0x2b, 0xaf, 0x5e, 0x8b, 0xcb, 0x37, 0xd1, 0x40, 0x88, 0x6d, 0x52, + 0x3e, 0x3d, 0x0e, 0xe8, 0x0d, 0xba, 0x4e, 0x61, 0x52, 0xcc, 0xe6, 0xa2, + 0xaa, 0xfe, 0x11, 0x7a, 0x49, 0x83, 0x82, 0xfe, 0xf8, 0xed, 0xb7, 0xc5, + 0xe6, 0x62, 0x8a, 0x01, 0x52, 0x74, 0x41, 0x97, 0x4f, 0xa5, 0x56, 0xc7, + 0x89, 0x45, 0x19, 0x6e, 0x0f, 0x37, 0xaf, 0x26, 0xef, 0xe6, 0x95, 0x75, + 0xc2, 0x81, 0xc7, 0xdc, 0x92, 0xbe, 0x7d, 0xb3, 0xc7, 0x41, 0xa4, 0x6e, + 0x55, 0xff, 0x90, 0x98, 0x0b, 0xb4, 0x38, 0x90, 0xd3, 0x7f, 0x45, 0x20, + 0x15, 0xc9, 0x63, 0xda, 0xe8, 0xac, 0x55, 0x47, 0x29, 0xbe, 0x02, 0xff, + 0x61, 0x8e, 0x17, 0x5a, 0x20, 0x60, 0x0c, 0x86, 0xdb, 0x80, 0x4b, 0x8e, + 0xb4, 0xd2, 0xad, 0x11, 0x3e, 0x5e, 0xf1, 0xed, 0xdf, 0xf1, 0xef, 0x53, + 0x09, 0x22, 0x43, 0x8f, 0xbd, 0x20, 0xbe, 0x81, 0x78, 0x85, 0x69, 0xc5, + 0x6f, 0x25, 0xca, 0xfb, 0x51, 0x48, 0x5a, 0xd9, 0x49, 0x24, 0x5e, 0x94, + 0x69, 0xeb, 0x64, 0x71, 0xb2, 0x2c, 0xbe, 0x73, 0x9d, 0x75, 0xe9, 0x67, + 0x37, 0xa6, 0x35, 0xc8, 0x07, 0xf9, 0xfe, 0xde, 0xc0, 0xab, 0x42, 0xa6, + 0x78, 0x8f, 0x72, 0xd7, 0x9f, 0xd1, 0x98, 0x08, 0x35, 0x25, 0x01, 0xaf, + 0x92, 0xca, 0x57, 0x74, 0x36, 0xee, 0x1d, 0x08, 0x3a, 0x2d, 0x5d, 0xf3, + 0x1d, 0x5f, 0x0b, 0x9e, 0xac, 0x28, 0x26, 0x77, 0xcf, 0x37, 0x9b, 0x4c, + 0x31, 0x14, 0x4f, 0xfe, 0xaf, 0x4f, 0x7e, 0x41, 0x26, 0xab, 0x41, 0x6d, + 0x61, 0x6b, 0xfd, 0xbc, 0xe3, 0xda, 0x2f, 0x81, 0xfc, 0xa6, 0x45, 0xc9, + 0x0e, 0xeb, 0x20, 0x03, 0x04, 0x3d, 0xce, 0x76, 0xc7, 0x1c, 0x52, 0xc5, + 0x03, 0x98, 0x2e, 0x3b, 0x2b, 0x9f, 0x51, 0xcb, 0x25, 0x89, 0x59, 0xd7, + 0xad, 0xce, 0x7a, 0x9e, 0x65, 0x6b, 0x32, 0x60, 0x7a, 0x62, 0x99, 0xd4, + 0xb7, 0xa3, 0x88, 0xae, 0x1e, 0x2a, 0x49, 0xcb, 0x7b, 0x61, 0x8c, 0xa6, + 0x66, 0xc8, 0x67, 0x01, 0x13, 0x0d, 0x48, 0xb0, 0xbd, 0x9a, 0x9e, 0xdb, + 0x56, 0x2e, 0xb9, 0xae, 0xec, 0xa4, 0x05, 0xa0, 0xb7, 0x43, 0x16, 0xe6, + 0x6e, 0x24, 0x39, 0xdf, 0x1b, 0x6e, 0x80, 0x21, 0x66, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x61, 0x6b, 0x1d, 0x3d, 0x99, 0x45, 0x23, 0x73, + 0xf5, 0xb8, 0xec, 0x97, 0xe1, 0xc2, 0x84, 0xee, 0xec, 0xa3, 0xbc, 0x53, + 0xf3, 0xcd, 0x85, 0x0f, 0x08, 0x1d, 0x00, 0x07, 0x07, 0x34, 0x34, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x15, + 0x34, 0x08, 0x34, 0x86, 0x36, 0x33, 0x11, 0x09, 0x08, 0x34, 0x41, 0xb7, + 0x81, 0x93, 0xca, 0x19, 0x3f, 0x18, 0x41, 0xb7, 0x81, 0x93, 0xca, 0x19, + 0x3f, 0x18, 0x3e, 0x72, 0xab, 0x36, 0x98, 0xa6, 0xab, 0x50, 0x6e, 0xf3, + 0x74, 0x41, 0xd3, 0xda, 0x7d, 0xb4, 0x6b, 0x01, 0xe8, 0xcf, 0x75, 0x05, + 0xd6, 0x4a, 0x54, 0xe0, 0x61, 0xb7, 0xac, 0xd5, 0x4c, 0xcd, 0x58, 0xb4, + 0x9d, 0xc4, 0x35, 0x00, 0xb6, 0x35, 0x44, 0x87, 0x31, 0x70, 0x51, 0x1a, + 0x23, 0xb6, 0x21, 0x60, 0x8c, 0x6c, 0x65, 0xbf, 0xf1, 0xd1, 0x7e, 0x07, + 0x56, 0x8a, 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, 0x7c, 0xca, + 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, 0xda, 0x39, + 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, + 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, 0xc0, 0x39, + 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, 0xc5, 0x1c, + 0xff, 0xec, 0x68, 0x74, 0x74, 0x70, 0xd0, 0x0b, 0x39, 0x81, 0x5c, 0x18, + 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, 0x07, 0x28, + 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x03, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa1, 0x6f, + 0x3f, 0x1b, 0x33, 0x82, 0x64, 0x59, 0xaa, 0x01, 0x83, 0x01, 0xcb, 0x07, + 0x08, 0x16, 0x9c, 0xdf, 0x17, 0xf4, 0x20, 0x74, 0x62, 0xf4, 0xc4, 0xfc, + 0x8b, 0x8d, 0xef, 0x7b, 0x2d, 0x3d, 0x14, 0x52, 0x10, 0x2f, 0x9a, 0x7f, + 0xfa, 0xad, 0x48, 0xbf, 0x88, 0x10, 0x5f, 0xa9, 0xf0, 0x66, 0x80, 0x0a, + 0x72, 0xb0, 0x04, 0x8c, 0x81, 0x72, 0x4f, 0x1a, 0xc2, 0x24, 0x04, 0xec, + 0x78, 0x71, 0x26, 0x0f, 0xd8, 0x74, 0x86, 0x9e, 0x46, 0xc1, 0x83, 0x13, + 0x11, 0x1f, 0xb1, 0x16, 0x02, 0x41, 0x69, 0x4b, 0x4a, 0xca, 0x62, 0x1e, + 0xd3, 0xdf, 0xf9, 0x4a, 0xda, 0x34, 0x42, 0x49, 0xd5, 0x16, 0x69, 0x4f, + 0x21, 0x89, 0xf4, 0x74, 0xb1, 0xd8, 0x3a, 0xf3, 0x44, 0x80, 0x1c, 0x06, + 0x1a, 0xe3, 0xc8, 0x0d, 0x95, 0x03, 0x39, 0x5a, 0xb6, 0xc8, 0x20, 0x72, + 0x2a, 0xc0, 0xad, 0x92, 0x7c, 0xc1, 0xcf, 0xee, 0x68, 0x14, 0xde, 0x35, + 0x96, 0x1d, 0x58, 0x54, 0x9f, 0x8f, 0xf1, 0xfb, 0xfc, 0x64, 0xba, 0xbd, + 0x01, 0x01, 0x78, 0xb7, 0x97, 0xcc, 0x59, 0x82, 0x8e, 0x76, 0x2e, 0xa5, + 0x68, 0x73, 0x3f, 0x48, 0xb7, 0xbf, 0xf7, 0x7f, 0x57, 0x56, 0x9c, 0xc7, + 0xcc, 0xe8, 0x85, 0xdb, 0x2f, 0x52, 0xa1, 0xfe, 0x22, 0x99, 0xcf, 0xa4, + 0xd8, 0xc8, 0xc5, 0xa0, 0x25, 0xbf, 0x5c, 0x9f, 0x1a, 0x85, 0x6e, 0x56, + 0xa7, 0x5e, 0x3e, 0x86, 0xfa, 0x2f, 0xa2, 0x17, 0xed, 0x64, 0xce, 0x5c, + 0xce, 0x7c, 0x09, 0x5a, 0xe3, 0x41, 0x2a, 0x57, 0x15, 0xd7, 0xac, 0xd9, + 0x24, 0x98, 0xb3, 0x2b, 0x03, 0x0e, 0x2b, 0x8f, 0x28, 0xe0, 0x70, 0x6d, + 0x7a, 0xeb, 0xb2, 0x6b, 0xcb, 0x0e, 0x1a, 0x44, 0xed, 0x9b, 0x3a, 0x5c, + 0xee, 0x60, 0x37, 0xcf, 0xb4, 0xa4, 0x38, 0x4b, 0xf1, 0x2e, 0xa6, 0xee, + 0x7e, 0xa2, 0x61, 0x25, 0x89, 0x10, 0x84, 0xa3, 0x9b, 0x30, 0x6d, 0x62, + 0x9a, 0x64, 0x62, 0x82, 0xcd, 0xfc, 0xf2, 0x47, 0x50, 0x8c, 0x41, 0x18, + 0x58, 0x81, 0x3e, 0x32, 0xc7, 0x04, 0xd6, 0x2c, 0xb0, 0x5a, 0x85, 0x80, + 0x09, 0x76, 0xba, 0x90, 0xe2, 0x2b, 0xc3, 0x32, 0xf0, 0xe5, 0xed, 0xdc, + 0x55, 0x39, 0xd2, 0xab, 0x4b, 0xc6, 0x19, 0xfb, 0xbe, 0xf9, 0xc0, 0x4a, + 0x92, 0x18, 0x46, 0x5c, 0x77, 0xf5, 0x7f, 0xac, 0x11, 0xdb, 0x9c, 0x53, + 0xf1, 0xd9, 0x5f, 0xb1, 0x04, 0x3f, 0x75, 0x26, 0xab, 0x22, 0xd8, 0x1e, + 0x9e, 0x1e, 0x30, 0x73, 0x54, 0xad, 0x3e, 0x66, 0x94, 0x94, 0x55, 0xe7, + 0xc7, 0x51, 0x3e, 0xa6, 0x91, 0x52, 0x02, 0x56, 0xba, 0xed, 0x4a, 0x60, + 0x3a, 0x2b, 0x3e, 0xc4, 0xce, 0xd0, 0xf9, 0xd7, 0x47, 0x06, 0x92, 0x5a, + 0x78, 0x90, 0x8a, 0x09, 0x53, 0x17, 0x4d, 0xf2, 0x5c, 0x6d, 0x3c, 0xad, + 0x8a, 0xe3, 0x31, 0xe8, 0xfd, 0x00, 0xdb, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x61, 0x6b, 0x1c, 0xfb, 0xd0, 0x84, 0xfc, 0xf6, 0xdf, 0x84, + 0xc7, 0x3d, 0x97, 0x62, 0x33, 0x4b, 0x7a, 0x73, 0x32, 0x97, 0xda, 0xe4, + 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xee, 0x00, 0x0f, 0x77, 0x0e, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x0b, 0x34, 0x34, 0x34, + 0x15, 0x34, 0x08, 0x34, 0x33, 0x09, 0x01, 0x83, 0xdc, 0xc4, 0xea, 0x61, + 0x0c, 0x2a, 0x01, 0x7c, 0xca, 0x21, 0x9c, 0x02, 0x33, 0xbe, 0xd8, 0x0b, + 0x56, 0xcb, 0x20, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, + 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0xc8, + 0xed, 0x75, 0x5e, 0xc0, 0x39, 0x77, 0x37, 0x43, 0x09, 0x0d, 0x45, 0x28, + 0xbb, 0x76, 0xf1, 0xc5, 0x1c, 0xff, 0xec, 0x68, 0x74, 0x74, 0x70, 0xd0, + 0x0b, 0x39, 0x81, 0x5c, 0x18, 0x7d, 0x83, 0x2c, 0xef, 0x32, 0x39, 0xeb, + 0x7a, 0x77, 0x58, 0x07, 0x28, 0xdc, 0x47, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, + 0xd8, 0x07, 0x09, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x08, 0x81, + 0x07, 0x0b, 0x34, 0x34, 0x34, 0x15, 0x34, 0x08, 0x34, 0x33, 0x09, 0x01, + 0x83, 0xdc, 0xc4, 0xea, 0x61, 0x0c, 0x2a, 0x01, 0x7c, 0xca, 0x21, 0x9c, + 0x02, 0x33, 0xbe, 0xd8, 0x0b, 0x56, 0xcb, 0x20, 0xda, 0x39, 0xa3, 0xee, + 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09, 0xc8, 0xed, 0x75, 0x5e, 0xc0, 0x39, 0x77, 0x37, + 0x43, 0x09, 0x0d, 0x45, 0x28, 0xbb, 0x76, 0xf1, 0xc5, 0x1c, 0xff, 0xec, + 0x68, 0x74, 0x70, 0x73, 0xd0, 0x0b, 0x39, 0x81, 0x5c, 0x18, 0x7d, 0x83, + 0x2c, 0xef, 0x32, 0x39, 0xeb, 0x7a, 0x77, 0x58, 0x07, 0x28, 0xdc, 0x47, + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, + 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x66, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x09, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x01, 0x0f, 0xfb, 0x00, 0x0f, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x01, 0x06, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xce, 0x00, + 0x0f, 0xe7, 0x0f, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x34, 0x01, 0x1d, 0x3d, + 0x99, 0x45, 0x23, 0x73, 0xf5, 0xb8, 0xec, 0x97, 0xe1, 0xc2, 0x84, 0xee, + 0xec, 0xa3, 0xbc, 0x53, 0xf3, 0xcd, 0x09, 0x18, 0x03, 0x34, 0x01, 0x1c, + 0xfb, 0xd0, 0x84, 0xfc, 0xf6, 0xdf, 0x84, 0xc7, 0x3d, 0x97, 0x62, 0x33, + 0x4b, 0x7a, 0x73, 0x32, 0x97, 0xda, 0xe4, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +unsigned int ios8_inet_keychain_2_db_len = 118784; diff --git a/keychain/securityd/Regressions/sd-10-policytree.m b/keychain/securityd/Regressions/sd-10-policytree.m new file mode 100644 index 00000000..43a435a5 --- /dev/null +++ b/keychain/securityd/Regressions/sd-10-policytree.m @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009,2012 Apple Inc. All Rights Reserved. + */ + +#include "trust/trustd/policytree.h" + +#include +#include +#include + +#include "securityd_regressions.h" + +#define DUMP_POLICY_TREE 0 + +int verbose = DUMP_POLICY_TREE; + +static bool randomly_add_children(policy_tree_t node, void *ctx) { + int i, count; + uint32_t rnd = arc4random(); +#if 1 + count = rnd % 7; + if (count > 4) + count = 0; +#else + if (rnd < 0x40000000) { + count = 1; + } else if (rnd < 0x80000000) { + count = 2; + } else if (rnd < 0xc0000000) { + count = 3; + } else if (rnd < 0xf0000000) { + count = 4; + } else { + count = 0; + } +#endif + +#if DUMP_POLICY_TREE + diag("node %p add %d children", node, count); +#endif + for (i = 1; i <= count ; ++i) { + policy_tree_add_child(node, &oidAnyPolicy, NULL); + //diag("node %p %d/%d children added", node, i, count); + //policy_tree_dump(node); + } + return count != 0; +} + +static void tests(void) +{ + policy_qualifier_t p_q = NULL; + policy_tree_t tree; + ok(tree = policy_tree_create(&oidAnyPolicy, p_q), + "create tree root"); + if (verbose) policy_tree_dump(tree); + +#if 0 + int i, count = 4; + for (i = 1; i <= count ; ++i) { + policy_tree_add_child(tree, &oidAnyPolicy, NULL); +#if DUMP_POLICY_TREE + diag("node %p %d/%d children added", tree, i, count); +#endif + } + policy_tree_dump(tree); +#else + int depth; + for (depth = 0; tree && depth < 7; ++depth) { + bool added = false; + while (!added) { + added = policy_tree_walk_depth(tree, depth, + randomly_add_children, NULL); +#if DUMP_POLICY_TREE + diag("depth: %d %s", depth, + (added ? "added children" : "no children added")); +#endif + } + if (verbose) policy_tree_dump(tree); +#if DUMP_POLICY_TREE + diag("prune_childless depth: %d", depth); +#endif + policy_tree_prune_childless(&tree, depth); + if (verbose) { + if (tree) + policy_tree_dump(tree); + else { +#if DUMP_POLICY_TREE + diag("tree empty at depth: %d", depth); +#endif + break; + } + } + } +#endif + if (tree) + policy_tree_prune(&tree); +} + +int sd_10_policytree(int argc, char *const *argv) +{ + plan_tests(1); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-01-items.m b/keychain/securityd/Regressions/secd-01-items.m new file mode 100644 index 00000000..a84b48b5 --- /dev/null +++ b/keychain/securityd/Regressions/secd-01-items.m @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include "secd_regressions.h" + +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemServer.h" + +#include +#include + +#include + +#include "SecdTestKeychainUtilities.h" + +#if USE_KEYSTORE +#include "OSX/utilities/SecAKSWrappers.h" + +int secd_01_items(int argc, char *const *argv) +{ + plan_tests(24 + kSecdTestSetupTestCount); + + secd_test_setup_testviews(); // if running all tests get the test views setup first + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_01_items", NULL); + + /* custom keybag */ + keybag_handle_t keybag; + keybag_state_t state; + char *passcode="password"; + int passcode_len=(int)strlen(passcode); + + ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(keybag); + + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + + + SecKeychainDbReset(NULL); + + /* Creating a password */ + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + const void *keys[] = { + kSecClass, + kSecAttrServer, + kSecAttrAccount, + kSecAttrPort, + kSecAttrProtocol, + kSecAttrAuthenticationType, + kSecReturnData, + kSecValueData + }; + const void *values[] = { + kSecClassInternetPassword, + CFSTR("members.spamcop.net"), + CFSTR("smith"), + eighty, + CFSTR("http"), + CFSTR("dflt"), + kCFBooleanTrue, + pwdata + }; + + CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + + + is_status(SecItemAdd(item, NULL), errSecInteractionNotAllowed, "add internet password while locked"); + + /* unlock */ + ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "unlock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + + ok_status(SecItemAdd(item, NULL), "add internet password, while unlocked"); + + + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + + is_status(SecItemAdd(item, NULL), errSecInteractionNotAllowed, + "add internet password again, while locked"); + + /* unlock */ + ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "unlock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + + is_status(SecItemAdd(item, NULL), errSecDuplicateItem, + "add internet password again, while unlocked"); + + CFTypeRef results = NULL; + /* Create a dict with all attrs except the data. */ + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + (array_size(keys)) - 1, NULL, NULL); + ok_status(SecItemCopyMatching(query, &results), "find internet password, while unlocked "); + if (results) { + CFRelease(results); + results = NULL; + } + + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + + is_status(SecItemCopyMatching(query, &results), errSecInteractionNotAllowed, "find internet password, while locked "); + + /* Reset keybag and custom $HOME */ + SecItemServerResetKeychainKeybag(); + SetCustomHomePath(NULL); + SecKeychainDbReset(NULL); + + + CFReleaseNull(pwdata); + CFReleaseNull(eighty); + CFReleaseSafe(item); + CFReleaseSafe(query); + + return 0; +} + +#else + +int secd_01_items(int argc, char *const *argv) +{ + plan_tests(1); + + todo("Not yet working in simulator"); + +TODO: { + ok(false); +} + + /* not implemented in simulator (no keybag) */ + return 0; +} +#endif + diff --git a/keychain/securityd/Regressions/secd-02-upgrade-while-locked.m b/keychain/securityd/Regressions/secd-02-upgrade-while-locked.m new file mode 100644 index 00000000..e57931b1 --- /dev/null +++ b/keychain/securityd/Regressions/secd-02-upgrade-while-locked.m @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "secd_regressions.h" + +#include "keychain/securityd/SecDbItem.h" +#include +#include +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#if TARGET_OS_IPHONE && USE_KEYSTORE +#include "OSX/utilities/SecAKSWrappers.h" + +#include "SecdTestKeychainUtilities.h" + +#include "ios6_1_keychain_2_db.h" + +static OSStatus query_one(void) +{ + OSStatus ok; + + /* querying a password */ + const void *keys[] = { + kSecClass, + kSecAttrAccessGroup, + }; + const void *values[] = { + kSecClassGenericPassword, + CFSTR("test"), + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + CFTypeRef results = NULL; + + ok = SecItemCopyMatching(query, &results); + + CFReleaseSafe(results); + CFReleaseSafe(query); + + return ok; +} + + + +static void *do_query(void *arg) +{ + /* querying a password */ + const void *keys[] = { + kSecClass, + kSecAttrAccessGroup, + }; + const void *values[] = { + kSecClassGenericPassword, + CFSTR("test"), + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + CFTypeRef results = NULL; + + for(int i=0;i<20;i++) + verify_action(SecItemCopyMatching(query, &results)==errSecInteractionNotAllowed, CFReleaseSafe(query); return (void *)-1); + + CFReleaseSafe(query); + + return NULL; +} + +static void *do_sos(void *arg) +{ + + for(int i=0;i<20;i++) + verify_action(SOSCCThisDeviceIsInCircle_Server(NULL)==-1, return (void *)-1); + + return NULL; +} + + +#define N_THREADS 10 + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(void); + +int secd_02_upgrade_while_locked(int argc, char *const *argv) +{ + plan_tests(11 + N_THREADS + kSecdTestSetupTestCount); + + __block keybag_handle_t keybag; + __block keybag_state_t state; + char *passcode="password"; + int passcode_len=(int)strlen(passcode); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_02_upgrade_while_locked", ^{ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + writeFile(keychain_path, ios6_1_keychain_2_db, ios6_1_keychain_2_db_len); + + /* custom notification */ + SecItemServerSetKeychainChangedNotification("com.apple.secdtests.keychainchanged"); + + /* Create and lock custom keybag */ + ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(keybag); + + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + }); + + CFReleaseSafe(keychain_path_cf); + }); + + CFArrayRef old_ag = CFRetainSafe(SecAccessGroupsGetCurrent()); + CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); + CFArrayAppendValue(test_ag, CFSTR("test")); + SecAccessGroupsSetCurrent(test_ag); + + pthread_t query_thread[N_THREADS]; + pthread_t sos_thread; + void *query_err[N_THREADS] = {NULL,}; + void *sos_err = NULL; + + for(int i=0; i +#include +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" + +#include + +#include + +#include +#include +#include +#include + +#include "SecdTestKeychainUtilities.h" + +static OSStatus do_query(void) +{ + /* querying a password */ + const void *keys[] = { + kSecClass, + kSecAttrServer, + kSecReturnAttributes, + }; + const void *values[] = { + kSecClassInternetPassword, + CFSTR("corrupt.spamcop.net"), + kCFBooleanTrue, + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + CFTypeRef results = NULL; + + OSStatus err = SecItemCopyMatching(query, &results); + CFReleaseNull(query); + return err; +} + +static void *do_add(void *arg) +{ + int tid=(int)(arg); + + for(int i=0;i<20;i++) { + /* Creating a password */ + SInt32 v_eighty = (tid+1)*1000+i; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + const void *keys[] = { + kSecClass, + kSecAttrServer, + kSecAttrAccount, + kSecAttrPort, + kSecAttrProtocol, + kSecAttrAuthenticationType, + kSecValueData + }; + const void *values[] = { + kSecClassInternetPassword, + CFSTR("members.spamcop.net"), + CFSTR("smith"), + eighty, + CFSTR("http"), + CFSTR("dflt"), + pwdata + }; + + CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + + ok_status(SecItemAdd(item, NULL), "add internet password"); + CFReleaseNull(item); + CFReleaseNull(eighty); + CFReleaseNull(pwdata); + } + + return NULL; +} + + +#define N_THREADS 10 + +static const char *corrupt_item_sql = "UPDATE inet SET data=X'12345678' WHERE rowid=1"; + + +int secd_03_corrupted_items(int argc, char *const *argv) +{ + plan_tests(4 + N_THREADS*21 + kSecdTestSetupTestCount); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_03_corrupted_items", NULL); + + /* add a password */ + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrServer, CFSTR("corrupt.spamcop.net")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); + CFDictionaryAddValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "add internet password"); + + /* corrupt the password */ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + /* Create a new keychain sqlite db */ + sqlite3 *db; + + is(sqlite3_open(keychain_path, &db), SQLITE_OK, "create keychain"); + is(sqlite3_exec(db, corrupt_item_sql, NULL, NULL, NULL), SQLITE_OK, + "corrupting keychain item1"); + + }); + + pthread_t add_thread[N_THREADS]; + void *add_err[N_THREADS] = {NULL,}; + + for(int i=0; i +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" + +#include + +#include + +#include +#include +#include +#include + +#include "SecdTestKeychainUtilities.h" + +/* Corrupt 1st and 3rd item */ +static const char *corrupt_item_sql = "UPDATE inet SET data=X'12345678' WHERE rowid=1 OR rowid=3"; + +int secd_04_corrupted_items(int argc, char *const *argv) +{ + plan_tests(11 + kSecdTestSetupTestCount); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_04_corrupted_items", NULL); + + /* add a password */ + CFTypeRef ref1 = NULL; + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrServer, CFSTR("corrupt.spamcop.net")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); + CFDictionaryAddValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); + CFDictionaryAddValue(query, kSecValueData, pwdata); + CFDictionaryAddValue(query, kSecReturnPersistentRef, kCFBooleanTrue); + ok_status(SecItemAdd(query, &ref1), "add internet password port 80"); + + /* add another one */ + CFTypeRef ref2 = NULL; + int v_eighty_one = 81; + CFNumberRef eighty_one = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty_one); + CFDictionarySetValue(query, kSecAttrPort, eighty_one); + ok_status(SecItemAdd(query, &ref2), "add internet password port 81"); + + /* add another one */ + CFTypeRef ref3 = NULL; + int v_eighty_two = 82; + CFNumberRef eighty_two = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty_two); + CFDictionarySetValue(query, kSecAttrPort, eighty_two); + ok_status(SecItemAdd(query, &ref3), "add internet password port 82"); + + /* remove the data, and return key from the query */ + CFDictionaryRemoveValue(query, kSecValueData); + CFDictionaryRemoveValue(query, kSecReturnPersistentRef); + + /* update second password to conflict with first one */ + CFDictionarySetValue(query, kSecAttrPort, eighty_one); + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(attributes, kSecAttrPort, eighty); + is_status(SecItemUpdate(query, attributes), errSecDuplicateItem, "update internet password port 80 to 81"); + + /* corrupt the first and 3rd password */ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + /* Create a new keychain sqlite db */ + sqlite3 *db; + + is(sqlite3_open(keychain_path, &db), SQLITE_OK, "open keychain"); + is(sqlite3_exec(db, corrupt_item_sql, NULL, NULL, NULL), SQLITE_OK, + "corrupting keychain items"); + + }); + + /* Try the update again */ + ok_status(SecItemUpdate(query, attributes), "update internet password port 80 to 81 (after corrupting item)"); + + /* query the persistent ref */ + CFTypeRef ref = NULL; + CFDictionarySetValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecReturnPersistentRef, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &ref), "Item 80 found"); + + CFDictionaryRemoveValue(query, kSecReturnPersistentRef); + ok(CFEqual(ref, ref2), "persistent ref of item 2"); + + CFReleaseNull(attributes); + + /* Update the 3rd item (82) */ + CFDictionarySetValue(query, kSecAttrPort, eighty_two); + + attributes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(attributes, kSecAttrLabel, CFSTR("This is the 3rd password")); + is_status(SecItemUpdate(query, attributes), errSecItemNotFound, "update internet password port 82 (after corrupting item)"); + + CFDictionarySetValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "re-adding internet password port 82 (after corrupting item)"); + CFReleaseNull(pwdata); + CFReleaseNull(attributes); + CFReleaseNull(query); + CFReleaseNull(eighty); + CFReleaseNull(eighty_one); + CFReleaseNull(eighty_two); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-05-corrupted-items.m b/keychain/securityd/Regressions/secd-05-corrupted-items.m new file mode 100644 index 00000000..7e190934 --- /dev/null +++ b/keychain/securityd/Regressions/secd-05-corrupted-items.m @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + + +#import "secd_regressions.h" + +#import +#import "keychain/securityd/SecDbItem.h" +#import +#import +#import +#import + +#import "keychain/securityd/SecItemServer.h" + +#import + +#import + +#import +#import +#import +#import + +#import "SecdTestKeychainUtilities.h" + +#define N_ITEMS (100) +#define N_THREADS (10) +#define N_ADDS (20) + +static void *do_add(void *arg) +{ + int tid=(int)(arg); + + for(int i=0;i +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include +#include + +#include "secd_regressions.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static void tests(void) +{ + + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFSetRef initialSyncViews = SOSViewCopyViewSet(kViewSetInitial); + CFMutableSetRef alwaysOnViews = SOSViewCopyViewSet(kViewSetAlwaysOn); + CFSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault); + int initialSyncViewCount = (int) CFSetGetCount(initialSyncViews); + CFReleaseNull(initialSyncViews); + CFSetRef backupSyncViews = SOSViewCopyViewSet(kViewSetRequiredForBackup); + int backupSyncViewCount = (int) CFSetGetCount(backupSyncViews); + CFReleaseNull(backupSyncViews); + int expectedStartupViewCount; + + if(initialSyncViewCount == 0) { + CFSetUnion(alwaysOnViews, defaultViews); + expectedStartupViewCount = (int) CFSetGetCount(alwaysOnViews); + } else { + CFMutableSetRef isViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, initialSyncViews); + CFSetUnion(isViews, backupSyncViews); + expectedStartupViewCount = (int) CFSetGetCount(isViews); + CFReleaseNull(isViews); + } + CFReleaseNull(alwaysOnViews); + CFReleaseNull(defaultViews); + + + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("AliceAccount"),CFSTR("TestType") ); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("BobAccount"),CFSTR("TestType") ); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Join circle: %@", error); + ok(SOSAccountCheckHasBeenInSync_wTxn(alice_account), "Alice account initial sync done"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + if(initialSyncViewCount > 0) { + ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); + } + CFSetRef bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); + is(CFSetGetCount(bob_viewSet), expectedStartupViewCount, "bob's initial view set should be just the initial sync and backup views"); + CFReleaseNull(bob_viewSet); + + if(initialSyncViewCount > 0) { + ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); + } + + SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); + + if(initialSyncViewCount > 0) { + bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); + is(CFSetGetCount(bob_viewSet), backupSyncViewCount, "bob's initial view set should be just the back up"); + CFReleaseNull(bob_viewSet); + } else { + ok(true, "don't mess with the total test count"); + } + bob_account = nil; + alice_account = nil; + + SOSDataSourceFactoryRelease(test_factory); + + SOSTestCleanup(); +} + +int secd_100_initialsync(int argc, char *const *argv) +{ + plan_tests(33); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-130-other-peer-views.m b/keychain/securityd/Regressions/secd-130-other-peer-views.m new file mode 100644 index 00000000..8fe1cb2c --- /dev/null +++ b/keychain/securityd/Regressions/secd-130-other-peer-views.m @@ -0,0 +1,178 @@ +// +// secd-130-other-peer-views.m +// sec +// +// Created by Mitch Adler on 7/9/16. +// +// + +#include +#include + +#include "secd_regressions.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "SecdTestKeychainUtilities.h" + +#include "SOSAccountTesting.h" + +#include "keychain/SecureObjectSync/SOSAccount.h" + +#define kAccountPasswordString ((uint8_t*) "FooFooFoo") +#define kAccountPasswordStringLen 10 + +static void tests(void) { + CFErrorRef error = NULL; + + // Unretained aliases. + CFDataRef cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFMutableDictionaryRef cfchanges = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetRef initialSyncViews = SOSViewCopyViewSet(kViewSetInitial); + int initialSyncViewCount = (int) CFSetGetCount(initialSyncViews); + CFReleaseNull(initialSyncViews); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + + CFArrayRef aView = CFArrayCreateForCFTypes(kCFAllocatorDefault, + kSOSViewPCSMasterKey, + NULL); + + CFArrayRef wifiView = CFArrayCreateForCFTypes(kCFAllocatorDefault, + kSOSViewWiFi, + NULL); + + CFArrayRef otherView = CFArrayCreateForCFTypes(kCFAllocatorDefault, + kSOSViewOtherSyncable, + NULL); + + CFArrayRef otherAndWifiViews = CFArrayCreateForCFTypes(kCFAllocatorDefault, + kSOSViewWiFi, + kSOSViewOtherSyncable, + NULL); + + is(SOSAccountPeersHaveViewsEnabled(carole_account, aView, &error), NULL, "Peer views empty (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, aView, &error), kCFBooleanFalse, "Peer views empty (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies too (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(david_account, &error), "David Applies too (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); + + is(SOSAccountPeersHaveViewsEnabled(carole_account, aView, &error), NULL, "Peer views empty (%@)", error); + CFReleaseNull(error); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 3, "See three applicants %@ (%@)", applicants, error); + CFReleaseNull(error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 5, "updates"); + + // Make all views work buy finishing initial sync. + SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); + SOSAccountPeerGotInSync_wTxn(carole_account, alice_account.peerInfo); + SOSAccountPeerGotInSync_wTxn(david_account, alice_account.peerInfo); + + int changeCount = (initialSyncViewCount) ? 4 : 1; + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), changeCount, "updates"); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, aView, &error), kCFBooleanTrue, "Peer views empty (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, wifiView, &error), kCFBooleanFalse, "Peer views empty (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountUpdateView_wTxn(alice_account, kSOSViewWiFi, kSOSCCViewEnable, &error), "Enable view (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountUpdateView_wTxn(bob_account, kSOSViewOtherSyncable, kSOSCCViewEnable, &error), "Enable view (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, wifiView, &error), kCFBooleanFalse, "Wifi view for Alice (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, otherView, &error), kCFBooleanTrue, "other view for Alice (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(alice_account, otherAndWifiViews, &error), kCFBooleanFalse, "both for Alice (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(bob_account, wifiView, &error), kCFBooleanTrue, "Wifi view for Bob (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(bob_account, otherView, &error), kCFBooleanFalse, "other view for Bob (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(bob_account, otherAndWifiViews, &error), kCFBooleanFalse, "both for Bob (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(carole_account, wifiView, &error), kCFBooleanTrue, "Wifi view for Carole (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(carole_account, otherView, &error), kCFBooleanTrue, "other view for Carole (%@)", error); + CFReleaseNull(error); + + is(SOSAccountPeersHaveViewsEnabled(carole_account, otherAndWifiViews, &error), kCFBooleanTrue, "both for Carole (%@)", error); + CFReleaseNull(error); + + CFReleaseNull(aView); + CFReleaseNull(wifiView); + CFReleaseNull(otherView); + CFReleaseNull(otherAndWifiViews); + + SOSTestCleanup(); +} + +int secd_130_other_peer_views(int argc, char *const *argv) +{ + plan_tests(72); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + secd_test_clear_testviews(); + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-154-engine-backoff.m b/keychain/securityd/Regressions/secd-154-engine-backoff.m new file mode 100644 index 00000000..e75660d4 --- /dev/null +++ b/keychain/securityd/Regressions/secd-154-engine-backoff.m @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" + +static int kTestTestCount = 10; +static int MAX_PENALTY_TIME = 32; + +struct monitor_traffic { + CFStringRef key; + int penalty_box; + int total_consecutive_attempts; + int last_write_timestamp; +}; + +static void clear_penalty(struct monitor_traffic *monitor){ + monitor->penalty_box = 0; + monitor->total_consecutive_attempts = 0; + monitor->last_write_timestamp = 0; +} +static int increase_penalty(int time){ + if(time == 32) + return time; + else if(time == 0) + return 1; + else + return (time * 2); +} + +static int decrease_penalty(int time){ + if(time == 0) + return time; + else if(time == 1) + return 0; + else + return (time/2); +} + +//calculate new penalty time based off time passed +static void calculate_new_penalty(struct monitor_traffic *monitor, int current_time){ + int difference = current_time - monitor->last_write_timestamp; + + while(difference){ + if(difference >= monitor->penalty_box * 2){ + monitor->penalty_box = decrease_penalty(monitor->penalty_box); + difference =- monitor->penalty_box *2; + } + else + break; + } +} + +static void keychain_changed_notification(struct monitor_traffic *monitor){ + clear_penalty(monitor); +} + +static void initialize_monitor(struct monitor_traffic *monitor){ + monitor->key = CFSTR("ak|alskdfj:a;lskdjf"); + monitor->penalty_box = 0; + monitor->total_consecutive_attempts = 0; + monitor->last_write_timestamp = 0; +} + +static int backoff_algorithm(CFArrayRef timestamps, struct monitor_traffic *monitor) +{ + __block int successful_writes = 0; + CFNumberRef timestamp; + + CFArrayForEachC(timestamps, timestamp) { + int current_time; + if(!CFNumberGetValue(timestamp, kCFNumberSInt32Type, ¤t_time)) + return successful_writes; + + if(monitor->last_write_timestamp == 0){ //successful default case, initially sending to another peer + successful_writes++; + } + else if(current_time == 0){ //keychain changed notification fired + keychain_changed_notification(monitor); + + } + else{ + if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts >= 4){ + monitor->penalty_box= increase_penalty(monitor->penalty_box); + monitor->total_consecutive_attempts++; + } + else if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts < 4 ){ + monitor->total_consecutive_attempts++; + if(monitor->penalty_box == 0) + successful_writes++; + } + else if((current_time - monitor->last_write_timestamp) >= (2*monitor->penalty_box)){ //we haven't written consecutively for 2* the penalty time + monitor->total_consecutive_attempts = 0; + calculate_new_penalty(monitor, current_time); + successful_writes++; + } + else if((current_time - monitor->last_write_timestamp) <= (2*monitor->penalty_box)){ //nonconsecutive write came in within the penalty time + monitor->penalty_box= increase_penalty(monitor->penalty_box); + if(monitor->last_write_timestamp != (current_time-1)) + monitor->total_consecutive_attempts = 0; + else + monitor->total_consecutive_attempts++; + } + } + if(current_time != 0) + monitor->last_write_timestamp = current_time; + } + + return successful_writes; +} + +static void tests(void) +{ + struct monitor_traffic *monitor = (struct monitor_traffic*)malloc(sizeof(struct monitor_traffic)); + initialize_monitor(monitor); + CFMutableArrayRef write_attempts = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFNumberRef timestamp = NULL; + int time; + +/* + * first test: peer continuously writes for 12 minutes + */ + for(int i = 1; i< 13; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + int successful_writes = backoff_algorithm(write_attempts, monitor); + ok(successful_writes == 5, "successfull writes should have only reached 5 minutes"); + ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should have maxed out to 32 minutes"); + + //reset monitor + initialize_monitor(monitor); + CFArrayRemoveAllValues(write_attempts); + +/* + * first test: peer continuously writes for 12 minutes, then backs off 2*(max penalty timeout) + */ + for(int i = 1; i< 13; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + time = 77; + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 109; + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + successful_writes = backoff_algorithm(write_attempts, monitor); + ok(successful_writes == 7, "successfull writes should have only reached 6"); //5 initial writes, then 1 write after enough time passes + ok(monitor->penalty_box == (MAX_PENALTY_TIME/4), "penalty box should have maxed out to 16 minutes"); + + //reset + initialize_monitor(monitor); + CFArrayRemoveAllValues(write_attempts); + +/* + * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets + */ + + for(int i = 1; i< 13; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + time = 76; //+ 32*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 108; //+ 16*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 124; //+ 8*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 132; //+ 4*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 136; //+ 2*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + time = 138; //+ 1*2 + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + + successful_writes = backoff_algorithm(write_attempts, monitor); + ok(successful_writes == 11, "successfull writes should have only reached 11"); + ok(monitor->penalty_box == 0, "penalty box should reset back to 0"); + + //reset + initialize_monitor(monitor); + CFArrayRemoveAllValues(write_attempts); + +/* + * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets + */ + + for(int i = 1; i< 13; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + time = 0; //flag that keychain changed notification fired + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + + for(int i = 1; i< 13; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + + successful_writes = backoff_algorithm(write_attempts, monitor); + ok(successful_writes == 10, "successfull writes should have only reached 10"); + ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should reset back to 0"); + + //reset + initialize_monitor(monitor); + CFArrayRemoveAllValues(write_attempts); + +/* + * first test: peer continuously writes for 5 minutes, then attempts to write again for another 5 minutes, the once much later + */ + for(int i = 1; i< 6; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + time = 40; + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + + for(int i = 100; i< 106; i++){ + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i); + CFArrayAppendValue(write_attempts, timestamp); + CFReleaseNull(timestamp); + } + time = 250; + timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time); + CFArrayAppendValue(write_attempts, timestamp); + + successful_writes = backoff_algorithm(write_attempts, monitor); + ok(successful_writes == 12, "successfull writes should have only reached 10"); + ok(monitor->penalty_box == 0, "penalty box should reset back to 0"); +} + +int secd_154_engine_backoff(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m b/keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m new file mode 100644 index 00000000..446afdce --- /dev/null +++ b/keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m @@ -0,0 +1,171 @@ +// +// secd-155-otrnegotiationmonitor.m +// secdtests_ios +// +// Created by Michelle Auricchio on 6/5/17. +// + +#import +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#include "keychain/SecureObjectSync/SOSTransportMessage.h" +#include "keychain/SecureObjectSync/SOSPeerOTRTimer.h" + +#import "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" +#include "SOSTestDevice.h" +#include "SOSTestDataSource.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + + +static void tests(void) +{ + CFErrorRef error = NULL; + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(NULL != alice_account, "Alice Created"); + ok(NULL != bob_account, "Bob Created"); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL); + SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL; + + ok(false == SOSEngineHandleCodedMessage(alice_account, alice_engine, (__bridge CFStringRef)bob_account.peerID, NULL, NULL)); + + SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL); + SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL; + + ok(false == SOSEngineHandleCodedMessage(bob_account, bob_engine, (__bridge CFStringRef)alice_account.peerID, NULL, NULL)); + + /* new routines to test */ + __block NSString *bobID = bob_account.peerID; + __block NSString *aliceID = alice_account.peerID; + + SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID)); + ok(false == SOSPeerTimerForPeerExist(alice_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID)); + }); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + }); + + //creating test devices + CFIndex version = 0; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFReleaseNull(views); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + + if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ + alice_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); + } + else{ + bob_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); + } + + CFReleaseNull(device); + } + CFReleaseNull(deviceIDs); + CFReleaseNull(peerMetas); + + SOSUnregisterAllTransportMessages(); + CFArrayRemoveAllValues(message_transports); + + ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); + + ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); + + // ids_test_sync(alice_account, bob_account); +} + +int secd_155_otr_negotiation_monitor(int argc, char *const *argv) +{ + plan_tests(44); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-156-timers.m b/keychain/securityd/Regressions/secd-156-timers.m new file mode 100644 index 00000000..f63e2dd2 --- /dev/null +++ b/keychain/securityd/Regressions/secd-156-timers.m @@ -0,0 +1,100 @@ +// +// secd-156-timers.m +// secdRegressions +// + +#import + +#include +#include + +#include +#include +#include + +#include "secd_regressions.h" +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 3; + + +static void testPeerRateLimiterSendNextMessageWithRetain(CFStringRef peerid, CFStringRef accessGroup) +{ + ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); +} + +static void testOTRTimer() +{ + dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); + + CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); + dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-otrtimer2", DISPATCH_QUEUE_SERIAL); + __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); + + dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer2, ^{ + testPeerRateLimiterSendNextMessageWithRetain(peeridRetained, CFSTR("NoAttribute")); + dispatch_semaphore_signal(sema2); + }); + dispatch_resume(timer2); + dispatch_source_set_cancel_handler(timer2, ^{ + CFReleaseSafe(peeridRetained); + }); + + CFReleaseNull(peeridRetained); + dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); + +} + +static void testOTRTimerWithRetain(CFStringRef peerid) +{ + ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); +} + +static void testRateLimitingTimer() + +{ + dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); + + CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); + + dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-ratelimit12", DISPATCH_QUEUE_SERIAL); + __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); + + dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer2, ^{ + testOTRTimerWithRetain(peeridRetained); + dispatch_semaphore_signal(sema2); + }); + dispatch_resume(timer2); + + dispatch_source_set_cancel_handler(timer2, ^{ + CFReleaseSafe(peeridRetained); + }); + + CFReleaseNull(peeridRetained); + dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); + +} +static void tests(){ + + testOTRTimer(); + testRateLimitingTimer(); +} + +int secd_156_timers(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-20-keychain_upgrade.m b/keychain/securityd/Regressions/secd-20-keychain_upgrade.m new file mode 100644 index 00000000..5bb2d5f2 --- /dev/null +++ b/keychain/securityd/Regressions/secd-20-keychain_upgrade.m @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + + +#import +#import +#import +#import +#import +#import +#import +#import +#import "keychain/securityd/SecItemServer.h" + +#import + +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" +#include "server_security_helpers.h" + +static int ckmirror_row_exists = 0; +static int ckmirror_row_callback(void* unused, int count, char **data, char **columns) +{ + ckmirror_row_exists = 1; + for (int i = 0; i < count; i++) { + if(strcmp(columns[i], "ckzone") == 0) { + is(strcmp(data[i], "ckzone"), 0, "Data is expected 'ckzone'"); + } + } + + return 0; +} + +static void +keychain_upgrade(bool musr, const char *dbname) +{ + OSStatus res; + + secd_test_setup_temp_keychain(dbname, NULL); + +#if TARGET_OS_IOS + if (musr) + SecSecuritySetMusrMode(true, 502, 502); +#endif + +#if TARGET_OS_IPHONE + /* + * Check system keychain migration + */ + + res = SecItemAdd((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"system-label-me", + (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, + (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], + }, NULL); + is(res, 0, "SecItemAdd(system)"); +#endif + + /* + * Check user keychain + */ + + res = SecItemAdd((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"user-label-me", + (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], + }, NULL); + is(res, 0, "SecItemAdd(user)"); + + NSString *keychain_path = CFBridgingRelease(__SecKeychainCopyPath()); + + // Add a row to a non-item table + /* Create a new keychain sqlite db */ + sqlite3 *db = NULL; + + is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); + is(sqlite3_exec(db, "INSERT into ckmirror VALUES(\"ckzone\", \"importantuuid\", \"keyuuid\", 0, \"asdf\", \"qwer\", \"ckrecord\", 0, 0, NULL, NULL, NULL);", NULL, NULL, NULL), SQLITE_OK, "row added to ckmirror table"); + is(sqlite3_close(db), SQLITE_OK, "close db"); + + SecKeychainDbReset(^{ + + /* Create a new keychain sqlite db */ + sqlite3 *db; + + is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "create keychain"); + is(sqlite3_exec(db, "UPDATE tversion SET minor = minor - 1", NULL, NULL, NULL), SQLITE_OK, + "\"downgrade\" keychain"); + is(sqlite3_close(db), SQLITE_OK, "close db"); + }); + +#if TARGET_OS_IPHONE + res = SecItemCopyMatching((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"system-label-me", + (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, + }, NULL); + is(res, 0, "SecItemCopyMatching(system)"); +#endif + + res = SecItemCopyMatching((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"user-label-me", + }, NULL); + is(res, 0, "SecItemCopyMatching(user)"); + + char* err = NULL; + + is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); + is(sqlite3_exec(db, "select * from ckmirror;", ckmirror_row_callback, NULL, &err), SQLITE_OK, "row added to ckmirror table"); + is(sqlite3_close(db), SQLITE_OK, "close db"); + is(ckmirror_row_exists, 1, "SQLite found a row in the ckmirror table"); + +#if TARGET_OS_IOS + if (musr) + SecSecuritySetMusrMode(false, 501, -1); +#endif +} + +int +secd_20_keychain_upgrade(int argc, char *const *argv) +{ +#if TARGET_OS_IPHONE +#define have_system_keychain_tests 2 +#else +#define have_system_keychain_tests 0 +#endif + + plan_tests((kSecdTestSetupTestCount + 5 + have_system_keychain_tests + 8) * 2); + + CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); + + NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; + [newACL addObjectsFromArray:@[ + @"com.apple.private.system-keychain", + @"com.apple.private.syncbubble-keychain", + @"com.apple.private.migrate-musr-system-keychain", + ]]; + + SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); + + keychain_upgrade(false, "secd_20_keychain_upgrade"); + keychain_upgrade(true, "secd_20_keychain_upgrade-musr"); + + SecAccessGroupsSetCurrent(currentACL); + CFReleaseNull(currentACL); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-200-logstate.m b/keychain/securityd/Regressions/secd-200-logstate.m new file mode 100644 index 00000000..55d926f9 --- /dev/null +++ b/keychain/securityd/Regressions/secd-200-logstate.m @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +// +// secd-200-logstate.c +// sec +// + +#include + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +#define HOW_MANY_MINIONS 4 + +static bool SOSArrayForEachAccount(CFArrayRef accounts, bool (^operation)(SOSAccount* account)) { + __block bool retval = true; + CFArrayForEach(accounts, ^(const void *value) { + SOSAccount* account = (__bridge SOSAccount*) value; + retval &= operation(account); + }); + return retval; +} + + +static inline void FeedChangesToMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { + FeedChangesTo(changes, master_account); + SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { + FeedChangesTo(changes, account); + return true; + }); + FeedChangesTo(changes, master_account); + +} + + +static inline bool ProcessChangesOnceMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { + bool result = FillAllChanges(changes); + FeedChangesToMasterMinions(changes, master_account, minion_accounts); + return result; +} + +static inline int ProcessChangesForMasterAndMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { + int result = 0; + bool new_data = false; + do { + new_data = ProcessChangesOnceMasterMinions(changes, master_account, minion_accounts); + ++result; + } while (new_data); + return result; +} + +static bool MakeTheBigCircle(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFErrorRef *error) { + bool retval = SOSAccountResetToOffering_wTxn(master_account, error); + if(!retval) + return retval; + ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); + retval = SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { + bool localret = SOSAccountJoinCircles_wTxn(account, error); + ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); + return localret; + }); + require_quiet(retval, errOut); + CFArrayRef applicants = SOSAccountCopyApplicants(master_account, error); + retval = SOSAccountAcceptApplicants(master_account , applicants, error); + CFReleaseNull(applicants); + ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); +errOut: + return retval; +} + + +static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef namefmt, CFStringRef data_source_name, size_t howmany) + CF_FORMAT_FUNCTION(1, 0); + +static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef name, CFStringRef data_source_name, size_t howmany) { + CFMutableArrayRef accounts = CFArrayCreateMutable(kCFAllocatorDefault, howmany, &kCFTypeArrayCallBacks); + + for(size_t i = 0; i < howmany; i++) { + CFStringRef tmpname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%ld"), name, (long)i); + SOSAccount* tmp = CreateAccountForLocalChanges(tmpname, CFSTR("TestSource")); + CFArraySetValueAtIndex(accounts, i, (__bridge const void *)(tmp)); + CFReleaseNull(tmpname); + } + return accounts; +} + +static bool AssertAllCredentialsAndUpdate(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error) { + __block bool retval = SOSAccountAssertUserCredentialsAndUpdate(master_account, user_account, user_password, error); + ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); + retval &= SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { + CFReleaseNull(*error); + return SOSAccountAssertUserCredentialsAndUpdate(account, user_account, user_password, error); + }); + CFReleaseNull(*error); + + return retval; +} + +static void timeval_delta(struct timeval *delta, struct timeval *start, struct timeval *end) { + if(end->tv_usec >= start->tv_usec) { + delta->tv_usec = end->tv_usec - start->tv_usec; + } else { + end->tv_sec--; + end->tv_usec += 1000000; + delta->tv_usec = end->tv_usec - start->tv_usec; + } + delta->tv_sec = end->tv_sec - start->tv_sec; +} + +static void reportTime(int peers, void(^action)(void)) { + struct rusage start_rusage; + struct rusage end_rusage; + struct timeval delta_utime; + struct timeval delta_stime; + + getrusage(RUSAGE_SELF, &start_rusage); + action(); + getrusage(RUSAGE_SELF, &end_rusage); + timeval_delta(&delta_utime, &start_rusage.ru_utime, &end_rusage.ru_utime); + timeval_delta(&delta_stime, &start_rusage.ru_stime, &end_rusage.ru_stime); + + diag("AccountLogState for %d peers: %ld.%06d user %ld.%06d system", peers, + delta_utime.tv_sec, delta_utime.tv_usec, + delta_stime.tv_sec, delta_stime.tv_usec); +} + +static void tests(void) +{ + NSError* ns_error = nil; + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* master_account = CreateAccountForLocalChanges(CFSTR("master"), CFSTR("TestSource")); + CFArrayRef minion_accounts = CreateManyAccountsForLocalChanges(CFSTR("minion"), CFSTR("TestSource"), HOW_MANY_MINIONS); + + ok(AssertAllCredentialsAndUpdate(changes, master_account, minion_accounts, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + + secLogEnable(); + reportTime(1, ^{ + SOSAccountLogState(master_account); + }); + secLogDisable(); + + ok(MakeTheBigCircle(changes, master_account, minion_accounts, &error), "Get Everyone into the circle %@", error); + + diag("WHAT?"); + secLogEnable(); + reportTime(HOW_MANY_MINIONS+1, ^{ + SOSAccountLogState(master_account); + }); + SOSAccountLogViewState(master_account); + secLogDisable(); + + NSData* acctData = [master_account encodedData:&ns_error]; + diag("Account DER Size is %lu for %d peers", (unsigned long)[acctData length], HOW_MANY_MINIONS+1); + ns_error = nil; + + SOSAccountTrustClassic* trust = master_account.trust; + CFDataRef circleData = SOSCircleCopyEncodedData(trust.trustedCircle, kCFAllocatorDefault, &error); + diag("Circle DER Size is %ld for %d peers", CFDataGetLength(circleData), HOW_MANY_MINIONS+1); + CFReleaseNull(circleData); + CFReleaseNull(error); + + CFDataRef peerData = SOSPeerInfoCopyEncodedData(master_account.peerInfo, kCFAllocatorDefault, &error); + diag("Peer DER Size is %ld", CFDataGetLength(peerData)); + CFReleaseNull(peerData); + CFReleaseNull(error); + + CFReleaseNull(error); + CFReleaseNull(minion_accounts); + + SOSTestCleanup(); + +} + +int secd_200_logstate(int argc, char *const *argv) +{ + plan_tests(((HOW_MANY_MINIONS+1)*10 + 1)); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-201-coders.m b/keychain/securityd/Regressions/secd-201-coders.m new file mode 100644 index 00000000..d851ca17 --- /dev/null +++ b/keychain/securityd/Regressions/secd-201-coders.m @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +// +// secd_201_coders +// sec +// + +#include + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSEngine.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" +#include "SOSTestDevice.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static void tests(void) +{ + + __block CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(cfpassword); + + CFReleaseNull(error); + ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); + CFReleaseNull(cfwrong_password); + is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountHasCompletedInitialSync(alice_account), "Alice thinks she's completed initial sync"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + //creating test devices + CFIndex version = 0; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFReleaseNull(views); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + + if([alice_account.peerID isEqual: (__bridge id) deviceID]){ + alice_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); + } + else{ + bob_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); + } + + CFReleaseNull(device); + } + CFReleaseNull(deviceIDs); + CFReleaseNull(peerMetas); + + SOSUnregisterAllTransportMessages(); + CFArrayRemoveAllValues(message_transports); + + + ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); + ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); + + alice_account = nil; + bob_account = nil; + + SOSTestCleanup(); + + + CFReleaseNull(changes); +} + +int secd_201_coders(int argc, char *const *argv) +{ + plan_tests(38); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-202-recoverykey.m b/keychain/securityd/Regressions/secd-202-recoverykey.m new file mode 100644 index 00000000..e00d57af --- /dev/null +++ b/keychain/securityd/Regressions/secd-202-recoverykey.m @@ -0,0 +1,67 @@ +// +// secd-202-recoverykey.c +// sec +// + +#import +#import + +#import + +#import + +#import +#import +#import + +#import "secd_regressions.h" +#import "SOSTestDataSource.h" +#import "SOSTestDevice.h" + +#import "SOSRegressionUtilities.h" +#import + +#import "SecdTestKeychainUtilities.h" + + +const int kTestRecoveryKeyCount = 3; + +static void testRecoveryKey(void) +{ + SecRecoveryKey *recoveryKey = NULL; + + recoveryKey = SecRKCreateRecoveryKeyWithError(@"AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW", NULL); + ok(recoveryKey, "got recovery key"); + + NSData *publicKey = SecRKCopyBackupPublicKey(recoveryKey); + ok(publicKey, "got publicKey"); +} + +const int kTestRecoveryKeyBasicNumberIterations = 100; +const int kTestRecoveryKeyBasicCount = 1 * kTestRecoveryKeyBasicNumberIterations; + +static void testRecoveryKeyBasic(void) +{ + NSString *recoveryKey = NULL; + NSError *error = NULL; + int n; + + for (n = 0; n < kTestRecoveryKeyBasicNumberIterations; n++) { + recoveryKey = SecRKCreateRecoveryKeyString(&error); + ok(recoveryKey, "SecRKCreateRecoveryKeyString: %@", error); + } +} + + +int secd_202_recoverykey(int argc, char *const *argv) +{ + plan_tests(kTestRecoveryKeyCount + kTestRecoveryKeyBasicCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + testRecoveryKeyBasic(); + + testRecoveryKey(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-21-transmogrify.m b/keychain/securityd/Regressions/secd-21-transmogrify.m new file mode 100644 index 00000000..26b900f9 --- /dev/null +++ b/keychain/securityd/Regressions/secd-21-transmogrify.m @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + + +#import +#import +#import +#import +#import +#import +#import +#import +#import "keychain/securityd/SecItemServer.h" + +#import + +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" +#include "server_security_helpers.h" + +int +secd_21_transmogrify(int argc, char *const *argv) +{ + plan_tests(kSecdTestSetupTestCount + 14); + +#if TARGET_OS_IOS + CFErrorRef error = NULL; + CFDictionaryRef result = NULL; + OSStatus res; + + CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); + + NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; + [newACL addObjectsFromArray:@[ + @"com.apple.private.system-keychain", + @"com.apple.private.syncbubble-keychain", + @"com.apple.private.migrate-musr-system-keychain", + @"com.apple.ProtectedCloudStorage", + ]]; + + SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); + + + secd_test_setup_temp_keychain("secd_21_transmogrify", NULL); + + /* + * Add to user keychain + */ + + res = SecItemAdd((CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"user-label-me", + (id)kSecValueData : [NSData dataWithBytes:"password" length:8] + }, NULL); + is(res, 0, "SecItemAdd(user)"); + + SecurityClient client = { + .task = NULL, + .accessGroups = (__bridge CFArrayRef)@[ + @"com.apple.ProtectedCloudStorage" + ], + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = true, + .uid = 502, + .inMultiUser = false, + .activeUser = 502, + }; + + is(_SecServerTransmogrifyToSystemKeychain(&client, &error), true, "_SecServerTransmogrifyToSystemKeychain: %@", error); + + CFDataRef musr = SecMUSRCreateActiveUserUUID(502); + + client.inMultiUser = true; + client.musr = musr; + + SecSecuritySetMusrMode(true, 502, 502); + + res = SecItemCopyMatching((CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"user-label-me", + (id)kSecUseSystemKeychain : (id)kCFBooleanTrue, + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + (id)kSecReturnData : @(YES) + }, (CFTypeRef *)&result); + is(res, 0, "SecItemCopyMatching(system)"); + + ok(isDictionary(result), "found item"); + if (isDictionary(result)) { + NSData *data = ((__bridge NSDictionary *)result)[@"musr"]; + ok([data isEqual:(__bridge id)SecMUSRGetSystemKeychainUUID()], "item is system keychain"); + + NSData* passwordData = [(__bridge NSDictionary*)result valueForKey:(id)kSecValueData]; + ok([passwordData isEqual:[NSData dataWithBytes:"password" length:8]], "no data found in transmogrified item"); + } else { + ok(0, "returned item is: %@", result); + } + CFReleaseNull(result); + + /* + * Check sync bubble + */ + + res = _SecItemAdd((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"pcs-label-me", + (id)kSecValueData : [NSData dataWithBytes:"some data" length:9], + }, &client, NULL, NULL); + is(res, true, "SecItemAdd(user)"); + + res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"pcs-label-me", + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + (id)kSecReturnData : @(YES), + }, &client, (CFTypeRef *)&result, &error); + is(res, true, "SecItemCopyMatching(system): %@", error); + + ok(isDictionary(result), "result is dictionary"); + ok([[(__bridge NSDictionary*)result valueForKey:(__bridge id)kSecValueData] isEqual:[NSData dataWithBytes:"some data" length:9]], "retrieved data matches stored data"); + + /* Check that data are in 502 active user keychain */ + ok (CFEqualSafe(((__bridge CFDataRef)((__bridge NSDictionary *)result)[@"musr"]), musr), "not in msr 502"); + + CFReleaseNull(result); + + + ok(_SecServerTransmogrifyToSyncBubble((__bridge CFArrayRef)@[@"com.apple.mailq.sync.xpc" ], client.uid, &client, &error), + "_SecServerTransmogrifyToSyncBubble: %@", error); + + CFReleaseNull(error); + + /* + * first check normal keychain + */ + + res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"pcs-label-me", + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + }, &client, (CFTypeRef *)&result, &error); + is(res, true, "SecItemCopyMatching(active): %@", error); + + ok(isDictionary(result), "result is dictionary"); + CFReleaseNull(result); + + SecSecuritySetMusrMode(true, 503, 503); + + /* + * then syncbubble keychain + */ + + res = _SecItemCopyMatching((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"pcs-label-me", + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + (id)kSecUseSyncBubbleKeychain : @502, + }, &client, (CFTypeRef *)&result, &error); + is(res, true, "SecItemCopyMatching(syncbubble): %@", error); + ok(isDictionary(result), "result is dictionary"); + + CFReleaseNull(result); + + SecSecuritySetMusrMode(false, 501, -1); + + SecAccessGroupsSetCurrent(currentACL); + CFReleaseNull(currentACL); + + CFRelease(musr); +#else + plan_skip_all("not support on non TARGET_OS_IOS"); +#endif + return 0; +} diff --git a/keychain/securityd/Regressions/secd-210-keyinterest.m b/keychain/securityd/Regressions/secd-210-keyinterest.m new file mode 100644 index 00000000..82e7c890 --- /dev/null +++ b/keychain/securityd/Regressions/secd-210-keyinterest.m @@ -0,0 +1,200 @@ +// +// secd-210-keyinterest.m +// Security +// +// Created by Mitch Adler on 10/31/16. +// +// + +#import + +#include "secd_regressions.h" + +#import "CKDStore.h" +#import "CKDKVSProxy.h" +#import "CKDSimulatedStore.h" +#import "CKDSimulatedAccount.h" +#import "CKDAKSLockMonitor.h" + +#include "SOSCloudKeychainConstants.h" + +@interface CKDSimulatedLockMonitor : NSObject + +@property (readwrite) BOOL unlockedSinceBoot; +@property (readwrite) BOOL locked; + +@property (weak) NSObject* listener; + ++ (instancetype) monitor; + +- (instancetype) init; + +- (void) recheck; + +- (void) notifyListener; +- (void) connectTo: (NSObject*) listener; + +- (void) lock; +- (void) unlock; + +@end + + +@implementation CKDSimulatedLockMonitor + ++ (instancetype) monitor { + return [[CKDSimulatedLockMonitor alloc] init]; +} + +- (instancetype) init { + self = [super init]; + if (self) { + _locked = true; + _unlockedSinceBoot = false; + } + + [self notifyListener]; + + return self; +} + +- (void) recheck { +} + +- (void) notifyListener { + // Take a strong reference: + __strong __typeof(self.listener) listener = self.listener; + + if (listener) { + if (self.locked) { + [listener locked]; + } else { + [listener unlocked]; + } + } +} + +- (void) connectTo: (NSObject*) listener { + self.listener = listener; + [self notifyListener]; +} + +- (void) lock { + self.locked = true; + [self notifyListener]; +} +- (void) unlock { + self.locked = false; + self.unlockedSinceBoot = true; + [self notifyListener]; +} + + +@end + +@interface UbiqitousKVSProxy (Testing) +- (void) flush; +@end + +@implementation UbiqitousKVSProxy (Testing) +- (void) flush { + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [self doAfterFlush:^{ + dispatch_semaphore_signal(sema); + }]; + + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); +} +@end + +static void tests(void) { + CKDSimulatedStore* store = [CKDSimulatedStore simulatedInterface]; + CKDSimulatedAccount* account = [[CKDSimulatedAccount alloc] init]; + CKDSimulatedLockMonitor* monitor = [CKDSimulatedLockMonitor monitor]; + + NSString * testKey = @"TestKey"; + + UbiqitousKVSProxy * proxy = [UbiqitousKVSProxy withAccount:account + store:store + lockMonitor:monitor + persistence:[NSURL fileURLWithPath:@"/tmp/kvsPersistenceTestFile"]]; + + NSDictionary* interests = @{ [NSString stringWithUTF8String:kMessageKeyParameter]:@{ @"UnlockedKeys":@[ testKey ] } }; + NSString* accountID = @"Account1"; + + dispatch_sync([proxy ckdkvsproxy_queue], ^{ + [proxy registerKeys:interests forAccount:accountID]; + }); + + is([[account extractKeyChanges] count], (NSUInteger)0, "No changes yet"); + + [store remoteSetObject:@1 forKey:testKey]; + [proxy flush]; + + is([[account extractKeyChanges] count], (NSUInteger)0, "Still none while locked"); + + [monitor unlock]; + [proxy flush]; + + is([[account extractKeyChanges] count], (NSUInteger)1, "Notified after unlock"); + + [monitor lock]; + [monitor unlock]; + [proxy flush]; + + is([[account extractKeyChanges] count], (NSUInteger)0, "lock unlock and nothing changes"); + + [store remoteSetObject:@2 forKey:testKey]; + [proxy flush]; + + { + NSDictionary *changes = [account extractKeyChanges]; + is([changes count], (NSUInteger)1, "lock, nothing changes"); + is(changes[testKey], @2, "Sent second value"); + } + + [monitor lock]; + [store remoteSetObject:@3 forKey:testKey]; + [proxy flush]; + + is([[account extractKeyChanges] count], (NSUInteger)0, "Changes to Unlocked not when locked"); + + [monitor unlock]; + [proxy flush]; + + { + NSDictionary *changes = [account extractKeyChanges]; + is([changes count], (NSUInteger)1, "Change defered to after unlock"); + is(changes[testKey], @3, "Correct value"); + } + + dispatch_sync([proxy ckdkvsproxy_queue], ^{ + [proxy registerKeys:interests forAccount:accountID]; + }); + [proxy flush]; + + is([[account extractKeyChanges] count], (NSUInteger)0, "Same interests, no new data"); + + dispatch_sync([proxy ckdkvsproxy_queue], ^{ + [proxy registerKeys:interests forAccount:@"different"]; + }); + [proxy flush]; + + { + NSDictionary *changes = [account extractKeyChanges]; + is([changes count], (NSUInteger)1, "New account, same interests, new data"); + is(changes[testKey], @3, "Latest value for new data"); + } + +} + + +int secd_210_keyinterest(int argc, char *const *argv) +{ + plan_tests(12); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-230-keybagtable.m b/keychain/securityd/Regressions/secd-230-keybagtable.m new file mode 100644 index 00000000..38107987 --- /dev/null +++ b/keychain/securityd/Regressions/secd-230-keybagtable.m @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "secd_regressions.h" + +#include "keychain/securityd/SecDbItem.h" +#include +#include +#include +#include + +#include "keychain/securityd/SecItemServer.h" + +#include +#include + +#include +#include + +#import "SecBackupKeybagEntry.h" + +#if 0 + + Add test for keybag table add SPI + Create an SPI to add a keybag to the keychain database (Keybag Table) + +// original secd_35_keychain_migrate_inet + +sudo defaults write /Library/Preferences/com.apple.security V10SchemaUpgradeTest -bool true +sudo defaults read /Library/Preferences/com.apple.security V10SchemaUpgradeTest + +#endif + +#if USE_KEYSTORE +#include "OSX/utilities/SecAKSWrappers.h" + +#include "SecdTestKeychainUtilities.h" + +static const bool kTestCustomKeybag = false; +static const bool kTestLocalKeybag = false; + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(void); + +#define kSecdTestCreateCustomKeybagTestCount 6 +#define kSecdTestLocalKeybagTestCount 1 +#define kSecdTestKeybagtableTestCount 5 +#define kSecdTestAddItemTestCount 2 + +#define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 + +// copied from si-33-keychain-backup.c +static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) +{ + keybag_handle_t handle = bad_keybag_handle; + + if (aks_create_bag(DATA_ARG(password), bag_type, &handle) == 0) { + void * keybag = NULL; + int keybag_size = 0; + if (aks_save_bag(handle, &keybag, &keybag_size) == 0) { + return CFDataCreate(kCFAllocatorDefault, keybag, keybag_size); + } + } + + return CFDataCreate(kCFAllocatorDefault, NULL, 0); +} + +static bool createCustomKeybag() { + /* custom keybag */ + keybag_handle_t keybag; + keybag_state_t state; + char *passcode="password"; + int passcode_len=(int)strlen(passcode); + const bool kTestLockedKeybag = false; + + ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(keybag); + + if (kTestLockedKeybag) { + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + } + + return true; +} + +static int keychainTestEnvironment(const char *environmentName, dispatch_block_t do_in_reset, dispatch_block_t do_in_environment) { + // + // Setup phase + // + CFArrayRef old_ag = SecAccessGroupsGetCurrent(); + CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); + CFArrayAppendValue(test_ag, CFSTR("test")); + SecAccessGroupsSetCurrent(test_ag); + + secd_test_setup_temp_keychain(environmentName, do_in_reset); + bool haveCustomKeybag = kTestCustomKeybag && createCustomKeybag(); + + // Perform tasks in the test keychain environment + if (do_in_environment) + do_in_environment(); + + // + // Cleanup phase + // + + // Reset keybag + if (haveCustomKeybag) + SecItemServerResetKeychainKeybag(); + + // Reset server accessgroups + SecAccessGroupsSetCurrent(old_ag); + CFReleaseSafe(test_ag); + // Reset custom $HOME + SetCustomHomePath(NULL); + SecKeychainDbReset(NULL); + return 0; +} + +static int addOneItemTest(NSString *account) { + /* Creating a password */ + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + + NSDictionary *item = @{ + (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassInternetPassword, + (__bridge NSString *)kSecAttrServer : @"members.spamcop.net", + (__bridge NSString *)kSecAttrAccount : account, // e.g. @"smith", + (__bridge NSString *)kSecAttrPort : @80, + (__bridge NSString *)kSecAttrProtocol : @"http", + (__bridge NSString *)kSecAttrAuthenticationType : @"dflt", + (__bridge NSString *)kSecValueData : (__bridge NSData *)pwdata + }; + + ok_status(SecItemAdd((CFDictionaryRef)item, NULL), "add internet password, while unlocked"); + CFReleaseSafe(pwdata); + return 0; +} + +static int localKeybagTest() { + const char *pass = "sup3rsekretpassc0de"; + CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); + CFDataRef keybag = create_keybag(kAppleKeyStoreAsymmetricBackupBag, password); + ok(keybag != NULL); + CFReleaseNull(keybag); + CFReleaseNull(password); + return 0; +} + +static int test_keybagtable() { + CFErrorRef error = NULL; + const char *pass = "sup3rsekretpassc0de"; + CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); + CFDataRef identifier = NULL; + CFURLRef pathinfo = NULL; + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + NSDictionary *deleteQuery = @{(__bridge NSString *)kSecAttrPublicKeyHash:(__bridge NSData *)identifier}; + ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteQuery, &error)); + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + NSDictionary *deleteAllQuery = @{(id)kSecMatchLimit: (id)kSecMatchLimitAll}; + ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteAllQuery, &error)); + + CFReleaseNull(identifier); + CFReleaseNull(pathinfo); + CFReleaseNull(password); + CFReleaseNull(error); + return 0; +} + +static void showHomeURL() { +#if DEBUG + CFURLRef homeURL = SecCopyHomeURL(); + NSLog(@"Home URL for test : %@", homeURL); + CFReleaseSafe(homeURL); +#endif +} + +int secd_230_keybagtable(int argc, char *const *argv) +{ + int testcount = kSecdTestSetupTestCount + kSecdTestKeybagtableTestCount + kSecdTestAddItemTestCount; + if (kTestLocalKeybag) + testcount += kSecdTestLocalKeybagTestCount; + if (kTestCustomKeybag) + testcount += kSecdTestCreateCustomKeybagTestCount; + plan_tests(testcount); + + dispatch_block_t run_tests = ^{ + showHomeURL(); + if (kTestLocalKeybag) + localKeybagTest(); + addOneItemTest(@"smith"); + test_keybagtable(); + addOneItemTest(@"jones"); + }; + + dispatch_block_t do_in_reset = NULL; + dispatch_block_t do_in_environment = run_tests; + + keychainTestEnvironment("secd_230_keybagtable", do_in_reset, do_in_environment); + + return 0; +} + +#else + +int secd_230_keybagtable(int argc, char *const *argv) +{ + plan_tests(1); + secLogDisable(); + + todo("Not yet working in simulator"); + + TODO: { + ok(false); + } + /* not implemented in simulator (no keybag) */ + return 0; +} +#endif diff --git a/keychain/securityd/Regressions/secd-30-keychain-upgrade.m b/keychain/securityd/Regressions/secd-30-keychain-upgrade.m new file mode 100644 index 00000000..fef6e75d --- /dev/null +++ b/keychain/securityd/Regressions/secd-30-keychain-upgrade.m @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2008,2010,2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "secd_regressions.h" + +/* TODO: This test needs to be updated. It was originally created to test upgrades from DB prior to the introduction of versionning, circa 2008. + We don't support upgrading from that old of keychain, but this test should be upgraded to test upgrades from v5 to v6 keychain, or more current + */ + +const char *create_db_sql = +"BEGIN TRANSACTION;" +"CREATE TABLE genp(cdat REAL,mdat REAL,desc BLOB,icmt BLOB,crtr INTEGER,type INTEGER,scrp INTEGER,labl BLOB,alis BLOB,invi INTEGER,nega INTEGER,cusi INTEGER,prot BLOB,acct BLOB NOT NULL DEFAULT '',svce BLOB NOT NULL DEFAULT '',gena BLOB,data BLOB,PRIMARY KEY(acct,svce));" +"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'4087574952','EnhancedVoicemail',NULL,X'34F32095A0ED6F32637629114439CE38E6FF39ADB591E761D20ED23F9FACF639258DA4F12454FD4D0189C0D39AAA9227');" +"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'TlalocNet','AirPort',NULL,X'52E24441994D93D18F344DDF6A7F1F6EC43A63BCEB5F89B02FEBEEAAE108BB4933EAE73A0FB615F693C70BCFBCF034BE74BDF0280ECBEB357EEFA3B7EF03060B');" +"INSERT INTO \"genp\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'weasels','AirPort',NULL,X'3FAD49851913382FBC92C9EB90D90D82A74B1DABB5F726648898B2FA2FBA405AA0B9D95D9837BBFF0F9B7C29954973249AA066F9F8AA68D79552970C687A7DA6');" +"CREATE TABLE inet(cdat REAL,mdat REAL,desc BLOB,icmt BLOB,crtr INTEGER,type INTEGER,scrp INTEGER,labl BLOB,alis BLOB,invi INTEGER,nega INTEGER,cusi INTEGER,prot BLOB,acct BLOB NOT NULL DEFAULT '',sdmn BLOB NOT NULL DEFAULT '',srvr BLOB NOT NULL DEFAULT '',ptcl INTEGER NOT NULL DEFAULT 0,atyp BLOB NOT NULL DEFAULT '',port INTEGER NOT NULL DEFAULT 0,path BLOB NOT NULL DEFAULT '',data BLOB,PRIMARY KEY(acct,sdmn,srvr,ptcl,atyp,port,path));" +"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'mb.7766@gmail.com','','imap.gmail.com','imap','',143,'',X'0029D7AFBF0000E0E386C8654070569B2DF1D7DC2D641AA29223297EC9E8AD86ED91CA6DEE3D2DA0FABD8F05DE5A7AD4CC46B134A211472B6DE50595EACAC149');" +"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'brouwer','','phonehome.apple.com','imap','',143,'',X'BB373BAE840427C5E1247540ADA559AB14DF3788906B786498A8E1CFF4B4C596634E4A4C7F9C55EA1B646163AFCDADA8');" +"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'mb.7766@gmail.com','','smtp.gmail.com','smtp','',25,'',X'042C08A4AECD3957822F531A602734F07B89DABA3BA6629ECEFE10E264C12635F83EFBB1707C6B39FB20CCE0200D8997B690FBB0B92911BFE9B2D1E05B1CD5F5');" +"INSERT INTO \"inet\" VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'brouwer','','phonehome.apple.com','smtp','',25,'',X'25B0775265ADC808B8AFB2F2602C44B13F5ECC1F04B1D5E6EAE1B803446F3A817CCF8401416FE673CE366E25FACF5C55');" +"CREATE TABLE cert(ctyp INTEGER NOT NULL DEFAULT 0,cenc INTEGER,labl BLOB,alis BLOB,subj BLOB,issr BLOB NOT NULL DEFAULT '',slnr BLOB NOT NULL DEFAULT '',skid BLOB,pkhh BLOB,data BLOB,PRIMARY KEY(ctyp,issr,slnr));" +"CREATE TABLE keys(kcls INTEGER NOT NULL DEFAULT 0,labl BLOB,alis BLOB,perm INTEGER,priv INTEGER,modi INTEGER,klbl BLOB NOT NULL DEFAULT '',atag BLOB NOT NULL DEFAULT '',crtr INTEGER NOT NULL DEFAULT 0,type INTEGER NOT NULL DEFAULT 0,bsiz INTEGER NOT NULL DEFAULT 0,esiz INTEGER NOT NULL DEFAULT 0,sdat REAL NOT NULL DEFAULT 0,edat REAL NOT NULL DEFAULT 0,sens INTEGER,asen INTEGER,extr INTEGER,next INTEGER,encr INTEGER,decr INTEGER,drve INTEGER,sign INTEGER,vrfy INTEGER,snrc INTEGER,vyrc INTEGER,wrap INTEGER,unwp INTEGER,data BLOB,PRIMARY KEY(kcls,klbl,atag,crtr,type,bsiz,esiz,sdat,edat));" +"CREATE INDEX ialis ON cert(alis);" +"CREATE INDEX isubj ON cert(subj);" +"CREATE INDEX iskid ON cert(skid);" +"CREATE INDEX ipkhh ON cert(pkhh);" +"CREATE INDEX ikcls ON keys(kcls);" +"CREATE INDEX iklbl ON keys(klbl);" +"CREATE INDEX iencr ON keys(encr);" +"CREATE INDEX idecr ON keys(decr);" +"CREATE INDEX idrve ON keys(drve);" +"CREATE INDEX isign ON keys(sign);" +"CREATE INDEX ivrfy ON keys(vrfy);" +"CREATE INDEX iwrap ON keys(wrap);" +"CREATE INDEX iunwp ON keys(unwp);" +"COMMIT;"; + +#include "SecdTestKeychainUtilities.h" + +#include "keychain/securityd/SecItemServer.h" +#include + +/* Test basic add delete update copy matching stuff. */ +static void tests(void) +{ + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_30_keychain_upgrade", ^{ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + /* Create a new keychain sqlite db */ + sqlite3 *db; + is(sqlite3_open(keychain_path, &db), SQLITE_OK, "create keychain"); + is(sqlite3_exec(db, create_db_sql, NULL, NULL, NULL), SQLITE_OK, + "populate keychain"); + + }); + + CFReleaseSafe(keychain_path_cf); + }); + + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); + CFDictionaryAddValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "add internet password"); + is_status(SecItemAdd(query, NULL), errSecDuplicateItem, + "add internet password again"); + + ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); + + ok_status(SecItemDelete(query), "Deleted the item we added"); + + CFReleaseSafe(eighty); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); + + + +} + +int secd_30_keychain_upgrade(int argc, char *const *argv) +{ + plan_tests(6 + kSecdTestSetupTestCount); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-31-keychain-unreadable.m b/keychain/securityd/Regressions/secd-31-keychain-unreadable.m new file mode 100644 index 00000000..d0f07f5e --- /dev/null +++ b/keychain/securityd/Regressions/secd-31-keychain-unreadable.m @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2008-2010,2013-2014,2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "secd_regressions.h" + +#include "keychain/securityd/SecItemServer.h" + +#include "SecdTestKeychainUtilities.h" + + +#if !(TARGET_OS_IOS && TARGET_OS_SIMULATOR) +static void setKeychainPermissions(int perm) { + CFStringRef kc_path_cf = __SecKeychainCopyPath(); + CFStringPerformWithCString(kc_path_cf, ^(const char *path) { + ok_unix(chmod(path, perm), "chmod keychain file %s to be %d", path, perm); + }); +} +#endif + +int secd_31_keychain_unreadable(int argc, char *const *argv) +{ +#if TARGET_OS_IOS && TARGET_OS_SIMULATOR + // When running on iOS device in debugger, the target usually runs + // as root, which means it has access to the file even after setting 000. + return 0; +#else + plan_tests(10 + kSecdTestSetupTestCount); + secd_test_setup_temp_keychain("secd_31_keychain_unreadable", ^{ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + int fd; + ok_unix(fd = open(keychain_path, O_RDWR | O_CREAT | O_TRUNC, 0644), + "create keychain file '%s'", keychain_path); + SKIP: { + skip("Cannot fchmod keychain file with invalid fd", 2, fd > -1); + ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_path); + ok_unix(close(fd), "close keychain file '%s'", keychain_path); + } + }); + + CFReleaseSafe(keychain_path_cf); + }); + + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); + CFDictionaryAddValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); + CFDictionaryAddValue(query, kSecValueData, pwdata); + + is_status(SecItemAdd(query, NULL), errSecNotAvailable, "Cannot add items to unreadable keychain"); + is_status(SecItemCopyMatching(query, NULL), errSecNotAvailable, "Cannot read items in unreadable keychain"); + + setKeychainPermissions(0644); + + ok_status(SecItemAdd(query, NULL), "Add internet password"); + is_status(SecItemAdd(query, NULL), errSecDuplicateItem, + "Add internet password again"); + ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); + + // For commented tests need to convince secd to let go of connections. + // Without intervention it keeps them and accesses continue to succeed. + /* + setKeychainPermissions(0); + is_status(SecItemCopyMatching(query, NULL), errSecNotAvailable, "Still cannot read items in unreadable keychain"); + + setKeychainPermissions(0644); + ok_status(SecItemCopyMatching(query, NULL), "Found the item again"); + */ + ok_status(SecItemDelete(query),"Deleted the item we added"); + + CFReleaseNull(eighty); + CFReleaseNull(pwdata); + CFReleaseNull(query); +#endif // !(TARGET_OS_IOS && TARGET_OS_SIMULATOR) + return 0; +} diff --git a/keychain/securityd/Regressions/secd-32-restore-bad-backup.m b/keychain/securityd/Regressions/secd-32-restore-bad-backup.m new file mode 100644 index 00000000..6e2f4754 --- /dev/null +++ b/keychain/securityd/Regressions/secd-32-restore-bad-backup.m @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2008-2010,2013 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "secd_regressions.h" + +#include "keychain/securityd/SecItemServer.h" + +#include "SecdTestKeychainUtilities.h" + +/* Keybag and exported plist data. */ +static const unsigned char keybag_data[] = { + 0x56, 0x45, 0x52, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, + 0x54, 0x59, 0x50, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x12, 0x3a, 0xf9, 0xcb, + 0xd8, 0x76, 0x47, 0x01, 0xaa, 0xc5, 0xcf, 0xe5, 0x14, 0xf4, 0xf2, 0x98, + 0x48, 0x4d, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x41, 0x4c, 0x54, 0x00, 0x00, 0x00, 0x14, 0xbb, 0xfd, 0xa3, 0x3e, + 0x32, 0xa7, 0x80, 0x48, 0xd1, 0x2a, 0x39, 0x4b, 0x78, 0x6b, 0x35, 0x11, + 0x27, 0x62, 0x38, 0xe4, 0x49, 0x54, 0x45, 0x52, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x27, 0x10, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0xba, 0x4e, 0xed, 0x78, 0x38, 0x4a, 0x41, 0x4c, 0x8a, 0x2f, 0x6d, 0x1c, + 0x3a, 0xc9, 0xc8, 0xad, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0b, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x75, 0x88, 0x12, 0x0f, 0xbf, 0x21, 0x6b, 0x65, 0x85, 0xd0, 0x67, 0xdf, + 0x9b, 0xd1, 0xb3, 0x40, 0x53, 0x03, 0xaf, 0xb8, 0x8f, 0xe3, 0x5c, 0x97, + 0x43, 0xdd, 0x71, 0x65, 0x27, 0xd3, 0x73, 0xeb, 0x37, 0x5b, 0x29, 0xe8, + 0xd1, 0x14, 0xfe, 0xa3, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x2b, 0x76, 0x49, 0x3c, 0xc2, 0x5c, 0x4e, 0xc8, 0x8d, 0xea, 0x9a, 0x59, + 0x11, 0x98, 0xdd, 0x40, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0a, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xee, 0x8f, 0x46, 0xd8, 0x10, 0x17, 0x6e, 0x6c, 0x63, 0xee, 0x04, 0x22, + 0xd4, 0xec, 0x7c, 0x53, 0x8f, 0x2c, 0x18, 0x8d, 0xf3, 0x86, 0xdb, 0xd6, + 0x19, 0xae, 0x1e, 0xe0, 0x45, 0xc7, 0x75, 0x13, 0x8c, 0xb3, 0x95, 0x6f, + 0x21, 0x60, 0xd2, 0x9e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x3e, 0x91, 0xc1, 0x5d, 0xb9, 0x64, 0x44, 0xb4, 0x81, 0x0f, 0xe5, 0x12, + 0xae, 0x89, 0xb5, 0x73, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x09, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xc1, 0x22, 0x1e, 0x92, 0x54, 0xc3, 0xd6, 0x04, 0xdc, 0x45, 0x3e, 0x24, + 0xf9, 0x0c, 0xbe, 0x46, 0x8a, 0x02, 0xf7, 0xfc, 0x32, 0x24, 0x6d, 0x21, + 0x57, 0x1a, 0x43, 0xd5, 0x5f, 0xda, 0x8a, 0x5a, 0x33, 0xc0, 0xc8, 0x67, + 0x37, 0x79, 0xfe, 0x57, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x4a, 0xb0, 0xd7, 0xc0, 0xfe, 0xf7, 0x42, 0x4f, 0xb2, 0xd9, 0xd8, 0x85, + 0x70, 0xea, 0x97, 0x74, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x08, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x45, 0x26, 0xb9, 0xce, 0x3f, 0x7c, 0xd9, 0xbf, 0x92, 0xb0, 0x2e, 0x93, + 0xbc, 0x85, 0xf9, 0xd8, 0xec, 0x30, 0xd2, 0x42, 0x4c, 0x9d, 0x89, 0x77, + 0xbc, 0xe3, 0x66, 0xf2, 0x23, 0x61, 0xad, 0xc7, 0xc7, 0x02, 0xb9, 0x44, + 0x3d, 0x66, 0xd1, 0x6f, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x63, 0xdc, 0x85, 0xdd, 0x5b, 0xcb, 0x49, 0x43, 0xa2, 0x23, 0x93, 0xe7, + 0xbc, 0x88, 0x67, 0x2c, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x07, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x2d, 0x80, 0xa8, 0xe6, 0x01, 0x32, 0x90, 0x06, 0x63, 0xb2, 0xaf, 0x23, + 0x29, 0xbb, 0x85, 0x2b, 0x8f, 0x03, 0x3c, 0x07, 0xf2, 0xc3, 0xff, 0x8c, + 0xe5, 0x61, 0xa0, 0xec, 0xc3, 0x53, 0x28, 0xd4, 0x98, 0x92, 0x30, 0x41, + 0xab, 0x2b, 0x7a, 0xc9, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x22, 0x05, 0x3e, 0xc4, 0x9c, 0x32, 0x48, 0x8e, 0xad, 0x25, 0xe5, 0xe1, + 0x1d, 0x05, 0xbf, 0x1c, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x06, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x2a, 0x51, 0x5a, 0x8b, 0x5c, 0x2d, 0x67, 0x49, 0x59, 0xce, 0xf6, 0x77, + 0xb0, 0x22, 0x8b, 0x53, 0x22, 0xfd, 0x5d, 0x1b, 0x6e, 0x97, 0x0c, 0xed, + 0x3a, 0xb5, 0x52, 0xe7, 0x04, 0x31, 0xf6, 0x97, 0x5c, 0x55, 0xf5, 0xcc, + 0xa9, 0xce, 0x37, 0x8c, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0xb8, 0x54, 0xc8, 0xe5, 0x40, 0xc3, 0x4f, 0x15, 0x8d, 0xda, 0xfb, 0x82, + 0x24, 0xe4, 0x84, 0xf3, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x05, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x97, 0x9d, 0xac, 0x94, 0xdc, 0x34, 0xbc, 0xea, 0x47, 0x1e, 0xf8, 0x9a, + 0x2e, 0xb9, 0x51, 0x60, 0xc7, 0xf3, 0x5f, 0x79, 0x43, 0x9e, 0xc8, 0x80, + 0xad, 0xdd, 0x86, 0x61, 0x73, 0xd1, 0xad, 0xd2, 0xc6, 0x39, 0xa6, 0x94, + 0x5f, 0x3d, 0x8e, 0x0e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x60, 0x85, 0x58, 0x0e, 0xbb, 0x91, 0x4b, 0x47, 0x84, 0xdc, 0x5a, 0x81, + 0x75, 0x9a, 0xcd, 0x99, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xba, 0x30, 0x0f, 0x71, 0x33, 0x72, 0x12, 0xeb, 0x2f, 0x30, 0x51, 0xd0, + 0x24, 0xfb, 0xba, 0x9b, 0xeb, 0x9b, 0x13, 0x22, 0xbe, 0x20, 0x1f, 0xe2, + 0xaa, 0xfe, 0x46, 0x6f, 0xe9, 0x24, 0x98, 0x74, 0x75, 0xe1, 0xe8, 0x78, + 0xe2, 0xdf, 0x1d, 0x79, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0xba, 0x02, 0xb1, 0xbf, 0x5a, 0x19, 0x47, 0xf9, 0x8e, 0x63, 0x61, 0xbb, + 0x29, 0x1b, 0x11, 0xd3, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xaa, 0x5d, 0xb4, 0x84, 0x93, 0xe9, 0x58, 0xf9, 0xe1, 0xb2, 0xcc, 0xbd, + 0xb0, 0xb5, 0xa5, 0x17, 0xe1, 0x00, 0x86, 0xbc, 0x8c, 0x66, 0x68, 0x6e, + 0x70, 0x4d, 0x65, 0xda, 0x06, 0xb6, 0x1a, 0xc1, 0x63, 0x1d, 0x72, 0xcd, + 0x86, 0x73, 0xd2, 0x94, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x3b, 0x0e, 0x79, 0xc8, 0xc9, 0xbc, 0x4b, 0x75, 0x88, 0x16, 0x89, 0xb8, + 0x69, 0x9b, 0x5e, 0xce, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xb3, 0x0a, 0x5d, 0xb2, 0x3e, 0x63, 0xb1, 0xc5, 0x02, 0xf2, 0x38, 0xbe, + 0x8b, 0xb9, 0xfa, 0x06, 0xcb, 0x41, 0x6f, 0x99, 0xe7, 0x69, 0x12, 0x5f, + 0x6e, 0xef, 0x17, 0x67, 0xe6, 0xf6, 0xe4, 0x61, 0x2b, 0x1d, 0xe7, 0x18, + 0x8a, 0x5d, 0x5f, 0x66, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x45, 0xc1, 0x1e, 0x42, 0x2f, 0xd4, 0x47, 0x56, 0xa6, 0x88, 0x3a, 0x38, + 0x07, 0x86, 0x74, 0xcd, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x92, 0xf6, 0xf2, 0xd3, 0x54, 0x02, 0xa9, 0xb3, 0x15, 0x19, 0x2a, 0x12, + 0x99, 0xb3, 0x81, 0xbc, 0x92, 0x7e, 0x5c, 0x47, 0xd3, 0x56, 0x92, 0x04, + 0xed, 0xbc, 0x5e, 0x22, 0x36, 0x6e, 0x51, 0xd4, 0xbb, 0xad, 0xaa, 0xa3, + 0xbd, 0x28, 0x90, 0x64 +}; + +static const char export_plist[] = "\ +\ +\ +\ +\ +genp\ +\ +\ +v_Data\ +\ +AwAAAAgAAAAoAAAAPjxrzgnoJYiuTfNV0OAii8Jgl8Zegkk93Dwm\ +dJo27hIyxqzTT+twzAHn0qbb+uq7IIDFbLZt9ThLJmpGuwMzXKl0\ +91YCqoT6d3zPAkSPhPwS29/LFE3hqeGsUyV9CSye3fW9A51b/+uA\ +XVD7LQdM9Xv7Def8JO9abBKW42X+l38SW0sOq34/243Hyp3q0VWT\ +XN+UojOkzAgsBxPsuHEOre0+9aOe+RzIO2R+s54YG3QaxSwhUOu/\ +DcN6raIA37BF0eOFHOlP6ZUH+NzwTWi5ycRyX833b0bMhU4M24yx\ +5Z88ysOPWZuD6oqycfo=\ +\ +v_PersistentRef\ +\ +Z2VucAAAAAAAAAA1\ +\ +\ +\ +\ +\ +"; + +/* Test backup-restore case, when item had inconsistently set pdmn attribute (due to another bug), + and mobile restore restored item with inconsistent attributes and afterwards tried SecItemUpdate() + on it, which failed, leading to the failure of the whole restore operation. + */ +static void tests(void) +{ + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_32_restore_bad_backup", ^{}); + + /* Restore keychain from plist. */ + CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, keybag_data, sizeof(keybag_data)); + CFDataRef backup = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)export_plist, sizeof(export_plist)); + ok_status(_SecKeychainRestoreBackup(backup, keybag, NULL)); + CFRelease(keybag); + CFRelease(backup); + + /* The restored item is kind of malformed (pdmn and accc attributes are inconsistent). Currently adopted way + of handling of this item is to try to handle it gracefully, this is what this test does (i.e. it checks that + it is possible to update such item). Another possibility which might be adopted in the future is dropping such + item during backup decoding. In this case, the test should be modified to check that the item does not exist + in the keychain at all. */ + + /* Try to update item with inconsistent accc and pdmn attributes. */ + CFDictionaryRef query = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), + kSecAttrService, CFSTR("test"), + NULL); + CFDictionaryRef update = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrService, CFSTR("updated-test"), + NULL); + + ok_status(SecItemUpdate(query, update)); + diag("This still fails - don't be alarmed"); + CFRelease(update); + CFRelease(query); +} + +int secd_32_restore_bad_backup(int argc, char *const *argv) +{ + plan_tests(2 + kSecdTestSetupTestCount); + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-33-keychain-backup.m b/keychain/securityd/Regressions/secd-33-keychain-backup.m new file mode 100644 index 00000000..ead14bdd --- /dev/null +++ b/keychain/securityd/Regressions/secd-33-keychain-backup.m @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include + +#include "keychain/securityd/SecKeybagSupport.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "OSX/utilities/SecAKSWrappers.h" + +#include +#include +#include +#include +#include + +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" +#include "server_security_helpers.h" + +struct test_persistent_s { + CFTypeRef persist[2]; + CFDictionaryRef query; + CFDictionaryRef query1; + CFDictionaryRef query2; + CFMutableDictionaryRef query3; + CFMutableDictionaryRef query4; +}; + +static void test_persistent(struct test_persistent_s *p) +{ + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + const void *keys[] = { + kSecClass, + kSecAttrServer, + kSecAttrAccount, + kSecAttrPort, + kSecAttrProtocol, + kSecAttrAuthenticationType, + kSecReturnPersistentRef, + kSecValueData + }; + const void *values[] = { + kSecClassInternetPassword, + CFSTR("zuigt.nl"), + CFSTR("frtnbf"), + eighty, + CFSTR("http"), + CFSTR("dflt"), + kCFBooleanTrue, + pwdata + }; + CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, + array_size(keys), &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + p->persist[0] = NULL; + // NUKE anything we might have left around from a previous test run so we don't crash. + SecItemDelete(item); + ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); + CFTypeRef results = NULL; + CFTypeRef results2 = NULL; +SKIP: { + skip("no persistent ref", 6, ok(p->persist[0], "got back persistent ref")); + + /* Create a dict with all attrs except the data. */ + keys[(array_size(keys)) - 2] = kSecReturnAttributes; + p->query = CFDictionaryCreate(NULL, keys, values, + (array_size(keys)) - 1, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + ok_status(SecItemCopyMatching(p->query, &results), "find internet password by attr"); + + const void *keys_persist[] = { + kSecReturnAttributes, + kSecValuePersistentRef + }; + const void *values_persist[] = { + kCFBooleanTrue, + p->persist[0] + }; + p->query2 = CFDictionaryCreate(NULL, keys_persist, values_persist, + (array_size(keys_persist)), &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + ok_status(SecItemCopyMatching(p->query2, &results2), "find internet password by persistent ref"); + ok(CFEqual(results, results2 ? results2 : CFSTR("")), "same item (attributes)"); + + CFReleaseNull(results); + CFReleaseNull(results2); + + ok_status(SecItemDelete(p->query), "delete internet password"); + + ok_status(!SecItemCopyMatching(p->query, &results), + "don't find internet password by attributes"); + ok(!results, "no results"); +} + + /* clean up left over from aborted run */ + if (results) { + CFDictionaryRef cleanup = CFDictionaryCreate(NULL, (const void **)&kSecValuePersistentRef, + &results, 1, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + SecItemDelete(cleanup); + CFRelease(results); + CFRelease(cleanup); + } + + ok_status(!SecItemCopyMatching(p->query2, &results2), + "don't find internet password by persistent ref anymore"); + ok(!results2, "no results"); + + CFReleaseNull(p->persist[0]); + + /* Add a new item and get it's persitant ref. */ + ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); + p->persist[1] = NULL; + CFMutableDictionaryRef item2 = CFDictionaryCreateMutableCopy(NULL, 0, item); + CFDictionarySetValue(item2, kSecAttrAccount, CFSTR("johndoe-bu")); + // NUKE anything we might have left around from a previous test run so we don't crash. + SecItemDelete(item2); + ok_status(SecItemAdd(item2, &p->persist[1]), "add second internet password"); + CFMutableDictionaryRef update = NULL; + CFStringRef server = NULL; +SKIP: { + skip("no persistent ref", 3, ok(p->persist[0], "got back persistent ref from first internet password")); + + is(CFGetTypeID(p->persist[0]), CFDataGetTypeID(), "result is a CFData"); + p->query3 = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(p->query3, kSecValuePersistentRef, p->persist[0]); + update = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(update, kSecAttrServer, CFSTR("zuigt.com")); + ok_status(SecItemUpdate(p->query3, update), "update via persitant ref"); + + /* Verify that the update really worked. */ + CFDictionaryAddValue(p->query3, kSecReturnAttributes, kCFBooleanTrue); + ok_status(SecItemCopyMatching(p->query3, &results2), "find updated internet password by persistent ref"); + server = CFDictionaryGetValue(results2, kSecAttrServer); + ok(CFEqual(server, CFSTR("zuigt.com")), "verify attribute was modified by update"); + CFReleaseNull(results2); + CFDictionaryRemoveValue(p->query3, kSecReturnAttributes); +} + +SKIP: { + skip("no persistent ref", 2, ok(p->persist[1], "got back persistent ref")); + + /* Verify that item2 wasn't affected by the update. */ + p->query4 = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(p->query4, kSecValuePersistentRef, p->persist[1]); + CFDictionaryAddValue(p->query4, kSecReturnAttributes, kCFBooleanTrue); + ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); + server = CFDictionaryGetValue(results2, kSecAttrServer); + ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); + CFReleaseNull(results2); +} + + /* Delete the item via persitant ref. */ + ok_status(SecItemDelete(p->query3), "delete via persitant ref"); + is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, + "don't find deleted internet password by persistent ref"); + CFReleaseNull(results2); + ok_status(SecItemCopyMatching(p->query4, &results2), + "find non deleted internet password by persistent ref"); + CFReleaseNull(results2); + + CFReleaseNull(update); + CFReleaseNull(item); + CFReleaseNull(item2); + CFReleaseNull(eighty); + CFReleaseNull(pwdata); +} + +static void test_persistent2(struct test_persistent_s *p) +{ + CFTypeRef results = NULL; + CFTypeRef results2 = NULL; + + ok_status(!SecItemCopyMatching(p->query, &results), + "don't find internet password by attributes"); + ok(!results, "no results"); + + ok_status(!SecItemCopyMatching(p->query2, &results2), + "don't find internet password by persistent ref anymore"); + ok(!results2, "no results"); + +SKIP:{ + ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); + skip("non updated internet password by persistent ref NOT FOUND!", 2, results2); + ok(results2, "non updated internet password not found"); + CFStringRef server = CFDictionaryGetValue(results2, kSecAttrServer); + ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); + CFReleaseNull(results2); +} + + is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, + "don't find deleted internet password by persistent ref"); + CFReleaseNull(results2); + ok_status(SecItemCopyMatching(p->query4, &results2), + "find non deleted internet password by persistent ref"); + CFReleaseNull(results2); + + ok_status(SecItemDelete(p->query4),"Deleted internet password by persistent ref"); + + CFRelease(p->query); + CFRelease(p->query2); + CFRelease(p->query3); + CFRelease(p->query4); + CFReleaseNull(p->persist[0]); + CFReleaseNull(p->persist[1]); +} + +static CFMutableDictionaryRef test_create_lockdown_identity_query(void) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("test-delete-me")); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("lockdown-identities")); + return query; +} + +static CFMutableDictionaryRef test_create_managedconfiguration_query(void) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrService, CFSTR("com.apple.managedconfiguration")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("Public")); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); + return query; +} + +static CFMutableDictionaryRef test_create_accounts_query(void) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrService, CFSTR("com.apple.account.CloudKit.token")); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); + return query; +} + +static void test_add_lockdown_identity_items(void) { + CFMutableDictionaryRef query = test_create_lockdown_identity_query(); + const char *v_data = "lockdown identity data (which should be a cert + key)"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_lockdown_identity_items"); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +static void test_remove_lockdown_identity_items(void) { + CFMutableDictionaryRef query = test_create_lockdown_identity_query(); + ok_status(SecItemDelete(query), "test_remove_lockdown_identity_items"); + CFReleaseSafe(query); +} + +static void test_no_find_lockdown_identity_item(void) { + CFMutableDictionaryRef query = test_create_lockdown_identity_query(); + is_status(SecItemCopyMatching(query, NULL), errSecItemNotFound, + "test_no_find_lockdown_identity_item"); + CFReleaseSafe(query); +} + +static CFMutableDictionaryRef test_create_sysbound_query(void) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("sysbound")); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); + return query; +} + +static void test_add_sysbound_item(void) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + int32_t val = kSecSecAttrSysBoundPreserveDuringRestore; + CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &val); + CFDictionaryAddValue(query, kSecAttrSysBound, num); + CFReleaseNull(num); + + const char *v_data = "sysbound identity data"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_sysbound_item"); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +static void test_remove_sysbound_item(void) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + ok_status(SecItemDelete(query), "test_remove_sysbound_item"); + CFReleaseSafe(query); +} + +static void test_find_sysbound_item(OSStatus expectedCode) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + is_status(SecItemCopyMatching(query, NULL), expectedCode, + "test_find_sysbound_item"); + CFReleaseSafe(query); +} + +/* + * BT + */ + +static CFMutableDictionaryRef test_create_bt_query(bool sync) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("com.apple.bluetooth")); + CFDictionaryAddValue(query, kSecAttrSynchronizable, sync ? kCFBooleanTrue : kCFBooleanFalse); + CFDictionarySetValue(query, kSecAttrAccount, sync ? CFSTR("sync") : CFSTR("non-sync")); + return query; +} + +static void test_add_bt_items(const char *data) { + CFMutableDictionaryRef query = NULL; + + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)data, strlen(data)); + + query = test_create_bt_query(false); + (void)SecItemDelete(query); + CFDictionarySetValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_bt_item(nonsync)"); + CFReleaseSafe(query); + + query = test_create_bt_query(true); + (void)SecItemDelete(query); + CFDictionarySetValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_bt_item(sync)"); + CFReleaseSafe(query); + + CFReleaseSafe(pwdata); +} + +static void test_find_bt_item(OSStatus expectedCode, bool sync, const char *data) { + CFMutableDictionaryRef query = test_create_bt_query(sync); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + CFDataRef pwdata = NULL; + is_status(SecItemCopyMatching(query, (CFTypeRef *)&pwdata), expectedCode, + "test_find_bt_item: %s", data); + CFIndex len = strlen(data); + is(len, CFDataGetLength(pwdata), "length wrong(%s)", data); + ok(memcmp(data, CFDataGetBytePtr(pwdata), len) == 0, "length wrong(%s)", data); + CFReleaseSafe(query); +} + +/* + * MC + */ + +static void test_add_managedconfiguration_item(void) { + CFMutableDictionaryRef query = test_create_managedconfiguration_query(); + const char *v_data = "public managedconfiguration password history data"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_managedconfiguration_item"); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +static void test_find_managedconfiguration_item(void) { + CFMutableDictionaryRef query = test_create_managedconfiguration_query(); + ok_status(SecItemCopyMatching(query, NULL), "test_find_managedconfiguration_item"); + ok_status(SecItemDelete(query), "test_find_managedconfiguration_item (deleted)"); + CFReleaseSafe(query); +} + +/* + * Accounts + */ + +static void test_add_accounts_item(const char *string) { + CFMutableDictionaryRef query = test_create_accounts_query(); + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)string, strlen(string)); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_accounts_item"); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +static char *test_find_accounts_item(void) { + CFMutableDictionaryRef query = test_create_accounts_query(); + CFDataRef data = NULL; + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, (CFTypeRef *)&data), "test_find_accounts_item"); + if (data == NULL) + return NULL; + ok(isData(data), "data"); + size_t len = CFDataGetLength(data); + char *str = malloc(len + 1); + memcpy(str, CFDataGetBytePtr(data), len); + str[len] = '\0'; + CFReleaseSafe(query); + CFReleaseSafe(data); + return str; +} + +static void test_delete_accounts_item(void) { + CFMutableDictionaryRef query = test_create_accounts_query(); + ok_status(SecItemDelete(query), "test_delete_accounts_item"); + CFReleaseSafe(query); +} + + + +#if USE_KEYSTORE +#define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 +static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) +{ + CFDataRef result = NULL; + void *bag = NULL; + int bagLen = 0; + + keybag_handle_t handle = bad_keybag_handle; + require_noerr(aks_create_bag(DATA_ARG(password), bag_type, &handle), out); + require_noerr(aks_save_bag(handle, &bag, &bagLen), out); + + result = CFDataCreate(kCFAllocatorDefault, bag, bagLen); + out: + return result; +} +#endif + +/* Test low level keychain migration from device to device interface. */ +static void tests(void) +{ + { + CFMutableDictionaryRef lock_down_query = test_create_lockdown_identity_query(); + (void)SecItemDelete(lock_down_query); + CFReleaseNull(lock_down_query); + } + + int v_eighty = 80; + CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); + CFDictionaryAddValue(query, kSecAttrPort, eighty); + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); + CFDictionaryAddValue(query, kSecValueData, pwdata); + // NUKE anything we might have left around from a previous test run so we don't crash. + (void)SecItemDelete(query); + + ok_status(SecItemAdd(query, NULL), "add internet password"); + is_status(SecItemAdd(query, NULL), errSecDuplicateItem, + "add internet password again"); + + ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); + + struct test_persistent_s p = {}; + test_persistent(&p); + + CFDataRef backup = NULL, keybag = NULL, password = NULL; + + test_add_lockdown_identity_items(); + test_add_sysbound_item(); + test_add_accounts_item("1"); + test_add_bt_items("kaka1"); + +#if USE_KEYSTORE + keybag = create_keybag(kAppleKeyStoreBackupBag, password); +#else + keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0); +#endif + + ok(backup = _SecKeychainCopyBackup(keybag, password), + "_SecKeychainCopyBackup"); + + test_add_managedconfiguration_item(); + test_delete_accounts_item(); + test_add_accounts_item("2"); + test_remove_lockdown_identity_items(); + test_remove_sysbound_item(); + + test_add_bt_items("kaka2"); + + ok_status(_SecKeychainRestoreBackup(backup, keybag, password), + "_SecKeychainRestoreBackup"); + CFReleaseSafe(backup); + + test_no_find_lockdown_identity_item(); + test_find_sysbound_item(errSecItemNotFound); + test_find_managedconfiguration_item(); + char *val = test_find_accounts_item(); + eq_string(val, "2", "string not 2 as expected: %s", val); + test_delete_accounts_item(); + + /* + * Check that the kaka1 entry was "overwritten" + */ + test_find_bt_item(errSecSuccess, true, "kaka2"); + test_find_bt_item(errSecSuccess, false, "kaka1"); + + ok_status(SecItemCopyMatching(query, NULL), + "Found the item we added after restore"); + + test_persistent2(&p); + +#if USE_KEYSTORE + CFReleaseNull(keybag); + keybag = create_keybag(kAppleKeyStoreOTABackupBag, password); +#endif + + ok(backup = _SecKeychainCopyBackup(keybag, password), + "_SecKeychainCopyBackup"); + ok_status(_SecKeychainRestoreBackup(backup, keybag, password), + "_SecKeychainRestoreBackup"); + ok_status(SecItemCopyMatching(query, NULL), + "Found the item we added after restore"); + CFReleaseNull(backup); + + // force tombstone to be added, since it's not the default behavior per rdar://14680869 + CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue); + + ok_status(SecItemDelete(query), "Deleted item we added"); + +#if USE_KEYSTORE + CFReleaseNull(keybag); + keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password); +#endif + + // add syncable item + CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue); + ok_status(SecItemAdd(query, NULL), "add internet password"); + + // and non-syncable item + test_add_managedconfiguration_item(); + + CFDictionaryRef syncableBackup = NULL; + + CFErrorRef error = NULL; + CFDictionaryRef scratch = NULL; +SKIP: { + skip("skipping syncable backup tests", 7, + ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items")); + + // TODO: add item, call SecServerCopyTruthInTheCloud again + + // CFShow(syncableBackup); + + // find and delete + skip("skipping syncable backup tests", 6, + ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy")); + + skip("skipping syncable backup tests", 5, + ok_status(SecItemDelete(query), "delete item we backed up")); + + // ensure we added a tombstone + CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue); + skip("skipping syncable backup tests", 4, + ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted")); + CFDictionaryRemoveValue(query, kSecAttrTombstone); + + test_find_managedconfiguration_item(); // <- 2 tests here + + // TODO: add a different new item - delete what's not in the syncableBackup? + + // Do another backup after some changes + skip("skipping syncable backup tests", 1, + ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes")); + + skip("skipping syncable backup tests", 0, + ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items")); +} + CFReleaseNull(scratch); + CFReleaseNull(error); + + // non-syncable item should (still) be gone -> add should work + test_add_managedconfiguration_item(); + test_find_managedconfiguration_item(); + + // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail + is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL), + "find restored item"); + is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item"); + + CFReleaseSafe(syncableBackup); + CFReleaseSafe(keybag); + CFReleaseSafe(eighty); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +int secd_33_keychain_backup(int argc, char *const *argv) +{ + plan_tests(85); + + CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); + + NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; + [newACL addObjectsFromArray:@[ + @"com.apple.bluetooth", + @"lockdown-identities", + @"apple", + ]]; + + SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); + + + secd_test_setup_temp_keychain("secd_33_keychain_backup", NULL); + + tests(); + + SecAccessGroupsSetCurrent(currentACL); + CFReleaseNull(currentACL); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-33-keychain-ctk.m b/keychain/securityd/Regressions/secd-33-keychain-ctk.m new file mode 100644 index 00000000..4aa765e0 --- /dev/null +++ b/keychain/securityd/Regressions/secd-33-keychain-ctk.m @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "secd_regressions.h" + +#include "SecdTestKeychainUtilities.h" +#include "SecKeybagSupport.h" + +const char *cert1 = "MIIFQzCCBCugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN8DrET5AAQ4dVIP+RD3XATFaBYpG9b2H0tV82gVGOv/t5cxOszAMxzsw7xlY/tMRrx5yz7IUUvueylHl98e7yMefP69vwqwSc4DWSELSqHOLMHd/uPLYLINIFqEW8Nq4Q02V2IxqBbiwtZeeSOqY3gQ2kiCd4cF8Itlr3UePJrlAgMBAAGjggKzMIICrzAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQg5YNVxRTOC13qs9cVUuvDIp6AH+jitdjhWJfai2bfP3QwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCGCGSAFlAwYIMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDETCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMDIGA1UdEQQrMCmgJwYIYIZIAWUDBgagGwQZ1Oc52nOc7TnOc52haFoIySreCmGE5znD4jAQBglghkgBZQMGCQEEAwEBADANBgkqhkiG9w0BAQsFAAOCAQEAVVGMeep+1wpVFdXFIXUTkxy9RjdOO3SmMGVomfVXofVOBfVzooaI+RV5UCURnoqoHYziBidxc9YKW6n9mX6p27KfrC1roHg6wu5xVEHJ93hju35g3WAXTnqNFiQpB+GU7UvJJEhkcTU2rChuYNS5SeFZ0pv1Gyzw7WjLfh9rdAPBfRg4gxpho9SMCUnI+p5KbEiptmimtPfsVq6htT3P+m2V4UXIT6sr7T6IpnPteMppsH43NKXNM6iPCkRCUPQ0d+lpfXAYGSFIzx2WesjSmrs/CHXfwmhnbrJNPCx9zlcCMmmfGcZGyufF+10wF9gv9qx+PUwi2xMKhwuKR1LoCg=="; +const char *cert2 = +"MIIFCTCCA/GgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKij0LIQlW0VKahBGF4tu/xdwGWN+KTLLGyMQmuuG+NNG+vQMSsdXD1pd00YMBiGn3sC5b+G7lQLZ85mDQfO+eI8GDjG+Sh8W8Cghku20sxZnQ+kZOLOr//R2/ZXonVaxoBR/9tBPh0MIEIVzRS8JmltZVfhkbIR6Wiox3jVEAsPAgMBAAGjggJ5MIICdTAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQga85kaqoMEaV+E04P1gZ2OUlbCbvr623fC30WhBZn3bMwDgYDVR0PAQH/BAQDAgbAMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDDTCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMCIGA1UdEQQbMBmBF2NvbW1vbl9uYW1lQHBpdmRlbW8ub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQANg1tGsgO32fVXDyRPHFeqDa0QmQ4itHrh6BAK6n94QL8383wuPDFkPy1TfVYVdYm0Gne6hyH/Z13ycw1XXNddooT7+OiYK5F1TEhfQNiRhzTqblB/yc2lv6Ho0EsOrwPhaBRaO3EFUyjeNMxsvG8Dr9Y5u2B38ESB4OsLKHq0eD/WZjEAlyGx16Qi7YlLiHGfLMorgkg9Mbp73guNO1PItDTAnqHUUOlQ01ThNug0sR5ua1zlNFx6AIPoX4yAPrtlEMZtbsevsXlgDpO1zc26p5icBmQHYT7uzdTEEN4tmcxXg6Z/dGB63GCluf+Pc+ovRt/MMt2EbcIuwJ9C516H"; +const char *cert3 = +"MIICETCCAbigAwIBAgIJANiM7uTufLiKMAkGByqGSM49BAEwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MxGjAYBgNVBAMTEUFwcGxlIFRlc3QgQ0EyIEVDMSAwHgYJKoZIhvcNAQkBFhF2a3V6ZWxhQGFwcGxlLmNvbTAeFw0xNjA1MTIxMTMyMzlaFw0yNjA1MTAxMTMyMzlaMGYxEDAOBgNVBAMTB3NldG9rZW4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQHKxfYgbqRHmThPnO9yQX5KrL/EPa6dZU52Wys5gC3/Mk0dNt9dLhpWblAVaeBzkos4juN3cxbnoB9MsC4bvoLoyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAJBgcqhkjOPQQBA0gAMEUCIQClcoYLhEA/xIGU94ZBcup26Pb7pXaWaaOM3+9z510TRwIgV/iprC051SuQzkqXA5weVliJOohFYjO+gUoH/6MJpDg="; + +extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); + +static void test_item_add(void) { + + static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; + CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); + __block NSUInteger objIDIdx = 0; + + CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrTokenID, CFSTR("tokenid"), + kSecAttrService, CFSTR("ctktest-service"), + kSecValueData, valueData, + kSecReturnAttributes, kCFBooleanTrue, + NULL); + // Setup token hook. + __block int phase = 0; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); + + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + phase++; + is(objectID, NULL); + eq_cf(CFDictionaryGetValue(at, kSecClass), kSecClassGenericPassword); + eq_cf(CFDictionaryGetValue(at, kSecAttrService), CFDictionaryGetValue(attrs, kSecAttrService)); + eq_cf(CFDictionaryGetValue(at, kSecAttrTokenID), CFSTR("tokenid")); + eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData); + CFDictionaryRemoveValue(at, kSecValueData); + ++objIDIdx; + return (__bridge_retained CFDataRef)[NSData dataWithBytes:&objIDIdx length:sizeof(objIDIdx)]; + }; + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + phase++; + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + phase++; + return CFRetain(valueData); + }; + }); + + CFTypeRef result = NULL; + ok_status(SecItemAdd(attrs, &result)); + eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service")); + eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid")); + is(CFDictionaryGetValue(result, kSecValueData), NULL); + CFReleaseNull(result); + + is(phase, 3); + + phase = 0; + CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue); + CFDictionarySetValue(attrs, kSecAttrService, CFSTR("ctktest-service1")); + ok_status(SecItemAdd(attrs, &result)); + eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service1")); + eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid")); + eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData); + CFReleaseNull(result); + + is(phase, 4); + + phase = 0; + CFDictionaryRemoveValue(attrs, kSecReturnAttributes); + CFDictionarySetValue(attrs, kSecAttrAccount, CFSTR("2nd")); + ok_status(SecItemAdd(attrs, &result)); + eq_cf(result, valueData); + CFReleaseNull(result); + is(phase, 4); + + CFRelease(attrs); + CFRelease(valueData); +} + +static void test_item_query() { + static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; + CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); + CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1); + + __block int phase = 0; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + phase++; + return CFRetain(valueData); + }; + }); + + // Add non-token item with the same service, to test queries returning mixed results. + CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrService, CFSTR("ctktest-service"), + kSecValueData, valueData2, + NULL); + ok_status(SecItemAdd(attrs, NULL)); + CFRelease(attrs); + + // Query with service. + CFMutableDictionaryRef query; + query = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrService, CFSTR("ctktest-service"), + kSecReturnAttributes, kCFBooleanTrue, + kSecReturnData, kCFBooleanTrue, + NULL); + + phase = 0; + CFTypeRef result = NULL; + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 2); + is(CFGetTypeID(result), CFDictionaryGetTypeID()); + eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData); + is(CFGetTypeID(CFDictionaryGetValue(result, kSecAttrAccessControl)), SecAccessControlGetTypeID()); + eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service")); + CFReleaseSafe(result); + + phase = 0; + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 2); + is(CFGetTypeID(result), CFArrayGetTypeID()); + is(CFArrayGetCount(result), 2); + CFReleaseSafe(result); + + phase = 0; + CFDictionaryRemoveValue(query, kSecMatchLimit); + CFDictionaryRemoveValue(query, kSecReturnData); + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 0); + is(CFGetTypeID(result), CFDictionaryGetTypeID()); + is(CFDictionaryGetValue(result, kSecValueData), NULL); + CFReleaseSafe(result); + + phase = 0; + CFDictionaryRemoveValue(query, kSecReturnAttributes); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + CFDictionarySetValue(query, kSecAttrTokenID, CFSTR("tokenid")); + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 2); + eq_cf(result, valueData); + CFReleaseSafe(result); + + static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'}; + NSData *persistentRefId = [NSData dataWithBytes:tk_persistent_ref_id length:sizeof(tk_persistent_ref_id)]; + phase = 0; + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"ctktest-service", + (id)kSecReturnPersistentRef : @YES }, &result)); + is(phase, 0); + NSData *persistentRef = (__bridge NSData *)result; + is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); + CFReleaseSafe(result); + + phase = 0; + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"ctktest-service", + (id)kSecReturnData : @YES, + (id)kSecReturnPersistentRef : @YES }, &result)); + is(phase, 2); + persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; + is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); + CFReleaseSafe(result); + + phase = 0; + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"ctktest-service", + (id)kSecReturnAttributes : @YES, + (id)kSecReturnPersistentRef : @YES }, &result)); + is(phase, 0); + persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; + is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); + CFReleaseSafe(result); + + phase = 0; + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"ctktest-service", + (id)kSecReturnData : @YES, + (id)kSecReturnAttributes : @YES, + (id)kSecReturnPersistentRef : @YES }, &result)); + is(phase, 2); + persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef]; + is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo); + CFReleaseSafe(result); + + CFRelease(query); + CFRelease(valueData); + CFRelease(valueData2); +} + +static void test_item_update() { + static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; + CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1); + CFTypeRef result = NULL; + + CFMutableDictionaryRef query, attrs; + + // Setup token hook. + __block int phase = 0; + __block bool store_value = false; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); + + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + phase++; + eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData2); + if (!store_value) { + CFDictionaryRemoveValue(at, kSecValueData); + } + return CFRetainSafe(objectID); + }; + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + phase++; + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + phase++; + return CFRetain(valueData2); + }; + }); + + query = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrTokenID, CFSTR("tokenid"), + kSecAttrService, CFSTR("ctktest-service"), + NULL); + + attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecValueData, valueData2, + NULL); + + ok_status(SecItemUpdate(query, attrs)); + is(phase, 3); + + phase = 0; + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &result)); + eq_cf(valueData2, result); + CFRelease(result); + is(phase, 2); + + phase = 0; + store_value = true; + CFDictionaryRemoveValue(query, kSecReturnData); + ok_status(SecItemUpdate(query, attrs)); + is(phase, 3); + + phase = 0; + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &result)); + eq_cf(valueData2, result); + CFRelease(result); + is(phase, 0); + + phase = 0; + CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1")); + CFDictionaryRemoveValue(query, kSecReturnData); + ok_status(SecItemUpdate(query, attrs)); + is(phase, 5); + + phase = 0; + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 0); + is(CFGetTypeID(result), CFArrayGetTypeID()); + is(CFArrayGetCount(result), 2); + eq_cf(CFArrayGetValueAtIndex(result, 0), valueData2); + eq_cf(CFArrayGetValueAtIndex(result, 1), valueData2); + + CFRelease(query); + CFRelease(attrs); + CFRelease(valueData2); +} + +static void test_item_delete(void) { + + CFMutableDictionaryRef query; + CFTypeRef result; + + __block int phase = 0; + __block CFErrorRef deleteError = NULL; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid")); + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + phase++; + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->deleteObject = ^bool(CFDataRef objectID, CFErrorRef *error) { + phase++; + if (deleteError != NULL) { + CFAssignRetained(*error, deleteError); + deleteError = NULL; + return false; + } + return true; + }; + }); + + query = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrTokenID, CFSTR("tokenid"), + kSecAttrService, CFSTR("ctktest-service"), + NULL); + + phase = 0; + ok_status(SecItemDelete(query)); + is(phase, 2); + + phase = 0; + is_status(SecItemCopyMatching(query, &result), errSecItemNotFound); + is(phase, 0); + + phase = 0; + CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1")); + ok_status(SecItemCopyMatching(query, &result)); + is(phase, 0); + + phase = 0; +#if LA_CONTEXT_IMPLEMENTED + LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; }); + deleteError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL); + ok_status(SecItemDelete(query), "delete multiple token items"); + is(phase, 6, "connect + delete-auth-fail + copyAccess + connect + delete + delete-2nd"); +#else + ok_status(SecItemDelete(query), "delete multiple token items"); + is(phase, 3, "connect + delete + delete"); +#endif + + phase = 0; + is_status(SecItemCopyMatching(query, &result), errSecItemNotFound); + is(phase, 0); + + is_status(SecItemDelete(query), errSecItemNotFound); + + CFRelease(query); + CFReleaseSafe(deleteError); +} + +static void test_key_generate(int globalPersistence, int privatePersistence, int publicPersistence, + bool privateIsPersistent, bool publicIsPersistent) { + __block int phase = 0; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase |= 0x01; + + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + id privateKey; + CFTypeRef keyClass = CFDictionaryGetValue(at, kSecAttrKeyClass) ?: kSecAttrKeyClassPrivate; + eq_cf(keyClass, kSecAttrKeyClassPrivate, "only private keys can be created on token"); + NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate }; + if (objectID != NULL) { + phase |= 0x20; + privateKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)objectID, (CFDictionaryRef)params, NULL)); + } else { + phase |= 0x02; + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, error)); + } + NSDictionary *privKeyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); + CFDictionarySetValue(at, kSecClass, kSecClassKey); + CFDictionarySetValue(at, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); + CFDictionarySetValue(at, kSecAttrKeySizeInBits, CFSTR("256")); + CFDictionarySetValue(at, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + return CFBridgingRetain(privKeyAttrs[(id)kSecValueData]); + }; + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + phase |= 0x04; + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { + phase |= 0x08; + SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes); + CFDataRef publicData; + SecKeyCopyPublicBytes(privKey, &publicData); + CFRelease(privKey); + return publicData; + }; + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + phase |= 0x10; + return kCFNull; + }; + }); + + NSMutableDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC, + (id)kSecAttrKeySizeInBits: @"256", + (id)kSecAttrTokenID: @"tokenid", + }.mutableCopy; + if (globalPersistence >= 0) { + params[(id)kSecAttrIsPermanent] = globalPersistence ? @YES : @NO; + } + if (publicPersistence >= 0) { + params[(id)kSecPublicKeyAttrs] = @{ (id)kSecAttrIsPermanent: publicPersistence ? @YES : @NO }; + } + if (privatePersistence >= 0) { + params[(id)kSecPrivateKeyAttrs] = @{ (id)kSecAttrIsPermanent: privatePersistence ? @YES : @NO }; + } + + NSError *error; + phase = 0; + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error)); + isnt(privateKey, nil, "failed to generate token key, error %@", error); + is(phase, privateIsPersistent ? 0x3f : 0x1f); + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); + isnt(publicKey, nil, "failed to get public key from private key"); + + NSDictionary *query = @{ (id)kSecValueRef: privateKey, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnRef: @YES, + (id)kSecReturnData: @YES }; + phase = 0; + NSDictionary *result; + if (privateIsPersistent) { + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent private key not found in kc"); + is(phase, 0x19); + is(result[(id)kSecValueData], nil); + eq_cf((__bridge CFTypeRef)result[(id)kSecAttrTokenID], @"tokenid"); + NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)result[(id)kSecValueRef])); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + } else { + is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral private key found in kc"); + is(phase, 0x08); + + // Balancing test count from the branch above + ok(true); + ok(true); + ok(true); + ok(true); + } + + query = @{ (id)kSecValueRef: publicKey, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnRef: @YES, + (id)kSecReturnData: @YES }; + phase = 0; + result = nil; + if (publicIsPersistent) { + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent public key not found in kc"); + NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + } else { + is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral public key found in kc"); + + // Balancing test count from the branch above + ok(true); + } + + // Get OID from the private key and try to create duplicate of the key using its OID and attributes. + NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); + NSData *oid = attrs[(id)kSecAttrTokenOID]; + ok(oid != nil, "private key attributes need OID"); + phase = 0; + id copyKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)[NSData data], + (CFDictionaryRef)@{ (id)kSecAttrTokenID: @"tokenid", (id)kSecAttrTokenOID: oid }, + (void *)&error)); + ok(copyKey != nil, "copied key is created"); + is(phase, 0x21); + attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyKey)); + is(phase, 0x29); + phase = 0; + eq_cf((__bridge CFTypeRef)attrs[(id)kSecClass], kSecClassKey); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyClass], kSecAttrKeyClassPrivate); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyType], kSecAttrKeyTypeECSECPrimeRandom); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeySizeInBits], CFSTR("256")); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], CFSTR("tokenid")); + id copyPublicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)copyKey)); + ok(copyPublicKey != nil); + is(phase, 0x08); + NSDictionary *pubAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyPublicKey)); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)pubAttrs[(id)kSecAttrApplicationLabel]); +} + +static void test_key_sign(void) { + + static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; + CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data)); + + __block int phase = 0; + __block CFErrorRef cryptoError = NULL; + __block SecKeyOperationType cryptoOperation = -1; + __block SecKeyAlgorithm cryptoAlgorithm = NULL; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + + blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { + phase++; + SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes); + CFDataRef publicData; + ok_status(SecKeyCopyPublicBytes(privKey, &publicData)); + CFRelease(privKey); + return publicData; + }; + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + phase++; + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { + SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1); + phase++; + cryptoOperation = operation; + cryptoAlgorithm = algorithm; + if (cryptoError != NULL) { + CFAssignRetained(*error, cryptoError); + cryptoError = NULL; + return NULL; + } + return CFRetainSafe(valueData); + }; + + blocks->copyObjectData = ^CFTypeRef(CFDataRef objectID, CFErrorRef *error) { + phase++; + return kCFNull; + }; + }); + + NSDictionary *query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecReturnRef: @YES }; + + phase = 0; + SecKeyRef privateKey = NULL; + ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey)); + is(phase, 2); + + phase = 0; + CFMutableDataRef sig = CFDataCreateMutable(NULL, 0); + CFDataSetLength(sig, 256); + size_t sigLen = CFDataGetLength(sig); + ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen)); + is(phase, 1); + is(cryptoAlgorithm, kSecKeyAlgorithmECDSASignatureDigestX962); + is(cryptoOperation, kSecKeyOperationTypeSign); + CFDataSetLength(sig, sigLen); + is(CFDataGetLength(sig), CFDataGetLength(valueData)); + eq_cf(valueData, sig); + +#if LA_CONTEXT_IMPLEMENTED + phase = 0; + CFDataSetLength(sig, 256); + sigLen = CFDataGetLength(sig); + LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; }); + cryptoError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL); + ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen)); + is(phase, 4); + is(cryptoError, NULL); + CFDataSetLength(sig, sigLen); + is(CFDataGetLength(sig), CFDataGetLength(valueData)); + eq_cf(valueData, sig); +#endif + + NSError *error; + NSData *result; + result = CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionRaw, + valueData, (void *)&error)); + eq_cf((__bridge CFDataRef)result, valueData); + is(cryptoAlgorithm, kSecKeyAlgorithmRSAEncryptionRaw); + is(cryptoOperation, kSecKeyOperationTypeDecrypt); + + NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256 }; + SecKeyRef otherPrivKey = NULL, otherPubKey = NULL; + ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)params, &otherPubKey, &otherPrivKey)); + + error = nil; + result = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privateKey, kSecKeyAlgorithmECDHKeyExchangeCofactor, + otherPubKey, (CFDictionaryRef)@{}, (void *)&error)); + eq_cf((__bridge CFDataRef)result, valueData); + is(cryptoAlgorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor); + is(cryptoOperation, kSecKeyOperationTypeKeyExchange); + + CFReleaseSafe(otherPrivKey); + CFReleaseSafe(otherPubKey); + CFReleaseSafe(cryptoError); + CFRelease(sig); + CFRelease(privateKey); +} + +static void test_key_generate_with_params(void) { + + const UInt8 data[] = "foo"; + CFDataRef cred_ref = CFDataCreate(NULL, data, 4); + __block int phase = 0; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + phase++; + eq_cf(CFDictionaryGetValue(attributes, kSecUseOperationPrompt), CFSTR("prompt")); + is(CFDictionaryGetValue(attributes, kSecUseAuthenticationUI), NULL); + eq_cf(CFDictionaryGetValue(attributes, kSecUseCredentialReference), cred_ref); + + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + phase++; + SecCFCreateError(-4 /* kTKErrorCodeCanceledByUser */, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error); + return NULL; + }; + }); + + CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL, + kSecAttrIsPermanent, kCFBooleanTrue, + NULL); + + CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecAttrKeyType, kSecAttrKeyTypeEC, + kSecAttrKeySizeInBits, CFSTR("256"), + kSecAttrTokenID, CFSTR("tokenid"), + kSecPrivateKeyAttrs, prk_params, + kSecUseOperationPrompt, CFSTR("prompt"), + kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow, + kSecUseCredentialReference, cred_ref, + NULL); + CFRelease(prk_params); + + SecKeyRef publicKey = NULL, privateKey = NULL; + phase = 0; + is_status(SecKeyGeneratePair(params, &publicKey, &privateKey), errSecUserCanceled); + is(phase, 2); + + CFReleaseSafe(publicKey); + CFReleaseSafe(privateKey); + CFRelease(params); + CFRelease(cred_ref); +} + +static void test_error_codes(void) { + + CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL, + kSecClass, kSecClassGenericPassword, + kSecAttrTokenID, CFSTR("tokenid"), + NULL); + // Setup token hook. + __block OSStatus ctk_error = 0; + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + SecCFCreateError(ctk_error, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error); + return NULL; + }; + }); + + ctk_error = kTKErrorCodeBadParameter; + is_status(SecItemAdd(attrs, NULL), errSecParam); + + ctk_error = kTKErrorCodeNotImplemented; + is_status(SecItemAdd(attrs, NULL), errSecUnimplemented); + + ctk_error = kTKErrorCodeCanceledByUser; + is_status(SecItemAdd(attrs, NULL), errSecUserCanceled); + + CFRelease(attrs); +} + +static CFDataRef copy_certificate_data(const char *base64Cert) +{ + size_t size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), NULL, 0); + ok(size); + CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, size); + CFDataSetLength(data, size); + size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), (char*)CFDataGetMutableBytePtr(data), CFDataGetLength(data)); + ok(size); + CFDataSetLength(data, size); + + return data; +} + +static CFMutableDictionaryRef copy_certificate_attributes(const char *base64Cert) +{ + CFDataRef data = copy_certificate_data(base64Cert); + + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, data); + ok(cert); + CFDictionaryRef certAttributes = SecCertificateCopyAttributeDictionary(cert); + ok(certAttributes); + CFMutableDictionaryRef result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, certAttributes); + ok(result); + + if (certAttributes) + CFRelease(certAttributes); + if (data) + CFRelease(data); + if (cert) + CFRelease(cert); + + return result; +} + +static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFStringRef oid, CFStringRef tokenID) +{ + CFMutableDictionaryRef certAttributes = copy_certificate_attributes(base64cert); + + CFDictionarySetValue(certAttributes, kSecAttrLabel, label); + CFDictionarySetValue(certAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); + CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid); + CFDictionaryRemoveValue(certAttributes, kSecValueData); + + SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(acl); + CFTypeRef key[] = { kSecAttrTokenID }; + CFTypeRef value[] = { tokenID }; + CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + ok(SecAccessControlSetProtection(acl, protection, NULL)); + CFRelease(protection); + ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef aclData = SecAccessControlCopyData(acl); + ok(aclData); + if (aclData) { + CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData); + CFRelease(aclData); + } + + if (acl) + CFRelease(acl); + + return certAttributes; +} + +static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFStringRef oid, CFStringRef tokenID) +{ + CFMutableDictionaryRef keyAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ; + + CFDictionarySetValue(keyAttributes, kSecClass, kSecClassKey); + CFDictionarySetValue(keyAttributes, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + CFDictionarySetValue(keyAttributes, kSecAttrKeyType, kSecAttrKeyTypeRSA); + CFNumberRef keySize = CFNumberCreateWithCFIndex(kCFAllocatorDefault, 2048); + CFDictionarySetValue(keyAttributes, kSecAttrKeySizeInBits, keySize); + CFRelease(keySize); + + CFDictionarySetValue(keyAttributes, kSecAttrCanDecrypt, kCFBooleanTrue); + CFDictionarySetValue(keyAttributes, kSecAttrCanSign, kCFBooleanTrue); + CFDictionarySetValue(keyAttributes, kSecAttrCanUnwrap, kCFBooleanTrue); + CFDictionarySetValue(keyAttributes, kSecAttrCanDerive, kCFBooleanFalse); + CFDictionarySetValue(keyAttributes, kSecAttrIsPrivate, kCFBooleanTrue); + + CFDictionarySetValue(keyAttributes, kSecAttrLabel, label); + CFDictionarySetValue(keyAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); + CFDictionarySetValue(keyAttributes, kSecAttrTokenOID, oid); + CFDictionarySetValue(keyAttributes, kSecAttrApplicationLabel, CFDictionaryGetValue(certAttributes, kSecAttrPublicKeyHash)); + + SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(acl); + CFTypeRef key[] = { kSecAttrTokenID }; + CFTypeRef value[] = { tokenID }; + CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + ok(SecAccessControlSetProtection(acl, protection, NULL)); + CFRelease(protection); + ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef aclData = SecAccessControlCopyData(acl); + ok(aclData); + if (aclData) { + CFDictionarySetValue(keyAttributes, kSecAttrAccessControl, aclData); + CFRelease(aclData); + } + + if (acl) + CFRelease(acl); + + return keyAttributes; +} + +static void check_array_for_type_id(CFArrayRef array, CFTypeID typeID) +{ + if (array && CFGetTypeID(array) == CFArrayGetTypeID()) { + for (CFIndex i = 0; i < CFArrayGetCount(array); ++i) { + ok(CFGetTypeID(CFArrayGetValueAtIndex(array, i)) == typeID); + } + } +} + +static void test_propagate_token_items() +{ + CFStringRef cert1OID = CFSTR("oid1"); + CFStringRef cert2OID = CFSTR("oid2"); + CFStringRef key1OID = CFSTR("oid3"); + CFStringRef key2OID = CFSTR("oid4"); + + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + if (CFEqual(oid, cert1OID)) { + return copy_certificate_data(cert1); + } + else if (CFEqual(oid, cert2OID)) { + return copy_certificate_data(cert2); + } + else if (CFEqual(oid, key1OID) || CFEqual(oid, key2OID)) { + return kCFNull; + } + else { + return NULL; + } + }; + }); + + CFStringRef tokenID = CFSTR("com.apple.secdtest:propagate_test_token"); + + CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), cert1OID, tokenID); + ok(certQuery); + CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), key1OID, tokenID); + ok(keyQuery); + + CFArrayAppendValue(items, certQuery); + CFArrayAppendValue(items, keyQuery); + CFReleaseSafe(certQuery); + CFReleaseSafe(keyQuery); + + certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), cert2OID, tokenID); + ok(certQuery); + keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), key2OID, tokenID); + ok(keyQuery); + + CFArrayAppendValue(items, certQuery); + CFArrayAppendValue(items, keyQuery); + CFReleaseSafe(certQuery); + CFReleaseSafe(keyQuery); + + OSStatus result; + ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items."); + + ok_status(result = SecItemUpdateTokenItems(tokenID, items), "Failed to propagate items."); + CFRelease(items); + + CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(query, kSecClass, kSecClassCertificate); + CFDictionarySetValue(query, kSecAttrAccessGroup, CFSTR("com.apple.token")); + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); + CFTypeRef queryResult; + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs"); + check_array_for_type_id(queryResult, SecCertificateGetTypeID()); + CFReleaseNull(queryResult); + + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs"); + check_array_for_type_id(queryResult, CFDataGetTypeID()); + CFReleaseNull(queryResult); + + CFDictionarySetValue(query, kSecClass, kSecClassKey); + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two keys"); + check_array_for_type_id(queryResult, SecKeyGetTypeID()); + CFReleaseNull(queryResult); + + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array"); + CFReleaseNull(queryResult); + + CFDictionarySetValue(query, kSecClass, kSecClassIdentity); + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two identities"); + check_array_for_type_id(queryResult, SecIdentityGetTypeID()); + CFReleaseNull(queryResult); + + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + ok_status(SecItemCopyMatching(query, &queryResult)); + ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array"); + CFReleaseNull(queryResult); + + ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items."); + + CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse); + is_status(SecItemCopyMatching(query, &queryResult), errSecItemNotFound); + CFReleaseNull(queryResult); + CFRelease(query); +} + +static void test_identity_on_two_tokens() { + CFStringRef cert3OID = CFSTR("oid1"); + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + if (CFEqual(oid, cert3OID)) + return copy_certificate_data(cert3); + else + return kCFNull; + }; + + }); + + @autoreleasepool { + NSString *tokenID1 = @"com.apple.secdtest:identity_test_token1"; + NSString *tokenID2 = @"com.apple.secdtest:identity_test_token2"; + + NSError *error; + NSData *privKeyData = [[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters]; + id privKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)privKeyData, (CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate}, (void *)&error)); + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)privKey)); + NSData *pubKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash((__bridge SecKeyRef)publicKey)); + + id ac = CFBridgingRelease(SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL)); + id acData = CFBridgingRelease(SecAccessControlCopyData((__bridge SecAccessControlRef)ac)); + NSDictionary *keyQuery = @{ (id)kSecClass: (id)kSecClassKey, + (id)kSecAttrTokenID: tokenID1, + (id)kSecAttrKeyType : (id)kSecAttrKeyTypeECSECPrimeRandom, + (id)kSecAttrKeySizeInBits : @"256", + (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, + (id)kSecAttrIsPrivate: @YES, + (id)kSecAttrAccessControl: acData, + (id)kSecAttrTokenOID : privKeyData, + (id)kSecAttrApplicationLabel : pubKeyHash, + }; + OSStatus result; + ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[keyQuery]), "Failed to propagate key item."); + + id privateKey; + ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)@{(id)kSecClass: (id)kSecClassKey, (id)kSecAttrTokenID: tokenID1, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecReturnRef: @YES}, (void *)&privateKey)); + + NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), cert3OID, (__bridge CFStringRef)tokenID2)); + ok(certQuery); + + ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[certQuery]), "Failed to propagate cert item."); + + CFTypeRef resultRef; + NSDictionary *query = @{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; + ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); + CFReleaseNull(resultRef); + + query = @{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; + ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); + CFReleaseNull(resultRef); + + query = @{ (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken }; + ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef)); + CFReleaseNull(resultRef); + } +} + +static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) { + TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { + + blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { + return CFBridgingRetain([@"oid" dataUsingEncoding:NSUTF8StringEncoding]); + }; + + blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { + SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey); + CFDataRef data = SecKeyCopyExternalRepresentation(publicKey, error); + CFReleaseNull(publicKey); + return data; + }; + + blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { + return kCFNull; + }; + + blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { + SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); + SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); + CFDataRef acData = SecAccessControlCopyData(ac); + CFRelease(ac); + return acData; + }; + + blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { + CFTypeRef result = kCFNull; + CFTypeRef algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1); + switch (operation) { + case kSecKeyOperationTypeKeyExchange: { + if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) || + CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) { + NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes(privateKey)); + NSDictionary *params = @{ + (id)kSecAttrKeyType: attrs[(id)kSecAttrKeyType], + (id)kSecAttrKeySizeInBits: attrs[(id)kSecAttrKeySizeInBits], + (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic, + }; + SecKeyRef pubKey = SecKeyCreateWithData(in1, (CFDictionaryRef)params, error); + if (pubKey == NULL) { + return NULL; + } + result = SecKeyCopyKeyExchangeResult(privateKey, algorithm, pubKey, in2, error); + CFReleaseSafe(pubKey); + } + break; + } + case kSecKeyOperationTypeDecrypt: { + if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { + result = SecKeyCreateDecryptedData(privateKey, algorithm, in1, error); + } + break; + } + default: + break; + } + return result; + }; + }); + + NSDictionary *privateParams = CFBridgingRelease(SecKeyCopyAttributes(privateKey)); + NSDictionary *params = @{ (id)kSecAttrKeyType : privateParams[(id)kSecAttrKeyType], + (id)kSecAttrKeySizeInBits : privateParams[(id)kSecAttrKeySizeInBits], + (id)kSecAttrTokenID : @"tid-ies", + (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @YES } + }; + NSError *error; + SecKeyRef tokenKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error); + ok(tokenKey != NULL, "create token-based key (err %@)", error); + SecKeyRef tokenPublicKey = SecKeyCopyPublicKey(tokenKey); + + NSData *plaintext = [@"plaintext" dataUsingEncoding:NSUTF8StringEncoding]; + + error = nil; + NSData *ciphertext = CFBridgingRelease(SecKeyCreateEncryptedData(tokenPublicKey, algorithm, (CFDataRef)plaintext, (void *)&error)); + ok(ciphertext, "failed to encrypt IES, err %@", error); + + NSData *decrypted = CFBridgingRelease(SecKeyCreateDecryptedData(tokenKey, algorithm, (CFDataRef)ciphertext, (void *)&error)); + ok(decrypted, "failed to decrypt IES, err %@", error); + + eq_cf((__bridge CFDataRef)plaintext, (__bridge CFDataRef)decrypted, "decrypted(%@) != plaintext(%@)", decrypted, plaintext); + + CFReleaseNull(tokenKey); + CFReleaseNull(tokenPublicKey); +} + +static void test_ecies() { + NSError *error; + SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error); + ok(privateKey != NULL, "failed to generate CPU EC key: %@", error); + + test_ies(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); + + CFReleaseNull(privateKey); +} + +static void test_rsawrap() { + NSError *error; + SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048}, (void *)&error); + ok(privateKey != NULL, "failed to generate CPU RSA key: %@", error); + + test_ies(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM); + + CFReleaseNull(privateKey); +} + +static void tests(void) { + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_33_keychain_ctk", NULL); + + test_item_add(); + test_item_query(); + test_item_update(); + test_item_delete(); + + // params: int globalPersistence, int privatePersistence, int publicPersistence, bool privateIsPersistent, bool publicIsPersistent + test_key_generate(-1, -1, -1, true, false); + test_key_generate(0, -1, -1, false, false); + test_key_generate(1, -1, -1, true, true); + test_key_generate(-1, 0, 0, false, false); + test_key_generate(-1, 1, 0, true, false); + test_key_generate(-1, 0, 1, false, true); + test_key_generate(-1, 1, 1, true, true); + test_key_generate(0, 1, 1, true, true); + test_key_generate(1, 1, 1, true, true); + + test_key_sign(); + test_key_generate_with_params(); + test_error_codes(); + test_propagate_token_items(); + test_identity_on_two_tokens(); + test_rsawrap(); + test_ecies(); +} + +int secd_33_keychain_ctk(int argc, char *const *argv) { + plan_tests(491); + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-34-backup-der-parse.m b/keychain/securityd/Regressions/secd-34-backup-der-parse.m new file mode 100644 index 00000000..352b832d --- /dev/null +++ b/keychain/securityd/Regressions/secd-34-backup-der-parse.m @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2008-2010,2013 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "secd_regressions.h" + +#include "keychain/securityd/SecItemServer.h" + +#include "SecdTestKeychainUtilities.h" + +/* Keybag and exported plist data. */ +static const unsigned char backup_data[] = { + 0x30, 0x82, 0x06, 0xf4, 0x04, 0x82, 0x06, 0xf0, 0x56, 0x45, 0x52, 0x53, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x54, 0x59, 0x50, 0x45, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x55, 0x55, 0x49, 0x44, + 0x00, 0x00, 0x00, 0x10, 0x60, 0x5e, 0x34, 0x57, 0xbe, 0xa0, 0x48, 0xd6, + 0x9b, 0x22, 0xfa, 0x80, 0xff, 0x3a, 0xe9, 0x9b, 0x48, 0x4d, 0x43, 0x4b, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x52, 0x41, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x53, 0x41, 0x4c, 0x54, + 0x00, 0x00, 0x00, 0x14, 0x50, 0x2e, 0x97, 0xc6, 0xfa, 0xed, 0x9b, 0xc0, + 0x6f, 0x09, 0x2a, 0xca, 0x29, 0x38, 0x47, 0x34, 0x9f, 0xc0, 0x29, 0x7e, + 0x49, 0x54, 0x45, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x27, 0x10, + 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x6f, 0x6a, 0x84, 0xd0, + 0x73, 0x27, 0x4a, 0xbc, 0xb3, 0x28, 0xb4, 0xa4, 0xc5, 0x36, 0x4a, 0xdf, + 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0b, + 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, + 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x69, 0xa7, 0xb1, 0xcd, + 0x86, 0x2c, 0xc4, 0xc4, 0x81, 0x52, 0xb3, 0xe7, 0xf9, 0x78, 0xad, 0xec, + 0xaf, 0xc4, 0xe1, 0x71, 0xc9, 0x98, 0xca, 0xb4, 0xa8, 0x86, 0xdc, 0xe9, + 0xcf, 0x48, 0xce, 0x82, 0xa4, 0xeb, 0xf4, 0x43, 0x6d, 0xb0, 0xee, 0x05, + 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xcf, 0x0b, 0x7c, 0x16, + 0xa1, 0x69, 0x16, 0x1f, 0x52, 0x5a, 0xb5, 0x16, 0xa2, 0x75, 0xe0, 0x5f, + 0xb2, 0x55, 0x53, 0xed, 0x10, 0xc6, 0xd1, 0x4d, 0x47, 0x65, 0xe6, 0xcb, + 0xd0, 0x77, 0x12, 0x56, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x5c, 0x1d, 0x0e, 0xde, 0x90, 0xac, 0x45, 0x1f, 0xa1, 0x10, 0x75, 0x84, + 0xf4, 0x9c, 0xe9, 0x65, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0a, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xdd, 0xd8, 0xfa, 0x79, 0x6a, 0x6a, 0x63, 0xfc, 0x40, 0xf2, 0xa9, 0x1d, + 0xe9, 0xf1, 0xf6, 0xdb, 0x14, 0xc4, 0x55, 0x52, 0x80, 0x2e, 0xe3, 0x48, + 0x91, 0x53, 0x17, 0xd9, 0xb6, 0x91, 0x05, 0x42, 0x25, 0xa3, 0xb8, 0xc7, + 0x95, 0x21, 0x14, 0xb7, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, + 0x48, 0xb5, 0xd3, 0xe5, 0xdb, 0xc5, 0x3b, 0x20, 0x23, 0x35, 0x4f, 0xd4, + 0x28, 0xe5, 0x43, 0x59, 0xaf, 0x74, 0xd3, 0x40, 0xd3, 0x24, 0x7c, 0x0a, + 0xe7, 0x86, 0x9e, 0xde, 0x96, 0x6d, 0xdb, 0x3a, 0x55, 0x55, 0x49, 0x44, + 0x00, 0x00, 0x00, 0x10, 0xc7, 0x1f, 0xde, 0xb6, 0xb0, 0x49, 0x42, 0x90, + 0x90, 0x32, 0xbf, 0x39, 0x84, 0x9d, 0xb3, 0xa1, 0x43, 0x4c, 0x41, 0x53, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x57, 0x52, 0x41, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x4b, 0x54, 0x59, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x28, 0xc7, 0xbd, 0xb5, 0x0a, 0x70, 0x1a, 0xe6, 0xfb, + 0x39, 0x0a, 0x4a, 0x2d, 0x45, 0xf9, 0x5f, 0xb1, 0xc8, 0xdc, 0x88, 0x1a, + 0x26, 0xf1, 0xaa, 0x1a, 0xb5, 0xd9, 0xbf, 0xce, 0x1f, 0x7e, 0x69, 0xb2, + 0xdc, 0xbe, 0x48, 0x59, 0xea, 0xf0, 0x04, 0xba, 0x50, 0x42, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x20, 0x93, 0x26, 0xff, 0x91, 0xd0, 0x28, 0x45, 0x27, + 0x4c, 0xf0, 0x83, 0xa4, 0x39, 0x38, 0x30, 0xb5, 0x62, 0x18, 0xdc, 0xe2, + 0x9a, 0x50, 0xf7, 0xd4, 0x01, 0x38, 0xa0, 0x61, 0x69, 0x2b, 0x38, 0x6c, + 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0xdc, 0x23, 0x9d, 0x5c, + 0xdd, 0xf6, 0x4c, 0xa0, 0xbf, 0x63, 0x6e, 0xe8, 0x40, 0xaa, 0x43, 0xbf, + 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, + 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, + 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x68, 0xf5, 0x29, 0x43, + 0x1c, 0x42, 0x59, 0x83, 0xb8, 0x0d, 0x12, 0xf6, 0x7f, 0x6d, 0x66, 0xbe, + 0xdd, 0xaf, 0x05, 0x90, 0x52, 0xe7, 0x03, 0xea, 0x8a, 0x03, 0xc2, 0x6f, + 0x9c, 0x47, 0xb1, 0xea, 0x88, 0x08, 0x19, 0x2d, 0x00, 0x3b, 0x5b, 0x79, + 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xb4, 0x25, 0xc5, 0xa3, + 0x85, 0xe4, 0x62, 0x53, 0x62, 0xd7, 0x0c, 0x69, 0xb9, 0x6d, 0x04, 0xe0, + 0x5a, 0xbf, 0x1a, 0x79, 0xa5, 0x48, 0x26, 0x67, 0x9e, 0x3a, 0xc8, 0x42, + 0x18, 0xca, 0x75, 0x0c, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0xb5, 0xc8, 0x18, 0xb8, 0x8f, 0xea, 0x40, 0xe7, 0x88, 0xcd, 0xf4, 0xc5, + 0x96, 0xb8, 0x92, 0xf1, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x07, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xaa, 0x8a, 0x3c, 0x92, 0xea, 0x65, 0xa9, 0xdb, 0x3a, 0x36, 0x01, 0x54, + 0x2e, 0x62, 0xc6, 0xd2, 0x46, 0x75, 0x61, 0xac, 0x5d, 0xbb, 0x62, 0xaa, + 0xc3, 0xed, 0xbf, 0x14, 0x35, 0x13, 0x21, 0x2f, 0x47, 0x7d, 0x57, 0x07, + 0xf1, 0x80, 0xa4, 0xcc, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, + 0x3e, 0xb4, 0x78, 0x54, 0xd2, 0x19, 0xaf, 0xe4, 0x4c, 0x84, 0x02, 0xd0, + 0xf4, 0x50, 0xde, 0xd6, 0x44, 0xc9, 0xdf, 0x4b, 0x8d, 0x81, 0x2a, 0x2d, + 0xbb, 0xf1, 0x94, 0xd0, 0x4e, 0x57, 0xfa, 0x4e, 0x55, 0x55, 0x49, 0x44, + 0x00, 0x00, 0x00, 0x10, 0x59, 0x3c, 0xc5, 0xc5, 0xf2, 0x39, 0x4a, 0x44, + 0x90, 0xd4, 0xb1, 0x07, 0x17, 0x00, 0x64, 0x34, 0x43, 0x4c, 0x41, 0x53, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x57, 0x52, 0x41, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x28, 0x79, 0xdd, 0x59, 0x01, 0x1f, 0x45, 0xe4, 0x01, + 0x32, 0xb5, 0xae, 0x5e, 0x17, 0xd7, 0x6c, 0xc6, 0x1d, 0x28, 0xf0, 0x32, + 0x4a, 0x18, 0xff, 0x30, 0x2c, 0xe4, 0xcb, 0x7c, 0x58, 0x53, 0x00, 0x8b, + 0xb9, 0xdd, 0x71, 0x5f, 0xbc, 0x66, 0x9b, 0x4c, 0x50, 0x42, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x20, 0xc3, 0x2d, 0xc7, 0x4f, 0xb1, 0x7b, 0x3c, 0x9d, + 0xcb, 0xf4, 0xd6, 0x45, 0x20, 0x35, 0xbc, 0x3a, 0x6c, 0x13, 0x1d, 0x7c, + 0x63, 0x53, 0x17, 0xc9, 0x84, 0x86, 0xbd, 0x96, 0xb0, 0xa4, 0x39, 0x03, + 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0xcb, 0x2c, 0x33, 0x2e, + 0x69, 0x39, 0x43, 0xe5, 0x87, 0xbb, 0xbc, 0xd4, 0x47, 0xa4, 0x86, 0x7b, + 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, + 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, + 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x6f, 0x62, 0x11, 0xb0, + 0xdf, 0x5a, 0x39, 0x43, 0xe9, 0xc3, 0xc5, 0x0b, 0x1c, 0x57, 0x6f, 0x79, + 0x0d, 0x44, 0x9f, 0x44, 0xf2, 0x51, 0x1e, 0x68, 0xb8, 0xcf, 0x5c, 0x6d, + 0x94, 0x86, 0x86, 0x70, 0x12, 0xc1, 0x76, 0xc0, 0x18, 0xe4, 0x58, 0x1a, + 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0x6f, 0xba, 0xbd, 0x37, + 0x58, 0x5f, 0x96, 0x4d, 0x4c, 0x92, 0xbb, 0xf0, 0x43, 0xec, 0x84, 0xc3, + 0x68, 0x75, 0xf1, 0xd2, 0x04, 0x0d, 0xda, 0x8a, 0xec, 0xac, 0x02, 0xf7, + 0xf7, 0x4d, 0xf4, 0x0e, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0x8d, 0xa4, 0xb5, 0x6b, 0x95, 0x12, 0x46, 0xff, 0x9e, 0x1f, 0xdd, 0x2f, + 0xc0, 0x60, 0xc6, 0xd6, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0xa8, 0xa2, 0x8d, 0xe2, 0x16, 0xd8, 0xce, 0x18, 0x2c, 0x8e, 0xa4, 0x8d, + 0x32, 0xba, 0x83, 0xdb, 0x5e, 0xc8, 0x04, 0x59, 0x72, 0xca, 0x72, 0xe5, + 0x6f, 0xcd, 0x06, 0x98, 0xde, 0x4b, 0xcf, 0xa6, 0xd1, 0xe3, 0xba, 0x9b, + 0x68, 0xa6, 0xe5, 0xa2, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, + 0x46, 0x45, 0x3a, 0xc1, 0x62, 0x14, 0xd7, 0x3f, 0x8c, 0x7a, 0x66, 0x1d, + 0x4b, 0x5c, 0x86, 0x43, 0x75, 0xe6, 0x93, 0xf1, 0x31, 0x6b, 0x20, 0x8b, + 0x18, 0x87, 0x84, 0xcc, 0x92, 0xfc, 0xb3, 0x32, 0x55, 0x55, 0x49, 0x44, + 0x00, 0x00, 0x00, 0x10, 0xd8, 0x36, 0xc5, 0xf9, 0x76, 0x4b, 0x4c, 0x2c, + 0x8c, 0xaa, 0xf4, 0x62, 0xab, 0x14, 0xd5, 0x08, 0x43, 0x4c, 0x41, 0x53, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x57, 0x52, 0x41, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x28, 0x0c, 0xe1, 0xb2, 0xee, 0x08, 0xdb, 0xe4, 0xee, + 0xb5, 0x49, 0xd5, 0x3a, 0xe7, 0xd9, 0xbd, 0xf6, 0xab, 0x0e, 0x1a, 0x2a, + 0x16, 0x6c, 0x82, 0x88, 0x5e, 0x39, 0xf6, 0x89, 0xcf, 0x5c, 0x69, 0x3c, + 0x67, 0x56, 0x16, 0xa1, 0x2c, 0xf4, 0x7d, 0xb9, 0x50, 0x42, 0x4b, 0x59, + 0x00, 0x00, 0x00, 0x20, 0xc1, 0x54, 0xd5, 0xb9, 0xf1, 0x16, 0xe9, 0xb2, + 0x9b, 0x79, 0x73, 0x7a, 0xb7, 0x95, 0x0a, 0xdb, 0x15, 0x20, 0x4d, 0xa7, + 0x0f, 0x5d, 0xed, 0x1c, 0x95, 0x63, 0xec, 0xf8, 0xf0, 0xf2, 0x30, 0x75, + 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, 0x48, 0xf3, 0x98, 0x06, + 0xfe, 0xb8, 0x4e, 0xd6, 0xa9, 0xb3, 0xe1, 0xa2, 0x1f, 0xb0, 0x7b, 0xcd, + 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, + 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, + 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, 0x01, 0x8a, 0x2c, 0x90, + 0x67, 0x3f, 0xe0, 0xf8, 0xb1, 0xbb, 0x86, 0x7f, 0xdc, 0xcd, 0xfd, 0x22, + 0x98, 0x54, 0x30, 0x75, 0x49, 0xd1, 0xe8, 0xc2, 0x85, 0x51, 0x5b, 0xae, + 0xfa, 0x3f, 0xf8, 0xfc, 0xf8, 0xa6, 0xf9, 0xa0, 0x80, 0xa5, 0x3b, 0x87, + 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, 0xa6, 0x4f, 0x13, 0x8a, + 0x52, 0xe5, 0x5a, 0x65, 0x69, 0xd4, 0x70, 0xc8, 0xc7, 0xec, 0xbd, 0x27, + 0x3a, 0xcd, 0xd0, 0xb4, 0x61, 0x5d, 0xf4, 0x81, 0x67, 0xe5, 0x63, 0x77, + 0xbd, 0x4d, 0xb5, 0x0f, 0x55, 0x55, 0x49, 0x44, 0x00, 0x00, 0x00, 0x10, + 0xa9, 0x3b, 0xd2, 0x02, 0x4f, 0x72, 0x46, 0x32, 0x99, 0xa6, 0x7b, 0x62, + 0xaa, 0x11, 0xf4, 0x67, 0x43, 0x4c, 0x41, 0x53, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x52, 0x41, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x02, 0x4b, 0x54, 0x59, 0x50, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x57, 0x50, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x28, + 0x8d, 0xae, 0x30, 0xf1, 0x0f, 0x88, 0x7a, 0x8a, 0xb7, 0x34, 0xc9, 0x50, + 0x02, 0x20, 0x40, 0x3c, 0xce, 0xd2, 0xa9, 0xe7, 0x5a, 0x3a, 0xad, 0xad, + 0xac, 0xdc, 0x3a, 0xc2, 0x92, 0x9d, 0x33, 0x7a, 0x73, 0x78, 0x8a, 0x37, + 0x04, 0x2b, 0xbd, 0xf2, 0x50, 0x42, 0x4b, 0x59, 0x00, 0x00, 0x00, 0x20, + 0x72, 0x9c, 0x52, 0x44, 0xf0, 0xdd, 0xe1, 0x4a, 0x9e, 0x7b, 0x99, 0xec, + 0x64, 0x66, 0x5d, 0xde, 0xe4, 0x8d, 0x72, 0x87, 0xee, 0xd8, 0x66, 0xad, + 0x7d, 0x06, 0x0c, 0x98, 0xc9, 0x2f, 0xfb, 0x19, 0x31, 0x82, 0x03, 0x14, + 0x30, 0x0d, 0x0c, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0c, 0x04, 0x67, + 0x65, 0x6e, 0x70, 0x30, 0x1c, 0x0c, 0x04, 0x68, 0x61, 0x73, 0x68, 0x04, + 0x14, 0xac, 0x28, 0x52, 0x3c, 0xba, 0x05, 0xe5, 0xbd, 0x68, 0x3d, 0xd2, + 0x4c, 0xfb, 0x66, 0x80, 0xb3, 0xdf, 0xdc, 0x1f, 0x0f, 0x30, 0x82, 0x02, + 0xe3, 0x0c, 0x04, 0x64, 0x61, 0x74, 0x61, 0x04, 0x82, 0x02, 0xd9, 0x03, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xf1, + 0xa8, 0xb7, 0x9d, 0x4b, 0xb4, 0x44, 0x5b, 0xb7, 0x75, 0x4e, 0x73, 0x60, + 0xd9, 0xa9, 0x40, 0x08, 0xb0, 0xd9, 0x40, 0xd2, 0x9a, 0x01, 0xf1, 0x58, + 0x87, 0x0d, 0xb2, 0x37, 0xee, 0x3a, 0x76, 0xbe, 0x3c, 0x31, 0x6c, 0x93, + 0xa2, 0xd0, 0x8e, 0xf7, 0x5c, 0x97, 0x25, 0x69, 0xbc, 0xd1, 0x52, 0x73, + 0x32, 0xf4, 0x38, 0x13, 0xda, 0x86, 0xab, 0x6f, 0xe9, 0x6c, 0x4a, 0xeb, + 0xc4, 0x7a, 0xd8, 0x53, 0x03, 0x86, 0x48, 0x4f, 0x11, 0x1a, 0x1b, 0xa9, + 0x17, 0x21, 0xc3, 0x97, 0x12, 0xb6, 0x77, 0x03, 0xba, 0x22, 0x96, 0x0a, + 0x90, 0x01, 0x84, 0xd6, 0x5e, 0x2e, 0x3e, 0x8e, 0x50, 0xb7, 0x48, 0x38, + 0xb6, 0x7f, 0x77, 0x08, 0xf1, 0x2e, 0x5f, 0x3e, 0xda, 0x67, 0xff, 0xa4, + 0x82, 0x89, 0xad, 0xfa, 0x46, 0x38, 0x23, 0x35, 0xb3, 0x8f, 0x5d, 0x31, + 0x2e, 0x39, 0x08, 0x0a, 0x90, 0xe5, 0x5b, 0xf0, 0xc6, 0xb2, 0xa9, 0x8a, + 0x6f, 0x31, 0x5a, 0xbd, 0x6f, 0x74, 0x17, 0x67, 0xb4, 0x0c, 0x4b, 0xd8, + 0xf6, 0x4d, 0x25, 0xca, 0x06, 0xc0, 0x95, 0xf5, 0x70, 0x16, 0xb9, 0x49, + 0xbd, 0xaa, 0x73, 0xb5, 0xed, 0x4d, 0xb1, 0x92, 0x78, 0x28, 0xf7, 0x0d, + 0xbb, 0x73, 0x3d, 0x24, 0x78, 0x19, 0x55, 0xbb, 0x9b, 0x4e, 0xe6, 0x3b, + 0x84, 0x69, 0xd5, 0xbd, 0x3a, 0xcb, 0x8c, 0x70, 0x28, 0x10, 0x8c, 0x5c, + 0xfe, 0xb1, 0x0a, 0x2a, 0x7f, 0xb9, 0xbb, 0x32, 0xab, 0xc5, 0xf6, 0xfd, + 0x66, 0xb7, 0xf7, 0xce, 0x63, 0xcc, 0x05, 0x25, 0xd0, 0x0b, 0x37, 0x94, + 0xbc, 0x1f, 0x0d, 0x80, 0x6b, 0x6c, 0xfd, 0x5a, 0x62, 0xd6, 0xca, 0x3e, + 0x9a, 0x5f, 0x23, 0xfd, 0xc6, 0x9b, 0x65, 0xd4, 0x2a, 0x80, 0x51, 0x45, + 0x08, 0xe6, 0xc8, 0x20, 0x16, 0xb0, 0xb8, 0xc6, 0xee, 0x17, 0xb5, 0x6f, + 0x6f, 0xb5, 0x75, 0xb3, 0x14, 0x03, 0x68, 0xab, 0x99, 0x69, 0xf8, 0x87, + 0x70, 0x5c, 0x6f, 0x45, 0x7b, 0x49, 0xee, 0xb6, 0xbb, 0x3c, 0x0c, 0x50, + 0x90, 0x7c, 0x4c, 0xab, 0xca, 0x81, 0x80, 0x48, 0x5d, 0x13, 0xa2, 0x9e, + 0xf6, 0xfd, 0x2d, 0x57, 0x1d, 0xf0, 0x01, 0xc0, 0x7e, 0x69, 0x69, 0x83, + 0x81, 0x25, 0x70, 0x81, 0x66, 0x26, 0xa3, 0x0f, 0xb7, 0x56, 0x27, 0xcd, + 0x3b, 0x30, 0x45, 0x97, 0x5c, 0x69, 0x56, 0xa1, 0x22, 0x94, 0x87, 0x4b, + 0xd2, 0xf3, 0xc3, 0x92, 0x6d, 0x7d, 0xe3, 0x04, 0x0b, 0xa7, 0x07, 0x42, + 0x9e, 0x58, 0xd0, 0xbf, 0xa2, 0xd2, 0x52, 0xf2, 0xc5, 0xdd, 0xe7, 0x1f, + 0x2e, 0x01, 0x8b, 0xd5, 0xb5, 0x48, 0xb0, 0x94, 0xfb, 0xc4, 0xf8, 0x44, + 0x6c, 0xde, 0xbb, 0x6a, 0xf7, 0xd7, 0x9f, 0x2f, 0x33, 0x07, 0xca, 0xa6, + 0x70, 0x76, 0x58, 0x33, 0x51, 0x6f, 0x34, 0xf8, 0x5e, 0xbf, 0x84, 0xb4, + 0x6e, 0x56, 0x47, 0x12, 0xa2, 0xd1, 0xa1, 0xbb, 0xf1, 0xed, 0x41, 0xd7, + 0x54, 0x49, 0xec, 0x0e, 0x5f, 0x65, 0x84, 0x8e, 0xbe, 0xa0, 0x2a, 0xaa, + 0xe7, 0xff, 0xf3, 0xc0, 0x9d, 0x07, 0xc9, 0xe4, 0xfd, 0x9c, 0x78, 0x6f, + 0x94, 0x9a, 0xab, 0xe5, 0x4b, 0x41, 0x0c, 0x5b, 0x18, 0x40, 0x2c, 0xca, + 0x45, 0xd0, 0x91, 0xc3, 0x99, 0xfa, 0xc1, 0x99, 0xf5, 0x37, 0xf6, 0x2f, + 0x7c, 0x46, 0x4b, 0xea, 0xb9, 0x13, 0xf7, 0x34, 0x31, 0x90, 0x68, 0xa0, + 0xa5, 0x41, 0xfe, 0x45, 0xcd, 0x47, 0x62, 0x9d, 0x92, 0x8a, 0xf6, 0x0b, + 0xdd, 0x26, 0x13, 0x98, 0x8e, 0x8b, 0x42, 0xd9, 0x6c, 0x72, 0x61, 0x07, + 0x05, 0xf0, 0x7f, 0xe0, 0x44, 0x44, 0x02, 0x23, 0xf0, 0x33, 0xc2, 0xe1, + 0x5c, 0x85, 0x57, 0xc8, 0x4a, 0x73, 0xf4, 0x09, 0xba, 0xbd, 0x6f, 0xd0, + 0x3f, 0x76, 0x23, 0xd6, 0x14, 0x81, 0x07, 0x05, 0x08, 0xdb, 0x73, 0x43, + 0x65, 0xfd, 0xcf, 0x4f, 0x93, 0xdd, 0xe6, 0x44, 0x5e, 0xed, 0x1b, 0xf5, + 0x5d, 0x9e, 0xc3, 0xc1, 0x4d, 0x6b, 0x5c, 0xa2, 0xf7, 0x60, 0xd8, 0xb6, + 0x6e, 0x3e, 0xe8, 0x32, 0xc6, 0x24, 0xbb, 0xae, 0xa6, 0x3b, 0x1d, 0x6a, + 0x06, 0x3c, 0x2c, 0x6b, 0x4a, 0x33, 0x4d, 0x6c, 0xd6, 0xc4, 0x1b, 0xb2, + 0x2e, 0xcc, 0x92, 0x1b, 0xc8, 0xd4, 0xdd, 0xd8, 0x18, 0x1a, 0x1b, 0x9b, + 0xb4, 0xc7, 0xf7, 0xcc, 0xbb, 0x67, 0x02, 0x40, 0x94, 0x82, 0x36, 0xa4, + 0x3c, 0x3d, 0x6a, 0xf2, 0xcf, 0x58, 0x67, 0x7d, 0x7f, 0xd0, 0x17, 0x01, + 0xdf, 0xe4, 0xc3, 0xf7, 0x2d, 0x9d, 0x69, 0x19, 0x36, 0x3a, 0x9f, 0xcb, + 0xd5, 0x09, 0xf7, 0x4c, 0x61, 0x06, 0x59, 0xf9, 0x0b, 0x89, 0x9e, 0x73, + 0x9f, 0x44, 0x4e, 0x2e, 0x3d, 0xc0, 0xdd, 0xae, 0x70, 0x36, 0x58, 0x11, + 0xab, 0x0d, 0x73, 0xc2, 0x24, 0x45, 0x7d, 0x5e, 0xd2, 0x6a, 0xc0, 0xa1, + 0x0e, 0x86, 0x52, 0x01, 0xe8, 0xea, 0xce, 0x80, 0x97, 0x9f, 0xfa, 0x69, + 0xb9, 0x2d, 0x9a, 0xd3, 0xd9, 0xee, 0xc4, 0x36, 0xc7, 0x61, 0xdd, 0xe0, + 0xe7, 0xb4, 0xbe, 0x81, 0x54, 0x92, 0x89, 0x44, 0x9f, 0x3b, 0x77, 0x9b, + 0xcd, 0x17, 0xf2, 0x48, 0xd7, 0x1a, 0x46, 0xaf, 0x88, 0x9c, 0x0f, 0xc1, + 0x2b, 0x1e, 0x3d, 0xe5, 0x8e, 0xb3, 0x9b, 0xa0, 0x4b, 0xe6, 0x3f, 0xf4, + 0x27, 0xc4, 0xc9, 0x2c, 0x23, 0xc0, 0x26, 0xf3, 0x02, 0x02, 0x03, 0xe7, + 0x31, 0x82, 0x03, 0x14, 0x30, 0x0d, 0x0c, 0x05, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x0c, 0x04, 0x67, 0x65, 0x6e, 0x70, 0x30, 0x1c, 0x0c, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x04, 0x14, 0x20, 0x5a, 0x6b, 0x14, 0x4b, 0x34, 0x12, + 0xc6, 0x71, 0x8c, 0xe4, 0xa8, 0x07, 0x83, 0x0e, 0xe0, 0x6f, 0x2d, 0xe6, + 0x13, 0x30, 0x82, 0x02, 0xe3, 0x0c, 0x04, 0x64, 0x61, 0x74, 0x61, 0x04, + 0x82, 0x02, 0xd9, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x00, 0x00, 0x0d, 0x9c, 0x25, 0x6a, 0x30, 0x5b, 0x92, 0x39, 0xe8, + 0x4c, 0x61, 0x06, 0x44, 0x0f, 0xb1, 0x58, 0x6f, 0x0f, 0x5f, 0x4c, 0x8d, + 0xdb, 0x59, 0x69, 0x90, 0xd4, 0x2f, 0x4e, 0x78, 0xa9, 0x62, 0x1d, 0xbc, + 0xad, 0x25, 0x38, 0xb7, 0x05, 0xa3, 0x79, 0x94, 0xc7, 0x2c, 0x4f, 0x67, + 0xf3, 0x76, 0xf4, 0xf8, 0x58, 0x34, 0x85, 0x80, 0x2e, 0x3c, 0x90, 0xef, + 0xe7, 0xc2, 0x08, 0xd7, 0x6a, 0xdd, 0xba, 0xae, 0x55, 0x27, 0xd3, 0x42, + 0x27, 0x5d, 0x7e, 0x0e, 0xe5, 0x8e, 0xe9, 0xd5, 0x42, 0x3b, 0x48, 0x70, + 0x40, 0x25, 0xf5, 0xbe, 0xb6, 0x4e, 0x10, 0xf7, 0xe5, 0x60, 0x9d, 0xd7, + 0x8b, 0x63, 0x40, 0xf0, 0x8b, 0xa2, 0xf3, 0xd6, 0x04, 0xaf, 0x54, 0xa5, + 0xeb, 0x52, 0x80, 0x1a, 0xa8, 0xe0, 0xf7, 0x9b, 0x45, 0x94, 0x36, 0xee, + 0x40, 0xfd, 0xad, 0x2c, 0xf0, 0x92, 0x8e, 0x4a, 0x98, 0x80, 0xed, 0x43, + 0xd3, 0x17, 0xa6, 0xab, 0x96, 0xb4, 0x17, 0x1e, 0xab, 0xb4, 0x6b, 0x74, + 0x43, 0x7c, 0xd9, 0xe1, 0x66, 0x6f, 0x07, 0x20, 0x53, 0x66, 0xe6, 0x60, + 0xbf, 0x92, 0x73, 0x46, 0xfb, 0xb0, 0x81, 0xea, 0xf2, 0xac, 0x13, 0xf7, + 0xbb, 0xd4, 0x38, 0x1b, 0x64, 0xd3, 0xc3, 0x34, 0x37, 0x2c, 0xbc, 0x7d, + 0x36, 0x88, 0xb1, 0x90, 0xcd, 0x9e, 0xee, 0xaf, 0xcb, 0x63, 0x3f, 0x8a, + 0xf5, 0x1a, 0xfc, 0x21, 0xb2, 0xf0, 0xc0, 0x60, 0x72, 0xc7, 0xf0, 0x54, + 0x3e, 0x88, 0x4c, 0x69, 0x96, 0xc2, 0x2b, 0x25, 0x96, 0x41, 0x05, 0xd7, + 0xc6, 0x89, 0xe8, 0x33, 0x1c, 0x7a, 0x88, 0x81, 0xfe, 0xb2, 0x3d, 0x6f, + 0x60, 0x43, 0x1e, 0x62, 0x48, 0x76, 0xd2, 0xe6, 0xfb, 0x22, 0x8a, 0x5d, + 0xe6, 0xd8, 0xe2, 0x30, 0x51, 0x2f, 0xcc, 0xab, 0xb0, 0x31, 0x68, 0x43, + 0x51, 0x11, 0x67, 0x09, 0x3c, 0x34, 0x7e, 0x49, 0xe0, 0xe0, 0xd4, 0x74, + 0xe4, 0x17, 0x42, 0x32, 0x76, 0x3a, 0x2f, 0xc1, 0x8a, 0xb3, 0xfc, 0xdc, + 0x54, 0x00, 0x05, 0x00, 0x8b, 0x07, 0x70, 0xbb, 0xc1, 0x97, 0x33, 0x9f, + 0x93, 0x2c, 0xc1, 0xc8, 0x3b, 0xfb, 0x99, 0xe8, 0x3e, 0x60, 0x20, 0x7d, + 0xb7, 0x77, 0x20, 0x61, 0xda, 0xfb, 0x66, 0xa9, 0x0e, 0x5c, 0x65, 0x30, + 0x4d, 0x39, 0x6b, 0x39, 0xb6, 0xe3, 0x16, 0xc2, 0x01, 0x2b, 0x0d, 0x0b, + 0x95, 0xa7, 0x45, 0x40, 0xb8, 0x93, 0xaf, 0x97, 0x8c, 0x63, 0xab, 0x4f, + 0x9e, 0x90, 0x98, 0xda, 0xe7, 0x84, 0x41, 0xcc, 0xed, 0xb5, 0xc0, 0x35, + 0xa6, 0x1b, 0xe5, 0x51, 0x7f, 0xaa, 0x44, 0xd0, 0x32, 0x0c, 0x04, 0xfa, + 0x34, 0x4d, 0xb4, 0x3a, 0xd0, 0x4e, 0xc8, 0xcb, 0x6d, 0x98, 0x42, 0xad, + 0xc4, 0xe3, 0x38, 0x39, 0xc8, 0x21, 0x6a, 0xb5, 0x7f, 0x00, 0x99, 0x58, + 0x69, 0x5e, 0xd8, 0xe7, 0x43, 0x09, 0x7f, 0x7d, 0x65, 0xe9, 0xe1, 0x1e, + 0xa8, 0x60, 0x83, 0x5b, 0xa9, 0x87, 0xca, 0xe6, 0xf4, 0x27, 0xab, 0x93, + 0x8b, 0x43, 0x34, 0xdf, 0xd5, 0x3a, 0x36, 0x19, 0x19, 0x2f, 0x53, 0xef, + 0x8d, 0xa2, 0x4c, 0x29, 0x84, 0xe7, 0x0e, 0x52, 0xb4, 0x0c, 0x4c, 0xe1, + 0x90, 0xef, 0xd7, 0xd9, 0xb8, 0xb9, 0xd3, 0x46, 0xcf, 0x69, 0xd6, 0x35, + 0x59, 0xed, 0x0d, 0x02, 0xc7, 0xa7, 0xf2, 0x6b, 0x5e, 0xdd, 0x86, 0x52, + 0xc2, 0x85, 0xc2, 0x92, 0x69, 0x04, 0x51, 0x93, 0x7d, 0xa2, 0x22, 0x32, + 0x87, 0xa2, 0x9e, 0x76, 0x16, 0xc2, 0x01, 0x4c, 0x9a, 0x96, 0x82, 0xd1, + 0x98, 0xdc, 0xe0, 0xbe, 0x1a, 0xb0, 0x03, 0x1e, 0x2f, 0x44, 0x79, 0xc0, + 0x59, 0x95, 0x57, 0xa5, 0xc9, 0xcf, 0x55, 0x75, 0x78, 0x1d, 0xe2, 0x43, + 0x3a, 0x6b, 0x5f, 0xde, 0x5a, 0x32, 0x0f, 0x0e, 0x38, 0x36, 0xe4, 0x74, + 0x7a, 0x67, 0xd4, 0x88, 0x7e, 0x15, 0x7b, 0x32, 0xf8, 0x57, 0xd4, 0x27, + 0x38, 0xf4, 0x79, 0xf6, 0x7c, 0x0c, 0x6a, 0x1f, 0xbb, 0x22, 0x15, 0x46, + 0x4f, 0xec, 0x0b, 0xfc, 0xd8, 0x80, 0x87, 0xf4, 0x4c, 0x80, 0x9f, 0xa5, + 0x7a, 0xa5, 0x8f, 0x20, 0x22, 0x61, 0x53, 0xbf, 0xa5, 0x11, 0x87, 0x84, + 0x2b, 0xe3, 0x6d, 0x0d, 0x09, 0x00, 0x5f, 0x5f, 0x7f, 0xb6, 0x3c, 0x0c, + 0xc3, 0x0f, 0x93, 0xd5, 0x9c, 0xba, 0xb0, 0x7e, 0x4a, 0x37, 0xfa, 0xbf, + 0xe1, 0x22, 0x00, 0x49, 0xb6, 0x97, 0x08, 0x4e, 0x4e, 0x77, 0xd0, 0x36, + 0xa9, 0x6e, 0x3b, 0x07, 0x07, 0xe0, 0xab, 0x29, 0x6c, 0xc2, 0x2e, 0xf4, + 0x8e, 0x61, 0xe0, 0x36, 0x08, 0xd2, 0x01, 0x1a, 0x66, 0x99, 0x30, 0xbc, + 0xd9, 0x59, 0x41, 0x21, 0x58, 0x6f, 0xc5, 0xa3, 0xf3, 0x76, 0x1a, 0x75, + 0x60, 0xba, 0x28, 0x32, 0xdd, 0x38, 0x61, 0x45, 0x5d, 0x73, 0xc2, 0x36, + 0xb2, 0xf8, 0x2a, 0xb0, 0xa2, 0x3c, 0x40, 0x3d, 0x39, 0x7d, 0x1e, 0xe9, + 0x22, 0xa4, 0x7e, 0xc2, 0xd2, 0x80, 0x09, 0x3a, 0xd8, 0xe5, 0x73, 0x9e, + 0x46, 0x0b, 0x32, 0x74, 0x6d, 0x11, 0x96, 0xf2, 0x22, 0xc8, 0xd7, 0xbd, + 0x52, 0x92, 0x28, 0x59, 0x4a, 0xd7, 0x1e, 0x07, 0x2c, 0xc0, 0x13, 0x15, + 0xb3, 0x33, 0x9a, 0x76, 0xb2, 0x2b, 0x65, 0xe7, 0x4d, 0xc1, 0xf8, 0xa6, + 0x9c, 0xae, 0x70, 0x05, 0x98, 0x3f, 0xed, 0x56, 0xf2, 0xe2, 0x79, 0x40, + 0x02, 0x02, 0x03, 0xe7, 0x31, 0x82, 0x02, 0xf1, 0x30, 0x0d, 0x0c, 0x05, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0c, 0x04, 0x67, 0x65, 0x6e, 0x70, 0x30, + 0x1c, 0x0c, 0x04, 0x68, 0x61, 0x73, 0x68, 0x04, 0x14, 0xdb, 0xdd, 0x56, + 0xf1, 0xcb, 0x6a, 0xc9, 0x4a, 0xa8, 0x96, 0x8c, 0x91, 0xc1, 0x78, 0x69, + 0xe1, 0x42, 0x97, 0x32, 0x34, 0x30, 0x82, 0x02, 0xc0, 0x0c, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x04, 0x82, 0x02, 0xb6, 0x03, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x8f, 0xe0, 0xd5, 0xc6, 0x5f, + 0x89, 0xe9, 0x4c, 0x90, 0xda, 0xe0, 0xe9, 0xee, 0x3a, 0xdd, 0x7d, 0x61, + 0x54, 0x3e, 0xef, 0xa7, 0xea, 0x3a, 0x97, 0x2a, 0x9b, 0x56, 0x7c, 0x69, + 0xf9, 0x51, 0x2f, 0x40, 0x36, 0x16, 0xc0, 0xd6, 0x3f, 0xf9, 0x2e, 0xfe, + 0x44, 0x07, 0x8e, 0xc6, 0x71, 0x70, 0x86, 0x73, 0x52, 0xa8, 0x76, 0x37, + 0x42, 0x01, 0x93, 0xbe, 0x8c, 0x51, 0xd9, 0x4e, 0x45, 0xe8, 0xf9, 0x7c, + 0x4f, 0x16, 0x13, 0x80, 0x4d, 0x47, 0xd0, 0x59, 0x4e, 0xeb, 0x40, 0x2a, + 0x99, 0xa0, 0x7e, 0x77, 0x44, 0xf0, 0x62, 0xb8, 0x26, 0x39, 0x28, 0x18, + 0x88, 0xdb, 0x37, 0x0c, 0xf1, 0x37, 0x9b, 0x21, 0xbc, 0x50, 0xb7, 0x0f, + 0x9d, 0xa3, 0xcd, 0x36, 0x5d, 0x7d, 0xc7, 0x14, 0x20, 0x82, 0x66, 0x15, + 0x63, 0xce, 0x54, 0x04, 0x04, 0xbd, 0x85, 0x2b, 0xcc, 0xba, 0xdd, 0x65, + 0x7b, 0x8b, 0x6e, 0x0b, 0x8a, 0x51, 0x86, 0xdc, 0xaa, 0x14, 0xef, 0xcd, + 0x06, 0xaf, 0x7c, 0x28, 0xe3, 0x08, 0xc3, 0xaf, 0x87, 0x14, 0x51, 0x03, + 0x4c, 0xe8, 0x0f, 0x20, 0xd5, 0x2c, 0x81, 0x11, 0xce, 0x09, 0x26, 0x09, + 0x8a, 0x51, 0x28, 0x15, 0xef, 0xeb, 0x8c, 0x41, 0xbb, 0xa8, 0x6f, 0x2a, + 0x4c, 0x2d, 0x63, 0x6a, 0x9e, 0x5a, 0x3d, 0xcb, 0x16, 0x50, 0xc3, 0x4b, + 0xe5, 0x11, 0x8c, 0x7b, 0x2a, 0x63, 0x04, 0x42, 0xe0, 0x82, 0x76, 0x17, + 0x47, 0x0f, 0x36, 0x5d, 0x5e, 0x42, 0xa0, 0x86, 0x15, 0xe4, 0x8b, 0x2e, + 0x63, 0xa0, 0x5e, 0x14, 0x02, 0x73, 0x9b, 0x1c, 0x82, 0x5d, 0x02, 0x9f, + 0x99, 0x13, 0x59, 0x7b, 0x2a, 0xe8, 0xf6, 0xea, 0xb4, 0x15, 0x0e, 0xe2, + 0x27, 0x14, 0xdd, 0x45, 0xce, 0x84, 0x24, 0xb6, 0x46, 0x46, 0x48, 0x15, + 0xb6, 0x85, 0xa8, 0x38, 0xc9, 0x51, 0xe8, 0xae, 0x29, 0xfa, 0xbd, 0x1b, + 0x9e, 0x04, 0x5b, 0x5f, 0x35, 0x49, 0xc2, 0x12, 0xfb, 0x27, 0xa5, 0xac, + 0x5b, 0xac, 0x23, 0x00, 0x25, 0xfd, 0x45, 0x85, 0x0a, 0x70, 0x0e, 0xcc, + 0xa5, 0xc3, 0xce, 0x73, 0xe6, 0xe1, 0xd8, 0xb5, 0x28, 0x9c, 0x9c, 0x79, + 0x09, 0xc3, 0x40, 0xb5, 0x73, 0x8a, 0x75, 0x4f, 0xd5, 0x35, 0x90, 0xb2, + 0x2d, 0xdd, 0x5d, 0x89, 0xb9, 0x6d, 0xd8, 0x35, 0x26, 0x81, 0x7d, 0xa3, + 0xc1, 0x04, 0x95, 0xd1, 0xe4, 0x86, 0x5d, 0x9d, 0xef, 0xa9, 0x5c, 0x42, + 0x8e, 0x26, 0x18, 0x1e, 0x9a, 0xe4, 0x90, 0x8b, 0xff, 0x98, 0x19, 0x77, + 0x06, 0xb4, 0x79, 0xda, 0x1e, 0xfa, 0x83, 0xd1, 0x8c, 0x62, 0x1b, 0x17, + 0xe6, 0xce, 0xbd, 0x28, 0xe1, 0x73, 0x4c, 0x8d, 0xb1, 0x1b, 0x1b, 0xf6, + 0xa0, 0x7b, 0x98, 0xa7, 0xa2, 0xd3, 0xfd, 0x31, 0x70, 0x40, 0x25, 0x16, + 0xfa, 0xd7, 0x44, 0x0b, 0x68, 0xba, 0x09, 0xf9, 0x4e, 0xb7, 0xa6, 0xcd, + 0x9c, 0x0c, 0xd4, 0x98, 0xc4, 0xcc, 0x6b, 0x50, 0xeb, 0x23, 0xc2, 0x5a, + 0x33, 0xd9, 0x2f, 0x31, 0xfd, 0xba, 0xe5, 0x99, 0x5f, 0xdc, 0x21, 0x7c, + 0x47, 0x1e, 0x3a, 0xc2, 0x0b, 0xdd, 0xcf, 0xb4, 0x10, 0x15, 0xc4, 0xa0, + 0xeb, 0x85, 0xb6, 0x5f, 0x94, 0x03, 0x97, 0x67, 0xd8, 0x0d, 0xb7, 0xce, + 0xe7, 0x16, 0x15, 0x34, 0x92, 0xcf, 0x90, 0x50, 0xc5, 0xeb, 0x63, 0xc8, + 0xcd, 0xb4, 0x8d, 0xa1, 0x2f, 0xd1, 0x80, 0xcd, 0x36, 0xaa, 0x63, 0xb4, + 0xae, 0x7b, 0x0d, 0x07, 0x59, 0xc2, 0x54, 0x8f, 0xd7, 0x83, 0xd9, 0xd6, + 0xb3, 0xd3, 0x7e, 0x66, 0xc8, 0x0c, 0x57, 0x02, 0x6b, 0x4b, 0x8a, 0x74, + 0x47, 0x96, 0x39, 0x20, 0x0c, 0xad, 0xb8, 0xd1, 0x05, 0x92, 0xfe, 0x0d, + 0x1d, 0x4a, 0x65, 0x32, 0x53, 0x9b, 0x3d, 0xdb, 0x2d, 0x10, 0xd3, 0x0a, + 0x42, 0x79, 0xe0, 0x02, 0xc3, 0xe1, 0xec, 0x3d, 0xde, 0x57, 0x8d, 0x03, + 0x7e, 0x98, 0x62, 0x6c, 0x4a, 0x23, 0xa8, 0x3e, 0xd7, 0x11, 0x03, 0x0b, + 0x04, 0xae, 0x12, 0xb2, 0xde, 0xb5, 0x2b, 0x6c, 0x99, 0x9f, 0x0a, 0x42, + 0x20, 0x35, 0x2d, 0x0d, 0xfb, 0x9f, 0xdc, 0xfd, 0x31, 0x14, 0xbd, 0x07, + 0x94, 0x58, 0x7d, 0xd5, 0x9a, 0x3b, 0xe2, 0xf0, 0xd6, 0x50, 0xff, 0x5e, + 0x0a, 0xf0, 0xd6, 0x60, 0xb8, 0xa2, 0x71, 0x32, 0x11, 0xb7, 0x10, 0x08, + 0x70, 0xe7, 0x9d, 0xac, 0x5d, 0x14, 0x6e, 0xa0, 0x7d, 0x27, 0x2c, 0xd0, + 0xbd, 0xf1, 0x6e, 0x82, 0xdc, 0x6d, 0x57, 0x46, 0xf2, 0xe4, 0x96, 0x43, + 0x19, 0xc5, 0x9f, 0xe0, 0x8c, 0x6a, 0x0a, 0x55, 0x4a, 0xda, 0x3e, 0xdf, + 0x9c, 0x3b, 0xf1, 0x3e, 0x13, 0x3b, 0x7e, 0x9e, 0x76, 0xde, 0xeb, 0x3e, + 0x69, 0xd1, 0xa4, 0x47, 0x54, 0x30, 0xb8, 0x38, 0x15, 0x15, 0x27, 0x49, + 0x29, 0x93, 0xf0, 0xc6, 0x8a, 0xfa, 0xc0, 0xbb, 0xd4, 0xe3, 0x36, 0xcc, + 0xb8, 0x5e, 0x1a, 0x05, 0x57, 0xde, 0xa4, 0xbc, 0xbd, 0x21, 0x17, 0xda, + 0xd4, 0x96, 0x8d, 0x01, 0xa7, 0x79, 0xaa, 0x04, 0x43, 0xaf, 0x6a, 0xd2, + 0xb4, 0x2d, 0xc6, 0x15, 0x27, 0x02, 0x02, 0x03, 0xe7, 0x04, 0x14, 0x20, + 0x5a, 0x6b, 0x14, 0x4b, 0x34, 0x12, 0xc6, 0x71, 0x8c, 0xe4, 0xa8, 0x07, + 0x83, 0x0e, 0xe0, 0x6f, 0x2d, 0xe6, 0x13, 0x02, 0x02, 0x03, 0xe7 +}; + +/* Test backup-restore case, when item had inconsistently set pdmn attribute (due to another bug), + and mobile restore restored item with inconsistent attributes and afterwards tried SecItemUpdate() + on it, which failed, leading to the failure of the whole restore operation. + */ + +#if 0 +static bool SecKeychainWithBackupFile(CFStringRef backupName, CFErrorRef *error, void(^with)(FILE *bufile)) { + int fd = SecItemBackupHandoffFD(backupName, error); + if (fd < 0) + return false; + FILE *backup = fdopen(fd, "r"); + FILE *file = fopen_journal(fname, "w", error); + + if (!backup) { + close(fd); + return SecCheckErrno(!backup, error, CFSTR("fdopen")); + } + with(backup); + fclose(backup); + return true; +} + +static void secd_perform_with_data_in_file(const char* test_prefix, void(^with)(CFDataRef backupData)) +{ + CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random()); + + CFStringPerformWithCString(tmp_dir, ^(const char *tmp_dir_string) { + errno_t err = mkpath_np(tmp_dir_string, 0755); + ok(err == 0 || err == EEXIST, "Create temp dir %s (%d)", tmp_dir_string, err); + FILE *file = fopen(fname, "w", error); + + }); + + /* set custom keychain dir, reset db */ + SetCustomHomeURLString(tmp_dir); + + if(do_before_reset) + do_before_reset(); + + SecKeychainDbReset(NULL); + + CFReleaseNull(tmp_dir); + CFReleaseNull(keychain_dir); +} +#endif + + +static void tests(void) +{ + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_34_backup_der_parse", ^{}); + + (void)backup_data; + +#if 0 + FILE *backup = NULL; + CFErrorRef *error = NULL; + CFDataRef backupData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, backup_data, array_size(backup_data), kCFAllocatorNull); + + CFWriteStreamCreateWithBuffer(kCFAllocatorDefault, <#UInt8 *buffer#>, <#CFIndex bufferCapacity#>) + ok(SecKeychainWithBackupFileParse(backup, error, ^(SecBackupEventType et, CFTypeRef key, CFTypeRef item) { + diag("This still fails - don't be alarmed"); + })); + CFReleaseSafe(error); +#endif + +#if 0 + ok( SecKeychainWithBackupFileParse + (FILE *backup, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item))); + fclose(backup); + SecItemBackupWithChanges(CFSTR("SecureBackupService"), &error, ^(SecBackupEventType et, CFTypeRef key, CFTypeRef item) { + ; + }); + + CFStreamRef + /* Restore keychain from plist. */ + CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, keybag_data, sizeof(keybag_data)); + CFDataRef backup = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)export_plist, sizeof(export_plist)); + ok_status(_SecKeychainRestoreBackup(backup, keybag, NULL)); + CFRelease(keybag); + CFRelease(backup); + + /* The restored item is kind of malformed (pdmn and accc attributes are inconsistent). Currently adopted way + of handling of this item is to try to handle it gracefully, this is what this test does (i.e. it checks that + it is possible to update such item). Another possibility which might be adopted in the future is dropping such + item during backup decoding. In this case, the test should be modified to check that the item does not exist + in the keychain at all. */ + + /* Try to update item with inconsistent accc and pdmn attributes. */ + CFDictionaryRef query = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), + kSecAttrService, CFSTR("test"), + NULL); + CFDictionaryRef update = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrService, CFSTR("updated-test"), + NULL); + + ok_status(SecItemUpdate(query, update)); + diag("This still fails - don't be alarmed"); + CFRelease(update); + CFRelease(query); +#endif + +} + +int secd_32_restore_bad_backup(int argc, char *const *argv) +{ + plan_tests(2 + kSecdTestSetupTestCount); + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m b/keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m new file mode 100644 index 00000000..71c789f8 --- /dev/null +++ b/keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "secd_regressions.h" + +#include "keychain/securityd/SecDbItem.h" +#include +#include +#include +#include + +#include "keychain/securityd/SecItemServer.h" + +#include + +#include +#include + +#if TARGET_OS_IPHONE && USE_KEYSTORE +#include "OSX/utilities/SecAKSWrappers.h" + +#include "SecdTestKeychainUtilities.h" + +#include "ios8-inet-keychain-2.h" + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(void); + +int secd_35_keychain_migrate_inet(int argc, char *const *argv) +{ + plan_tests(11 + kSecdTestSetupTestCount); + + __block keybag_handle_t keybag; + __block keybag_state_t state; + char *passcode="password"; + int passcode_len=(int)strlen(passcode); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_35_keychain_migrate_inet", ^{ + CFStringRef keychain_path_cf = __SecKeychainCopyPath(); + + CFStringPerformWithCString(keychain_path_cf, ^(const char *keychain_path) { + writeFile(keychain_path, ios8_inet_keychain_2_db, ios8_inet_keychain_2_db_len); + + /* custom notification */ + SecItemServerSetKeychainChangedNotification("com.apple.secdtests.keychainchanged"); + + /* Create and lock custom keybag */ + ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(keybag); + + /* lock */ + ok(kAKSReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + }); + + CFReleaseSafe(keychain_path_cf); + }); + + CFArrayRef old_ag = CFRetainSafe(SecAccessGroupsGetCurrent()); + CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); + CFArrayAppendValue(test_ag, CFSTR("com.apple.cfnetwork")); + SecAccessGroupsSetCurrent(test_ag); + + /* querying a password */ + const void *keys[] = { + kSecClass, + kSecAttrAccessGroup, + kSecAttrSynchronizable, + kSecMatchLimit, + kSecReturnAttributes, + }; + const void *values[] = { + kSecClassInternetPassword, + CFSTR("com.apple.cfnetwork"), + kSecAttrSynchronizableAny, + kSecMatchLimitAll, + kCFBooleanTrue, + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + array_size(keys), NULL, NULL); + CFTypeRef results = NULL; + is_status(SecItemCopyMatching(query, &results), errSecInteractionNotAllowed); + + ok(kAKSReturnSuccess==aks_unlock_bag(keybag, passcode, passcode_len), "lock keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + + // We should be able to query 2 inet items from the DB here. But the database is encrypted + // by keybag which we do not know, so no item can be actually retrieved. The test could be + // improved by crafting DB to update using keybag hardcoded in the test, that way it would be possible + // to check that 2 inet items are really retrieved here. + is_status(SecItemCopyMatching(query, &results), errSecItemNotFound); + + /* Reset keybag */ + SecItemServerResetKeychainKeybag(); + + // Reset server accessgroups. + SecAccessGroupsSetCurrent(old_ag); + CFReleaseNull(old_ag); + CFReleaseSafe(test_ag); + + CFReleaseSafe(results); + CFReleaseSafe(query); + return 0; +} + +#else + +int secd_35_keychain_migrate_inet(int argc, char *const *argv) +{ + plan_tests(1); + + todo("Not yet working in simulator"); + +TODO: { + ok(false); +} + /* not implemented in simulator (no keybag) */ + /* Not implemented in OSX (no upgrade scenario) */ + return 0; +} +#endif diff --git a/keychain/securityd/Regressions/secd-36-ks-encrypt.m b/keychain/securityd/Regressions/secd-36-ks-encrypt.m new file mode 100644 index 00000000..ff85cb8f --- /dev/null +++ b/keychain/securityd/Regressions/secd-36-ks-encrypt.m @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "secd_regressions.h" + +#include + +#include +#include "SecDbKeychainItem.h" + +#include + +#if USE_KEYSTORE +#include "OSX/utilities/SecAKSWrappers.h" + +#include "SecdTestKeychainUtilities.h" + +int secd_36_ks_encrypt(int argc, char *const *argv) +{ + plan_tests(9); + + secd_test_setup_temp_keychain("secd_36_ks_encrypt", NULL); + + keybag_handle_t keybag; + keybag_state_t state; + CFDictionaryRef data = NULL; + CFDataRef enc = NULL; + CFErrorRef error = NULL; + SecAccessControlRef ac = NULL; + bool ret; + + char passcode[] = "password"; + int passcode_len = sizeof(passcode) - 1; + + + /* Create and lock custom keybag */ + is(kAKSReturnSuccess, aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + is(kAKSReturnSuccess, aks_get_lock_state(keybag, &state), "get keybag state"); + is(0, (int)(state&keybag_state_locked), "keybag unlocked"); + + data = (__bridge CFDictionaryRef)@{ + (id)kSecValueData : @"secret here", + }; + + ok(ac = SecAccessControlCreate(NULL, &error), "SecAccessControlCreate: %@", error); + ok(SecAccessControlSetProtection(ac, kSecAttrAccessibleWhenUnlocked, &error), "SecAccessControlSetProtection: %@", error); + + ret = ks_encrypt_data(keybag, ac, NULL, data, (__bridge CFDictionaryRef)@{@"persistref" : @"aaa-bbb-ccc"}, NULL, &enc, true, &error); + is(true, ret); + + CFReleaseNull(ac); + + { + CFMutableDictionaryRef attributes = NULL; + uint32_t version = 0; + + ret = ks_decrypt_data(keybag, kAKSKeyOpDecrypt, &ac, NULL, enc, NULL, NULL, &attributes, &version, true, NULL, &error); + is(true, ret, "ks_decrypt_data: %@", error); + + CFTypeRef aclProtection = ac ? SecAccessControlGetProtection(ac) : NULL; + ok(aclProtection && CFEqual(aclProtection, kSecAttrAccessibleWhenUnlocked), "AccessControl protection is: %@", aclProtection); + + CFReleaseNull(ac); + } + + CFReleaseNull(error); + CFReleaseNull(enc); + + return 0; +} + +#else /* !USE_KEYSTORE */ + +int secd_36_ks_encrypt(int argc, char *const *argv) +{ + plan_tests(1); + ok(true); + return 0; +} +#endif /* USE_KEYSTORE */ diff --git a/keychain/securityd/Regressions/secd-37-pairing-initial-sync.m b/keychain/securityd/Regressions/secd-37-pairing-initial-sync.m new file mode 100644 index 00000000..1e2d001d --- /dev/null +++ b/keychain/securityd/Regressions/secd-37-pairing-initial-sync.m @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "secd_regressions.h" + +#include "keychain/securityd/SecItemServer.h" + +#include "SecdTestKeychainUtilities.h" + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(void); + + +static void AddItem(NSDictionary *attr) +{ + NSMutableDictionary *mattr = [attr mutableCopy]; + mattr[(__bridge id)kSecValueData] = [NSData dataWithBytes:"foo" length:3]; + mattr[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + ok_status(SecItemAdd((__bridge CFDictionaryRef)mattr, NULL)); +} + +int secd_37_pairing_initial_sync(int argc, char *const *argv) +{ + CFErrorRef error = NULL; + CFTypeRef stuff = NULL; + OSStatus res = 0; + + plan_tests(16); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_37_pairing_initial_sync", NULL); + + CFArrayRef currentACL = CFRetainSafe(SecAccessGroupsGetCurrent()); + + NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; + [newACL addObjectsFromArray:@[ + @"com.apple.ProtectedCloudStorage", + ]]; + + SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); + + + NSDictionary *pcsinetattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"1", + (__bridge id)kSecAttrServer : @"current", + (__bridge id)kSecAttrType : @(0x10001), + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *pcsinetattrsNotCurrent = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"1", + (__bridge id)kSecAttrServer : @"noncurrent", + (__bridge id)kSecAttrType : @(0x00001), + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *pcsgenpattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"2", + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *ckksattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (__bridge id)kSecAttrAccount : @"2", + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + AddItem(pcsinetattrs); + AddItem(pcsinetattrsNotCurrent); + AddItem(pcsgenpattrs); + AddItem(ckksattrs); + + CFArrayRef items = _SecServerCopyInitialSyncCredentials(SecServerInitialSyncCredentialFlagTLK | SecServerInitialSyncCredentialFlagPCS, &error); + ok(items, "_SecServerCopyInitialSyncCredentials: %@", error); + CFReleaseNull(error); + + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + + + ok(_SecItemDeleteAll(&error), "SecItemServerDeleteAll: %@", error); + CFReleaseNull(error); + + ok(_SecServerImportInitialSyncCredentials(items, &error), "_SecServerImportInitialSyncCredentials: %@", error); + CFReleaseNull(error); + CFReleaseNull(items); + + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + is_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), errSecItemNotFound, + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + + SecAccessGroupsSetCurrent(currentACL); + CFReleaseNull(currentACL); + + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-40-cc-gestalt.m b/keychain/securityd/Regressions/secd-40-cc-gestalt.m new file mode 100644 index 00000000..8bfd1ef6 --- /dev/null +++ b/keychain/securityd/Regressions/secd-40-cc-gestalt.m @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include +#include "secd_regressions.h" + +static int kTestTestCount = 1; +static void tests(void) +{ + CFStringRef osVersion = SOSCCCopyOSVersion(); + + ok(osVersion != NULL, "OS Version Exists"); + + CFReleaseNull(osVersion); +} + +int secd_40_cc_gestalt(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-49-manifests.m b/keychain/securityd/Regressions/secd-49-manifests.m new file mode 100644 index 00000000..e12ff1be --- /dev/null +++ b/keychain/securityd/Regressions/secd-49-manifests.m @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "keychain/SecureObjectSync/SOSManifest.h" +#include "keychain/SecureObjectSync/SOSMessage.h" + +#include "secd_regressions.h" + +#include +#include +#include +#include "keychain/SecureObjectSync/SOSDigestVector.h" +#include "keychain/securityd/SecDbItem.h" +#include + +static int kTestTestCount = 68; + + +#define okmfcomplement(r, b, n, ...) test_okmfcomplement(r, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) +#define okmfdiff(a, b, eab,eba, ...) test_okmfdiff(a, b, eab, eba, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) +#define okmfintersection(a, b, n, ...) test_okmfintersection(a, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) +#define okmfpatch(b, r, a, n, ...) test_okmfpatch(b, r, a, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) +#define okmfunion(a, b, n, ...) test_okmfunion(a, b, n, test_create_description(__VA_ARGS__), test_directive, test_reason, __FILE__, __LINE__, NULL) + +static void appendManifestDescription(CFMutableStringRef string, CFStringRef prefix, SOSManifestRef mf) { + if (prefix) + CFStringAppend(string, prefix); + if (!mf) { + CFStringAppend(string, CFSTR("null")); + } else if (SOSManifestGetCount(mf) == 0) { + CFStringAppend(string, CFSTR("empty")); + } else { + char prefix = '{'; + const uint8_t *d = SOSManifestGetBytePtr(mf); + for (CFIndex endIX = SOSManifestGetCount(mf), curIX = 0; curIX < endIX; ++curIX, d += SOSDigestSize) { + CFStringAppendFormat(string, NULL, CFSTR("%c%c"), prefix, *d); + prefix = ' '; + } + CFStringAppend(string, CFSTR("}")); + } +} + +static int appendManifestComparison(CFMutableStringRef string, CFStringRef prefix, SOSManifestRef expected, SOSManifestRef computed) { + int passed = 0; + appendManifestDescription(string, prefix, computed); + if (CFEqualSafe(computed, expected)) { + // ok + passed = 1; + } else { + // wrong + appendManifestDescription(string, CFSTR("!="), expected); + } + return passed; +} + +static void test_okmfcomplement(SOSManifestRef r, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { + CFErrorRef error = NULL; + int passed = 0; + CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); + if (test_description && CFStringGetLength(test_description) != 0) + CFStringAppend(extendedDescription, CFSTR(" ")); + appendManifestDescription(extendedDescription, CFSTR("complement "), r); + appendManifestDescription(extendedDescription, CFSTR("->"), b); + SOSManifestRef new = SOSManifestCreateComplement(r, b, &error); + if (!new) { + CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateComplement: %@"), error); + } else { + passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); + } + test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); + CFReleaseSafe(test_description); + CFReleaseSafe(new); + CFReleaseSafe(error); +} + +static void test_okmfdiff(SOSManifestRef a, SOSManifestRef b, SOSManifestRef exp_a_b, SOSManifestRef exp_b_a, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { + CFErrorRef error = NULL; + SOSManifestRef a_minus_b = NULL; + SOSManifestRef b_minus_a = NULL; + int passed = 0; + CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); + if (test_description && CFStringGetLength(test_description) != 0) + CFStringAppend(extendedDescription, CFSTR(" ")); + appendManifestDescription(extendedDescription, CFSTR("diff "), a); + appendManifestDescription(extendedDescription, CFSTR("->"), b); + if (!SOSManifestDiff(a, b, &a_minus_b, &b_minus_a, &error)) { + CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestDiff: %@"), error); + } else { + passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), exp_a_b, a_minus_b); + passed &= appendManifestComparison(extendedDescription, CFSTR("->"), exp_b_a, b_minus_a); + } + test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); + CFReleaseSafe(test_description); + CFReleaseSafe(a_minus_b); + CFReleaseSafe(b_minus_a); + CFReleaseSafe(error); +} + +static void test_okmfintersection(SOSManifestRef a, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { + CFErrorRef error = NULL; + int passed = 0; + CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); + if (test_description && CFStringGetLength(test_description) != 0) + CFStringAppend(extendedDescription, CFSTR(" ")); + appendManifestDescription(extendedDescription, CFSTR("intersection "), a); + appendManifestDescription(extendedDescription, CFSTR("->") /*CFSTR(" \xe2\x88\xa9 ")*/, b); + SOSManifestRef new = SOSManifestCreateIntersection(a, b, &error); + if (!new) { + CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateIntersection: %@"), error); + } else { + passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); + } + test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); + CFReleaseSafe(test_description); + CFReleaseSafe(new); + CFReleaseSafe(error); +} + +static void test_okmfpatch(SOSManifestRef b, SOSManifestRef r, SOSManifestRef a, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { + CFErrorRef error = NULL; + int passed = 0; + CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); + if (test_description && CFStringGetLength(test_description) != 0) + CFStringAppend(extendedDescription, CFSTR(" ")); + appendManifestDescription(extendedDescription, CFSTR("patch "), b); + appendManifestDescription(extendedDescription, CFSTR("->"), r); + appendManifestDescription(extendedDescription, CFSTR("->"), a); + SOSManifestRef new = SOSManifestCreateWithPatch(b, r, a, &error); + if (!new) { + CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateWithPatch: %@"), error); + } else { + passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); + } + test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); + CFReleaseSafe(test_description); + CFReleaseSafe(new); + CFReleaseSafe(error); +} + +static void test_okmfunion(SOSManifestRef a, SOSManifestRef b, SOSManifestRef n, __attribute((cf_consumed)) CFStringRef test_description, const char *test_directive, const char *reason, const char *file, unsigned line, const char *fmt, ...) { + CFErrorRef error = NULL; + int passed = 0; + CFMutableStringRef extendedDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, test_description); + if (test_description && CFStringGetLength(test_description) != 0) + CFStringAppend(extendedDescription, CFSTR(" ")); + appendManifestDescription(extendedDescription, CFSTR("union "), a); + appendManifestDescription(extendedDescription, CFSTR("->") /*CFSTR(" \xe2\x88\xaa ")*/, b); + SOSManifestRef new = SOSManifestCreateUnion(a, b, &error); + if (!new) { + CFStringAppendFormat(extendedDescription, NULL, CFSTR(" SOSManifestCreateUnion: %@"), error); + } else { + passed = appendManifestComparison(extendedDescription, CFSTR(" -> "), n, new); + } + test_ok(passed, extendedDescription, test_directive, test_reason, file, line, NULL); + CFReleaseSafe(test_description); + CFReleaseSafe(new); + CFReleaseSafe(error); +} + +static SOSManifestRef createManifestWithString(CFStringRef string) { + struct SOSDigestVector dv = SOSDigestVectorInit; + CFIndex length = string ? CFStringGetLength(string) : 0; + CFStringInlineBuffer buf = {}; + CFRange range = { 0, length }; + CFStringInitInlineBuffer(string, &buf, range); + for (CFIndex ix = 0; ix < length; ++ix) { + uint8_t digest[20] = " "; + UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, ix); + digest[0] = c; + SOSDigestVectorAppend(&dv, digest); + } + SOSManifestRef mf = NULL; + mf = SOSManifestCreateWithDigestVector(&dv, NULL); + SOSDigestVectorFree(&dv); + return mf; +} + +static SOSManifestRef testCreateBadManifest() { + SOSManifestRef mf = createManifestWithString(CFSTR("bab")); + is(SOSManifestGetCount(mf), (size_t)2, "dupes eliminated?"); + return mf; +} + + +typedef struct mf_vectors { + SOSManifestRef null; + SOSManifestRef empty; + SOSManifestRef a; + SOSManifestRef b; + SOSManifestRef ab; + SOSManifestRef bab; + SOSManifestRef agh; + SOSManifestRef gh; + SOSManifestRef agghhjk; + SOSManifestRef gghh; + SOSManifestRef agghh; +} mf_t; + +static void setupMF(mf_t *mf) { + CFErrorRef error = NULL; + mf->null = NULL; + mf->empty = SOSManifestCreateWithBytes(NULL, 0, &error); + mf->a = createManifestWithString(CFSTR("a")); + mf->b = createManifestWithString(CFSTR("b")); + mf->ab = createManifestWithString(CFSTR("ab")); + mf->bab = testCreateBadManifest(); + mf->gh = createManifestWithString(CFSTR("gh")); + mf->agh = createManifestWithString(CFSTR("agh")); + mf->agghhjk = createManifestWithString(CFSTR("agghhjk")); + mf->gghh = createManifestWithString(CFSTR("gghh")); + mf->agghh = createManifestWithString(CFSTR("agghh")); +} + +static void teardownMF(mf_t *mf) { + if (!mf) return; + CFReleaseSafe(mf->empty); + CFReleaseSafe(mf->a); + CFReleaseSafe(mf->b); + CFReleaseSafe(mf->ab); + CFReleaseSafe(mf->bab); + CFReleaseSafe(mf->gh); + CFReleaseSafe(mf->agh); + CFReleaseSafe(mf->agghhjk); + CFReleaseSafe(mf->gghh); + CFReleaseSafe(mf->agghh); +} + +static void testNullManifest(SOSManifestRef mf) +{ + is(SOSManifestGetCount(mf), (size_t)0, "count is 0"); + is(SOSManifestGetSize(mf), (size_t)0, "capacity is 0"); +} + +static void testNull(mf_t *mf) { + testNullManifest(mf->null); + testNullManifest(mf->empty); +} + +static void testDiff(mf_t *mf) { + okmfdiff(mf->null, mf->null, mf->empty, mf->empty); + okmfdiff(mf->null, mf->empty, mf->empty, mf->empty); + okmfdiff(mf->null, mf->a, mf->empty, mf->a); + okmfdiff(mf->empty, mf->null, mf->empty, mf->empty); + okmfdiff(mf->empty, mf->empty, mf->empty, mf->empty); + okmfdiff(mf->empty, mf->a, mf->empty, mf->a); + okmfdiff(mf->a, mf->null, mf->a, mf->empty); + okmfdiff(mf->a, mf->empty, mf->a, mf->empty); + okmfdiff(mf->a, mf->a, mf->empty, mf->empty); + okmfdiff(mf->bab, mf->empty, mf->ab, mf->empty); + okmfdiff(mf->bab, mf->a, mf->b, mf->empty); + okmfdiff(mf->a, mf->bab, mf->empty, mf->b); + okmfdiff(mf->bab, mf->b, mf->a, mf->empty); + okmfdiff(mf->b, mf->bab, mf->empty, mf->a); + okmfdiff(mf->bab, mf->bab, mf->empty, mf->empty); +} + +static void testPatch(mf_t *mf) { + okmfpatch(mf->null, mf->null, mf->null, mf->empty); + okmfpatch(mf->empty, mf->empty, mf->empty, mf->empty); + okmfpatch(mf->bab, mf->b, mf->a, mf->a); + okmfpatch(mf->ab, mf->empty, mf->empty, mf->ab); + okmfpatch(mf->ab, mf->empty, mf->a, mf->ab); + okmfpatch(mf->bab, mf->empty, mf->a, mf->ab); + okmfpatch(mf->bab, mf->ab, mf->null, mf->empty); + okmfpatch(mf->bab, mf->empty, mf->empty, mf->ab); +} + +static void testUnion(mf_t *mf) { + okmfunion(mf->null, mf->null, mf->empty); + okmfunion(mf->null, mf->empty, mf->empty); + okmfunion(mf->empty, mf->null, mf->empty); + okmfunion(mf->empty, mf->empty, mf->empty); + okmfunion(mf->null, mf->a, mf->a); + okmfunion(mf->a, mf->null, mf->a); + okmfunion(mf->empty, mf->a, mf->a); + okmfunion(mf->a, mf->empty, mf->a); + okmfunion(mf->bab, mf->ab, mf->ab); + okmfunion(mf->empty, mf->bab, mf->ab); + okmfunion(mf->bab, mf->empty, mf->ab); +} + +static void testIntersect(mf_t *mf) { + okmfintersection(mf->null, mf->null, mf->empty); + okmfintersection(mf->null, mf->empty, mf->empty); + okmfintersection(mf->empty, mf->null, mf->empty); + okmfintersection(mf->empty, mf->empty, mf->empty); + okmfintersection(mf->null, mf->a, mf->empty); + okmfintersection(mf->a, mf->null, mf->empty); + okmfintersection(mf->empty, mf->a, mf->empty); + okmfintersection(mf->a, mf->empty, mf->empty); + okmfintersection(mf->bab, mf->ab, mf->ab); + okmfintersection(mf->bab, mf->a, mf->a); + okmfintersection(mf->a, mf->bab, mf->a); + okmfintersection(mf->b, mf->bab, mf->b); + okmfintersection(mf->bab, mf->bab, mf->ab); + okmfintersection(mf->gghh, mf->agghh, mf->gh); + okmfintersection(mf->agghhjk, mf->agghh, mf->agh); +} + +static void testComplement(mf_t *mf) { + okmfcomplement(mf->null, mf->null, mf->empty); + okmfcomplement(mf->null, mf->empty, mf->empty); + okmfcomplement(mf->empty, mf->null, mf->empty); + okmfcomplement(mf->empty, mf->empty, mf->empty); + okmfcomplement(mf->null, mf->a, mf->a); + okmfcomplement(mf->a, mf->null, mf->empty); + okmfcomplement(mf->empty, mf->a, mf->a); + okmfcomplement(mf->a, mf->empty, mf->empty); + okmfcomplement(mf->bab, mf->ab, mf->empty); + okmfcomplement(mf->ab, mf->bab, mf->empty); + okmfcomplement(mf->bab, mf->a, mf->empty); + okmfcomplement(mf->a, mf->bab, mf->b); + okmfcomplement(mf->b, mf->bab, mf->a); + okmfcomplement(mf->empty, mf->bab, mf->ab); +} + +static void tests(void) +{ + mf_t mf; + setupMF(&mf); + + testNull(&mf); + testDiff(&mf); + testPatch(&mf); + testUnion(&mf); + testIntersect(&mf); + testComplement(&mf); + + teardownMF(&mf); +} + +int secd_49_manifests(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-50-account.m b/keychain/securityd/Regressions/secd-50-account.m new file mode 100644 index 00000000..70ff2f44 --- /dev/null +++ b/keychain/securityd/Regressions/secd-50-account.m @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" + +static int kTestTestCount = 9 + kSecdTestSetupTestCount; +static void tests(void) +{ + NSError* error = nil; + CFErrorRef cfError = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); + + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); + + ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &cfError), "Credential setting (%@)", cfError); + CFReleaseNull(cfError); + CFReleaseNull(cfpassword); + + ok(NULL != account, "Created"); + + size_t size = [account.trust getDEREncodedSize:account err:&error]; + + error = nil; + uint8_t buffer[size]; + + uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; + error = nil; + + ok(start, "successful encoding"); + ok(start == buffer, "Used whole buffer"); + + const uint8_t *der = buffer; + SOSAccount* inflated = [SOSAccount accountFromDER:&der end:buffer + sizeof(buffer) + factory:test_factory error:&error]; + + ok(inflated, "inflated %@", error); + ok([inflated isEqual:account], "Compares"); + + error = nil; + + CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); + ok(SOSAccountResetToOffering_wTxn(account, &cfError), "Reset to Offering (%@)", error); + CFReleaseNull(cfError); + + is([account getCircleStatus:&cfError], kSOSCCInCircle, "Was in Circle (%@)", error); + CFReleaseNull(cfError); + + [account.trust updateGestalt:account newGestalt:new_gestalt]; + is([account getCircleStatus:&cfError], kSOSCCInCircle, "Still in Circle (%@)", error); + CFReleaseNull(cfError); + + CFReleaseNull(new_gestalt); + + SOSDataSourceFactoryRelease(test_factory); + SOSDataSourceRelease(test_source, NULL); + + account = nil; + inflated = nil; + + SOSTestCleanup(); +} + +int secd_50_account(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-50-message.m b/keychain/securityd/Regressions/secd-50-message.m new file mode 100644 index 00000000..67f198c1 --- /dev/null +++ b/keychain/securityd/Regressions/secd-50-message.m @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "keychain/SecureObjectSync/SOSManifest.h" +#include "keychain/SecureObjectSync/SOSMessage.h" + +#include "secd_regressions.h" + +#include +#include +#include "keychain/SecureObjectSync/SOSDigestVector.h" +#include "keychain/securityd/SecDbItem.h" + +static void testNullMessage(uint64_t msgid) +{ + SOSMessageRef sentMessage = NULL; + SOSMessageRef rcvdMessage = NULL; + SOSManifestRef sender = NULL; + CFErrorRef error = NULL; + CFDataRef data = NULL; + + // Encode + ok(sender = SOSManifestCreateWithBytes(NULL, 0, &error), "empty sender manifest create: %@", error); + CFReleaseNull(error); + ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, sender, NULL, NULL, false, &error), "sentMessage create: %@", error); + CFReleaseNull(error); + ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@", error); + CFReleaseNull(error); + + // Decode + ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); + CFReleaseNull(error); + __block size_t numObjects = 0; + SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { + numObjects++; + }); + ok(numObjects == 0, "no objects"); + + // Check if we got what we started with + ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); + + CFReleaseNull(data); + CFReleaseNull(sentMessage); + CFReleaseNull(rcvdMessage); + CFReleaseNull(sender); +} + +__unused static void testFlaggedMessage(const char *test_directive, const char *test_reason, uint64_t msgid, SOSMessageFlags flags) +{ + SOSMessageRef sentMessage = NULL; + SOSMessageRef rcvdMessage = NULL; + SOSManifestRef sender = NULL; + CFErrorRef error = NULL; + CFDataRef data = NULL; + + ok(sender = SOSManifestCreateWithBytes(NULL, 0, &error), "empty sender manifest create: %@", error); + CFReleaseNull(error); + ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, sender, NULL, NULL, false, &error), "sentMessage create: %@", error); + CFReleaseNull(error); + SOSMessageSetFlags(sentMessage, flags); + ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@", error); + CFReleaseNull(error); + + // Decode + ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); + CFReleaseNull(error); + __block size_t numObjects = 0; + SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { + numObjects++; + }); + ok(numObjects == 0, "no objects"); + + is(SOSMessageGetFlags(sentMessage), flags, "flags match after roundtrip"); + ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); + + CFReleaseNull(data); + CFReleaseNull(sentMessage); + CFReleaseNull(rcvdMessage); + CFReleaseNull(sender); +} + +__unused static void testDeltaManifestMessage(const char *test_directive, const char *test_reason, uint64_t msgid) +{ + SOSMessageRef sentMessage = NULL; + SOSMessageRef rcvdMessage = NULL; + SOSManifestRef sender = NULL; + SOSManifestRef proposed = NULL; + SOSManifestRef base = NULL; + CFErrorRef error = NULL; + CFDataRef data = NULL; + + struct SOSDigestVector dv = SOSDigestVectorInit; + SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that is 20 bytes long or so and stuff"); + SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); + SOSDigestVectorSort(&dv); + base = SOSManifestCreateWithBytes((const uint8_t *)dv.digest, dv.count * SOSDigestSize, &error); + SOSDigestVectorAppend(&dv, (const uint8_t *)"so much more is good to see here is another one for me"); + SOSDigestVectorAppend(&dv, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff!"); + SOSDigestVectorAppend(&dv, (const uint8_t *)"so much for is good to see here is another one for me"); + SOSDigestVectorSort(&dv); + if (msgid) + proposed = SOSManifestCreateWithBytes((const uint8_t *)dv.digest, dv.count * SOSDigestSize, &error); + + CFReleaseNull(error); + ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, proposed, base, proposed, true, &error), "sentMessage create: %@", error); + CFReleaseNull(base); + CFReleaseNull(proposed); + CFReleaseNull(error); + ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@ .. %@", error, sentMessage); + CFReleaseNull(error); + + // Decode + ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); + CFReleaseNull(error); + __block size_t numObjects = 0; + SOSMessageWithObjects(sentMessage, &error, ^(CFDataRef object, bool *stop) { + numObjects++; + }); + ok(numObjects == 0, "no objects"); + + ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); + + CFReleaseNull(data); + CFReleaseNull(sentMessage); + CFReleaseNull(rcvdMessage); + CFReleaseNull(sender); +} + +static CFDataRef testCopyAddedObject(SOSMessageRef message, CFPropertyListRef plist) +{ + CFErrorRef error = NULL; + CFDataRef der; + ok(der = CFPropertyListCreateDERData(kCFAllocatorDefault, plist, &error), "copy der: %@", error); + CFReleaseNull(error); + ok(SOSMessageAppendObject(message, der, &error), "likes object: %@", error); + CFReleaseNull(error); + return der; +} + +__unused static void testObjectsMessage(const char *test_directive, const char *test_reason, uint64_t msgid) +{ + SOSMessageRef sentMessage = NULL; + SOSMessageRef rcvdMessage = NULL; + SOSManifestRef sender = NULL; + SOSManifestRef proposed = NULL; + SOSManifestRef base = NULL; + CFErrorRef error = NULL; + CFDataRef data = NULL; + + struct SOSDigestVector dv1 = SOSDigestVectorInit; + struct SOSDigestVector dv2 = SOSDigestVectorInit; + SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that is 20 bytes long or so and stuff"); + SOSDigestVectorAppend(&dv2, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); + SOSDigestVectorAppend(&dv1, (const uint8_t *)"so much more is good to see here is another one for me"); + SOSDigestVectorAppend(&dv2, (const uint8_t *)"so much more is good to see here is another one for me"); + SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff"); + SOSDigestVectorAppend(&dv1, (const uint8_t *)"sha1 hash that was 23 bytes long or so and stuff!"); + SOSDigestVectorAppend(&dv2, (const uint8_t *)"so much for is good to see here is another one for me"); + SOSDigestVectorSort(&dv1); + SOSDigestVectorSort(&dv2); + base = SOSManifestCreateWithBytes((const uint8_t *)dv1.digest, dv1.count * SOSDigestSize, &error); + if (msgid) + proposed = SOSManifestCreateWithBytes((const uint8_t *)dv2.digest, dv2.count * SOSDigestSize, &error); + CFReleaseNull(error); + ok(sentMessage = SOSMessageCreateWithManifests(kCFAllocatorDefault, proposed, base, proposed, true, &error), "sentMessage create: %@", error); + CFReleaseNull(base); + CFReleaseNull(proposed); + CFDataRef O0, O1, O2, O3; + CFDataRef o0 = CFDataCreate(kCFAllocatorDefault, NULL, 0); + O0 = testCopyAddedObject(sentMessage, o0); + CFDataRef o1 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"test", 4); + O1 = testCopyAddedObject(sentMessage, o1); + CFDataRef o2 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"what an object", 14); + O2 = testCopyAddedObject(sentMessage, o2); + CFDataRef o3 = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"This one even has shiny stripe.", 31); + O3 = testCopyAddedObject(sentMessage, o3); + ok(data = SOSMessageCreateData(sentMessage, msgid, &error), "sentMessage data create: %@ .. %@", error, sentMessage); + CFReleaseNull(error); + + // Decode + ok(rcvdMessage = SOSMessageCreateWithData(kCFAllocatorDefault, data, &error), "rcvdMessage create: %@", error); + CFReleaseNull(error); + __block size_t numObjects = 0; + __block bool f0, f1, f2, f3; + f0 = f1 = f2 = f3 = false; + if (rcvdMessage) SOSMessageWithObjects(rcvdMessage, &error, ^(CFDataRef object, bool *stop) { + if (CFEqualSafe(object, O0)) f0 = true; + if (CFEqualSafe(object, O1)) f1 = true; + if (CFEqualSafe(object, O2)) f2 = true; + if (CFEqualSafe(object, O3)) f3 = true; + numObjects++; + }); + ok(f0, "got O0"); + ok(f1, "got O1"); + ok(f2, "got O2"); + ok(f3, "got O3"); + + ok(sentMessage && rcvdMessage && CFEqual(sentMessage, rcvdMessage), "sent %@ == rcvd %@", sentMessage, rcvdMessage); + + CFReleaseNull(o0); + CFReleaseNull(o1); + CFReleaseNull(o2); + CFReleaseNull(o3); + CFReleaseNull(O0); + CFReleaseNull(O1); + CFReleaseNull(O2); + CFReleaseNull(O3); + CFReleaseNull(data); + CFReleaseNull(sentMessage); + CFReleaseNull(rcvdMessage); + CFReleaseNull(sender); +} + +static void tests(void) +{ + testNullMessage(0); // v0 + + uint64_t msgid = 0; + testNullMessage(++msgid); // v2 + testFlaggedMessage(test_directive, test_reason, ++msgid, 0x865); + testFlaggedMessage(test_directive, test_reason, ++msgid, 0xdeadbeef); +} + +int secd_50_message(int argc, char *const *argv) +{ + plan_tests(26); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-51-account-inflate.m b/keychain/securityd/Regressions/secd-51-account-inflate.m new file mode 100644 index 00000000..08ee55e8 --- /dev/null +++ b/keychain/securityd/Regressions/secd-51-account-inflate.m @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" +#include "SOSTransportTestTransports.h" + +#if 0 +const uint8_t v6_der[] = { + 0x30, 0x82, 0x06, 0xee, 0x02, 0x01, 0x06, 0x31, 0x4e, 0x30, 0x11, 0x0c, + 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04, + 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c, + 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27, 0x73, 0x20, 0x69, + 0x50, 0x61, 0x64, 0x30, 0x82, 0x05, 0xe0, 0x30, 0x82, 0x05, 0xdc, 0x04, + 0x82, 0x04, 0x1c, 0x30, 0x82, 0x04, 0x18, 0x02, 0x01, 0x01, 0x0c, 0x02, + 0x61, 0x6b, 0x02, 0x08, 0x0d, 0x4f, 0xc4, 0x65, 0x00, 0x00, 0x00, 0x03, + 0x30, 0x82, 0x03, 0x2c, 0x30, 0x82, 0x01, 0xa2, 0x31, 0x82, 0x01, 0x56, + 0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x2b, + 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16, 0x32, 0x30, 0x31, + 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30, 0x35, 0x39, 0x2e, + 0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55, 0x0c, 0x10, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, + 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e, 0x16, 0x03, 0x13, + 0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4, 0xf0, 0x47, 0x52, + 0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06, 0x73, 0x23, 0x72, + 0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61, 0xc9, 0x08, 0x43, + 0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49, 0xe3, 0x0c, 0x8e, + 0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11, 0xe1, 0x30, 0x59, + 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x66, + 0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f, 0x75, 0xee, 0x65, + 0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c, 0xdb, 0x46, 0xe5, + 0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20, 0x0a, 0x37, 0xf0, + 0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4, 0x4a, 0x45, 0x02, + 0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf, 0x6b, 0x0b, 0x6b, + 0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, 0x74, 0x31, 0x4e, + 0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, + 0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27, + 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, + 0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf, 0xd2, 0xfb, 0x1e, + 0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47, 0x4b, 0xfe, 0xd0, + 0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02, 0x20, 0x6b, 0xcf, + 0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b, 0xad, 0xf5, 0xb9, + 0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e, 0x80, 0xef, 0xb5, + 0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x30, 0x82, 0x01, 0x82, 0x31, 0x82, + 0x01, 0x35, 0x30, 0x12, 0x0c, 0x0d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x01, 0x01, 0x01, 0x30, 0x14, + 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x29, 0x0c, 0x0d, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, + 0x74, 0x31, 0x18, 0x30, 0x16, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x06, 0x69, 0x43, 0x6c, + 0x6f, 0x75, 0x64, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, + 0x18, 0x16, 0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, + 0x30, 0x30, 0x35, 0x39, 0x2e, 0x39, 0x36, 0x30, 0x38, 0x33, 0x35, 0x5a, + 0x30, 0x55, 0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0x53, + 0x1d, 0x77, 0x7c, 0x1b, 0x8a, 0x53, 0xad, 0x88, 0xdf, 0x56, 0xf9, 0x11, + 0xfd, 0x40, 0x69, 0x7c, 0x0b, 0xbb, 0x2a, 0xf7, 0x48, 0x7e, 0x69, 0x3d, + 0x0c, 0xfb, 0xc8, 0x90, 0x27, 0xb5, 0x18, 0x88, 0x09, 0x3f, 0x06, 0x37, + 0xca, 0x5d, 0x9c, 0x64, 0x34, 0x13, 0x89, 0x09, 0xe9, 0x0e, 0x99, 0xa3, + 0xc8, 0xc1, 0x86, 0xb3, 0x6e, 0x30, 0xf1, 0x20, 0x38, 0x78, 0x56, 0x40, + 0xf4, 0xd7, 0x36, 0x30, 0x5a, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x47, + 0x30, 0x45, 0x02, 0x20, 0x45, 0x47, 0xbf, 0x5b, 0x4d, 0x57, 0x77, 0x90, + 0x7b, 0x74, 0x90, 0x2f, 0x5d, 0x7b, 0x02, 0x3c, 0x21, 0xe8, 0x5c, 0x24, + 0x0c, 0x77, 0xd8, 0x19, 0xff, 0xce, 0x28, 0x45, 0x76, 0x50, 0xb1, 0xee, + 0x02, 0x21, 0x00, 0xe3, 0xea, 0x0f, 0xcb, 0x72, 0xd7, 0x88, 0x15, 0xa4, + 0x71, 0xbe, 0x9e, 0xa6, 0xf2, 0x9c, 0xa8, 0x9b, 0x93, 0xec, 0x31, 0x7a, + 0xe3, 0x92, 0x8a, 0xf2, 0x2f, 0xfd, 0x98, 0xc9, 0xe1, 0xc4, 0x7c, 0x04, + 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xce, 0x5f, 0x67, 0x9d, 0x78, 0x9f, + 0xc6, 0x3b, 0xb3, 0x51, 0xde, 0x6d, 0x9e, 0xff, 0xf5, 0xab, 0xda, 0xf4, + 0x7e, 0xb2, 0xe9, 0x1a, 0xf2, 0xd9, 0x0d, 0x48, 0x30, 0x07, 0xbc, 0x06, + 0xf5, 0x42, 0x02, 0x20, 0x64, 0x1d, 0x7d, 0x43, 0xc1, 0x3b, 0x50, 0xd6, + 0x7b, 0x3b, 0xce, 0x6f, 0xec, 0x23, 0x21, 0x8a, 0x9b, 0x06, 0x3f, 0x64, + 0xfe, 0xd6, 0x29, 0xaf, 0x5b, 0x0c, 0x69, 0x8f, 0x48, 0x88, 0x08, 0x1e, + 0x30, 0x00, 0x30, 0x00, 0x31, 0x81, 0xd0, 0x30, 0x66, 0x0c, 0x1a, 0x30, + 0x56, 0x4f, 0x73, 0x47, 0x76, 0x56, 0x72, 0x51, 0x46, 0x4e, 0x46, 0x6b, + 0x52, 0x35, 0x37, 0x71, 0x59, 0x73, 0x4c, 0x47, 0x6f, 0x33, 0x49, 0x50, + 0x51, 0x04, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xf9, 0xc9, 0x69, 0xda, + 0x69, 0xe7, 0x32, 0xeb, 0x14, 0xc1, 0xbd, 0x56, 0xb7, 0x3e, 0xab, 0x08, + 0x6d, 0xe2, 0x16, 0xd9, 0x0a, 0xa8, 0x67, 0x7a, 0x56, 0xdc, 0x64, 0xf2, + 0x2f, 0x2e, 0xe8, 0xb9, 0x02, 0x21, 0x00, 0xac, 0x5c, 0x29, 0x80, 0x60, + 0x57, 0xd7, 0x51, 0x23, 0x1f, 0x00, 0x09, 0x70, 0xf3, 0xd5, 0x1a, 0x49, + 0xad, 0xaf, 0x35, 0x77, 0x07, 0xf4, 0x85, 0x1f, 0x63, 0xe0, 0xea, 0x67, + 0x36, 0xb5, 0x3b, 0x30, 0x66, 0x0c, 0x1a, 0x6e, 0x6b, 0x62, 0x77, 0x33, + 0x2f, 0x57, 0x72, 0x39, 0x4f, 0x33, 0x6a, 0x45, 0x68, 0x4f, 0x48, 0x46, + 0x67, 0x32, 0x34, 0x67, 0x62, 0x4d, 0x61, 0x6a, 0x76, 0x04, 0x48, 0x30, + 0x46, 0x02, 0x21, 0x00, 0x9f, 0x4f, 0x60, 0x2f, 0x54, 0x5e, 0x9f, 0x6a, + 0x7d, 0x37, 0xd9, 0x9f, 0x62, 0x69, 0xd7, 0x8c, 0xfc, 0xf5, 0x78, 0x54, + 0x7d, 0xb6, 0x91, 0x4b, 0x48, 0x88, 0x3d, 0x59, 0x05, 0x70, 0x09, 0xbf, + 0x02, 0x21, 0x00, 0xe2, 0xaf, 0xc9, 0x27, 0x12, 0xfa, 0x64, 0x51, 0x19, + 0x13, 0x1d, 0x57, 0x56, 0x6b, 0x93, 0xa3, 0xc6, 0x31, 0xf8, 0x70, 0x97, + 0x9e, 0x79, 0xf5, 0xc0, 0x2d, 0xf3, 0x3c, 0x8b, 0x86, 0x92, 0x28, 0x04, + 0x82, 0x01, 0xb8, 0x30, 0x82, 0x01, 0xb4, 0x30, 0x82, 0x01, 0xa2, 0x31, + 0x82, 0x01, 0x56, 0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, + 0x69, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, + 0x00, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16, + 0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30, + 0x35, 0x39, 0x2e, 0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55, + 0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e, + 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e, + 0x16, 0x03, 0x13, 0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4, + 0xf0, 0x47, 0x52, 0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06, + 0x73, 0x23, 0x72, 0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61, + 0xc9, 0x08, 0x43, 0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49, + 0xe3, 0x0c, 0x8e, 0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11, + 0xe1, 0x30, 0x59, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44, + 0x02, 0x20, 0x66, 0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f, + 0x75, 0xee, 0x65, 0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c, + 0xdb, 0x46, 0xe5, 0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20, + 0x0a, 0x37, 0xf0, 0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4, + 0x4a, 0x45, 0x02, 0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf, + 0x6b, 0x0b, 0x6b, 0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, + 0x74, 0x31, 0x4e, 0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, + 0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, + 0x63, 0x68, 0x27, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30, + 0x44, 0x02, 0x20, 0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf, + 0xd2, 0xfb, 0x1e, 0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47, + 0x4b, 0xfe, 0xd0, 0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02, + 0x20, 0x6b, 0xcf, 0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b, + 0xad, 0xf5, 0xb9, 0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e, + 0x80, 0xef, 0xb5, 0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x04, 0x0c, 0x6b, + 0x65, 0x79, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41, + 0x94, 0x6d, 0x46, 0x38, 0xde, 0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86, + 0xbe, 0xd5, 0x78, 0x08, 0x2f, 0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f, + 0x1e, 0xca, 0x05, 0x21, 0x51, 0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46, + 0x53, 0x7e, 0x49, 0x97, 0xb8, 0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92, + 0xdd, 0x30, 0xe2, 0x4d, 0xd4, 0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c, + 0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41, 0x94, 0x6d, 0x46, 0x38, 0xde, + 0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86, 0xbe, 0xd5, 0x78, 0x08, 0x2f, + 0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f, 0x1e, 0xca, 0x05, 0x21, 0x51, + 0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46, 0x53, 0x7e, 0x49, 0x97, 0xb8, + 0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92, 0xdd, 0x30, 0xe2, 0x4d, 0xd4, + 0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c, 0x04, 0x27, 0x30, 0x25, 0x04, + 0x10, 0x48, 0xd4, 0x7b, 0x6a, 0x50, 0xfb, 0x84, 0xf8, 0xb5, 0x8d, 0x13, + 0x62, 0xcc, 0x42, 0xa5, 0x42, 0x02, 0x03, 0x00, 0xc3, 0x50, 0x02, 0x02, + 0x01, 0x00, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07, + 0x31, 0x00 }; +#endif + +#define kCompatibilityTestCount 0 +#if 0 +static void test_v6(void) { + SOSDataSourceFactoryRef ak_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(ak_factory, CFSTR("ak"), test_source); + CFErrorRef error = NULL; + + const uint8_t *der_p = v6_der; + + SOSAccount* convertedAccount = SOSAccountCreateFromDER(kCFAllocatorDefault, ak_factory, &error, &der_p, v6_der + sizeof(v6_der)); + + ok(convertedAccount, "inflate v6 account (%@)", error); + CFReleaseSafe(error); + + is(kSOSCCInCircle, [convertedAccount.trust getCircleStatus:&error], "in the circle"); + + CFReleaseSafe(convertedAccount); + ak_factory->release(ak_factory); + SOSDataSourceRelease(test_source, NULL); +} +#endif + +static int kTestTestCount = 11 + kSecdTestSetupTestCount; +static void tests(void) +{ + + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); + + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"), CFSTR("TestType")); + ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + ok(NULL != account, "Created"); + + ok(SOSAccountResetToOffering_wTxn(account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + ok(testAccountPersistence(account), "Test Account->DER->Account Equivalence"); + + SOSTestCleanup(); + + test_factory->release(test_factory); + SOSDataSourceRelease(test_source, NULL); +} + +int secd_51_account_inflate(int argc, char *const *argv) +{ + plan_tests(kTestTestCount + kCompatibilityTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + secd_test_clear_testviews(); + tests(); + + /* we can't re-inflate the v6 DER since we don't have a viable private key for it. */ + // test_v6(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-52-account-changed.m b/keychain/securityd/Regressions/secd-52-account-changed.m new file mode 100644 index 00000000..37b1cf8b --- /dev/null +++ b/keychain/securityd/Regressions/secd-52-account-changed.m @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges( CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "update"); + + + CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); + ok ([bob_account.trust updateGestalt:bob_account newGestalt:new_gestalt], "did we send a null circle?"); + CFReleaseNull(new_gestalt); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "nothing published"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + /* ==================== Three Accounts setup =============================================*/ + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); + + + ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "update"); + + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "update"); + + accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); + accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); + CFDictionaryRef alice_devstate = SOSTestSaveStaticAccountState(alice_account); + CFDictionaryRef bob_devstate = SOSTestSaveStaticAccountState(bob_account); + CFDictionaryRef carol_devstate = SOSTestSaveStaticAccountState(carol_account); + + /* ==================== Three Accounts in circle =============================================*/ + InjectChangeToMulti(changes, CFSTR("^AccountChanged"), CFSTR("none"), alice_account, bob_account, carol_account, NULL); + SOSAccountInflateTestTransportsForCircle(alice_account, CFSTR("TestSource"), CFSTR("Alice"), &error); + SOSAccountInflateTestTransportsForCircle(bob_account, CFSTR("TestSource"), CFSTR("Bob"), &error); + SOSAccountInflateTestTransportsForCircle(carol_account, CFSTR("TestSource"), CFSTR("Carol"), &error); + + SOSTestRestoreAccountState(alice_account, alice_devstate); + SOSTestRestoreAccountState(bob_account, bob_devstate); + SOSTestRestoreAccountState(carol_account, carol_devstate); + + is([alice_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); + is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); + is([carol_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); + + CFDataRef cfpassword2 = CFDataCreate(NULL, (uint8_t *) "ooFooFooF", 10); + CFStringRef cfaccount2 = CFSTR("test2@test.org"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + is([alice_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); + is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + is([bob_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); + is([carol_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); + // Now everyone is playing the same account. + + /* ==================== Three Accounts setup =============================================*/ + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + is(countActivePeers(alice_account), 2, "2 peers - alice and icloud"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + is([alice_account getCircleStatus:&error], kSOSCCInCircle, "Alice is in circle"); + is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in circle"); + is([carol_account getCircleStatus:&error], kSOSCCNotInCircle, "Carol is not in circle"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + is([carol_account getCircleStatus:&error], kSOSCCRequestPending, "Carol has a pending request"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + is(countActivePeers(alice_account), 4, "4 peers - alice, bob, carol, and icloud"); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); + + accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); + accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); + + CFReleaseSafe(cfpassword2); + CFReleaseNull(changes); + alice_account = nil; + bob_account = nil; + carol_account = nil; + + SOSTestCleanup(); + +} + + +int secd_52_account_changed(int argc, char *const *argv) +{ + plan_tests(113); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-52-offering-gencount-reset.m b/keychain/securityd/Regressions/secd-52-offering-gencount-reset.m new file mode 100644 index 00000000..bb2f6a74 --- /dev/null +++ b/keychain/securityd/Regressions/secd-52-offering-gencount-reset.m @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + + SOSAccountTrustClassic *carolTrust = carol_account.trust; + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(error); + ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); + CFReleaseNull(cfwrong_password); + is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + //bob now goes def while Alice does some stuff. + + ok([alice_account.trust leaveCircle:alice_account err:&error], "ALICE LEAVES THE CIRCLE (%@)", error); + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Alice resets to offering again (%@)", error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + + ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + SOSAccountSetUserPublicTrustedForTesting(carol_account); + ok(SOSAccountResetToOffering_wTxn(carol_account, &error), "Carol is going to push a reset to offering (%@)", error); + + int64_t valuePtr = 0; + CFNumberRef gencount = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &valuePtr); + + SOSCircleSetGeneration(carolTrust.trustedCircle, gencount); + + SecKeyRef user_privkey = SOSUserKeygen(cfpassword, (__bridge CFDataRef)(carol_account.accountKeyDerivationParamters), &error); + CFNumberRef genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); + CFIndex testPtr; + CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); + ok(testPtr== 0); + + SOSCircleSignOldStyleResetToOfferingCircle(carolTrust.trustedCircle, carolTrust.fullPeerInfo, user_privkey, &error); + + SOSTransportCircleTestRemovePendingChange((SOSCircleStorageTransportTest*)carol_account.circle_transport, SOSCircleGetName(carolTrust.trustedCircle), NULL); + CFDataRef circle_data = SOSCircleCopyEncodedData(carolTrust.trustedCircle, kCFAllocatorDefault, &error); + if (circle_data) { + [carol_account.circle_transport postCircle:SOSCircleGetName(carolTrust.trustedCircle) circleData:circle_data err:&error]; + } + CFReleaseNull(circle_data); + + genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); + CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); + ok(testPtr== 0); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + SOSAccountSetUserPublicTrustedForTesting(alice_account); + SOSAccountSetUserPublicTrustedForTesting(bob_account); + + is(ProcessChangesUntilNoChange(changes, carol_account, alice_account, bob_account, NULL), 2, "updates"); + + is([alice_account getCircleStatus:&error],kSOSCCNotInCircle,"alice is not in the account (%@)", error); + is([bob_account getCircleStatus:&error], kSOSCCNotInCircle,"bob is not in the account (%@)", error); + is([carol_account getCircleStatus:&error], kSOSCCInCircle,"carol is in the account (%@)", error); + + CFReleaseNull(gencount); + CFReleaseNull(cfpassword); + CFReleaseNull(user_privkey); + alice_account = nil; + bob_account = nil; + carol_account = nil; + + SOSTestCleanup(); +} + +int secd_52_offering_gencount_reset(int argc, char *const *argv) +{ + plan_tests(63); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-55-account-circle.m b/keychain/securityd/Regressions/secd-55-account-circle.m new file mode 100644 index 00000000..d8035f97 --- /dev/null +++ b/keychain/securityd/Regressions/secd-55-account-circle.m @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 257; + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(error); + ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); + CFReleaseNull(cfwrong_password); + is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + ok(SOSAccountHasCompletedInitialSync(alice_account), "Alice thinks she's completed initial sync"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + ok(!SOSAccountHasCompletedInitialSync(bob_account), "Bob thinks he hasn't completed initial sync"); + + CFDictionaryRef alice_new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice, but different")); + + ok([alice_account.trust updateGestalt:alice_account newGestalt:alice_new_gestalt], "Update gestalt %@ (%@)", alice_account, error); + SOSAccountUpdateTestTransports(alice_account, alice_new_gestalt); + CFReleaseNull(alice_new_gestalt); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + accounts_agree("Alice's name changed", bob_account, alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + accounts_agree("Alice bails", bob_account, alice_account); + + peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 1, "See one peer %@ (%@)", peers, error); + CFReleaseNull(peers); + + ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + accounts_agree("Alice accepts' Bob", bob_account, alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + accounts_agree("Bob accepts Alice", bob_account, alice_account); + + // As of PR-13917727/PR-13906870 this no longer works (by "design"), in favor of making another more common + // failure (apply/OSX-psudo-reject/re-apply) work. Write races might be "fixed better" with affirmitave rejection. +#if 0 + + // + // Write race emulation. + // + // + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + FeedChangesTo(changes, bob_account); // Bob sees Alice leaving and rejoining + FeedChangesTo(changes, alice_account); // Alice sees bob concurring + + accounts_agree("Alice leaves & returns", bob_account, alice_account); + + ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + FeedChangesTo(changes, bob_account); // Bob sees Alice Applying + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + CFMutableDictionaryRef bobAcceptanceChanges = ExtractPendingChanges(changes); + + // Alice re-applies without seeing that she was accepted. + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves again (%@)", error); + CFReleaseNull(error); + ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + CFReleaseSafe(ExtractPendingChanges(changes)); // Alice loses the race to write her changes - bob never sees em. + + FeedChangesTo(&bobAcceptanceChanges, alice_account); // Alice sees bob inviting her in the circle. + + FeedChangesTo(changes, bob_account); // Bob sees Alice Concurring + + // As of PR-13917727/PR-13906870 + accounts_agree("Alice leave, applies back, loses a race and eventually gets in", bob_account, alice_account); +#endif + + // Both in circle. + + // Emulation of Innsbruck11A368 +Roots: Device A was removed when Device B joined. + + // We want Alice to leave circle while an Applicant on a full concordance signed circle with old-Alice as an Alum and Bob a peer. + // ZZZ + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves once more (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + accounts_agree("Alice and Bob see Alice out of circle", bob_account, alice_account); + + ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves while applying (%@)", error); + FeedChangesTo(changes, bob_account); // Bob sees Alice become an Alum. + + CFReleaseNull(error); + + is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice isn't applying any more"); + accounts_agree("Alice leaves & some fancy concordance stuff happens", bob_account, alice_account); + + ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + //FeedChangesTo(changes, bob_account); // Bob sees Alice reapply. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + accounts_agree("Alice comes back", bob_account, alice_account); + + // Emulation of + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + ok(SOSAccountJoinCircles_wTxn(carol_account, &error), "Carol Applies (%@)", error); + CFReleaseNull(error); + + CFMutableDictionaryRef dropped_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + FillChanges(dropped_changes, carol_account); + CFReleaseNull(dropped_changes); + + ok(SOSAccountResetToOffering_wTxn(carol_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 2, "updates"); + accounts_agree("13889901", carol_account, bob_account); + is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSMembershipRevoked, "Bob affirms he hasn't left."); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob ReApplies (%@)", error); + is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 2, "updates"); + { + CFArrayRef applicants = SOSAccountCopyApplicants(carol_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(carol_account, applicants, &error), "Carol accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + is(ProcessChangesUntilNoChange(changes, bob_account, carol_account, NULL), 3, "updates"); + accounts_agree("rdar://problem/13889901-II", bob_account, carol_account); + + // Alice has been out of the loop, bring her back up to speed before changing things (to avoid gen count race) + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "Reset propogation"); + + // Test multiple removal, including our own departure via that API + ok(SOSAccountResetToOffering_wTxn(alice_account, NULL), "Reset to offering"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "Reset propogation"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, NULL), "bob joins again"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "Bob request"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "carol request"); + + ok(SOSAccountJoinCircles_wTxn(carol_account, NULL), "carol joins again"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "carol request"); + + CFArrayRef peers_to_remove_array = CFArrayCreateForCFTypes(kCFAllocatorDefault, + bob_account.peerInfo, + carol_account.peerInfo, + NULL); + + ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, NULL)); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "Remove peers"); + + ok([alice_account isInCircle:&error], "Alice still here"); + ok(![bob_account isInCircle:&error], "Bob not in circle"); + // Carol's not in circle, but reapplied, as she's persistent until positive rejection. + ok(![carol_account isInCircle:NULL], "carol not in circle"); + + CFReleaseNull(peers_to_remove_array); + + CFReleaseNull(alice_new_gestalt); + alice_account = nil; + bob_account = nil; + carol_account = nil; + + SOSTestCleanup(); +} + +int secd_55_account_circle(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-55-account-incompatibility.m b/keychain/securityd/Regressions/secd-55-account-incompatibility.m new file mode 100644 index 00000000..da6aabca --- /dev/null +++ b/keychain/securityd/Regressions/secd-55-account-incompatibility.m @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSKVSKeys.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 10; + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef data_name = CFSTR("TestSource"); + CFStringRef circle_key_name = SOSCircleKeyCreateWithName(data_name, NULL); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_name); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), data_name); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + FillAllChanges(changes); + FeedChangesToMulti(changes, alice_account, carol_account, NULL); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); + CFReleaseNull(cfwrong_password); + is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); + CFReleaseNull(error); + + CFDataRef incompatibleDER = SOSCircleCreateIncompatibleCircleDER(&error); + + InjectChangeToMulti(changes, circle_key_name, incompatibleDER, alice_account, NULL); + CFReleaseNull(circle_key_name); + CFReleaseNull(incompatibleDER); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + CFReleaseNull(changes); + alice_account = nil; + bob_account = nil; + carol_account = nil; + SOSTestCleanup(); +} + +int secd_55_account_incompatibility(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-56-account-apply.m b/keychain/securityd/Regressions/secd-56-account-apply.m new file mode 100644 index 00000000..50748a08 --- /dev/null +++ b/keychain/securityd/Regressions/secd-56-account-apply.m @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +#define kAccountPasswordString ((uint8_t*) "FooFooFoo") +#define kAccountPasswordStringLen 10 + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + // Lost Application Scenario + is(ProcessChangesOnce(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies too (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + accounts_agree("alice and carole agree", alice_account, carole_account); + accounts_agree("alice and bob agree", alice_account, bob_account); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + accounts_agree("alice and carole agree", alice_account, carole_account); + + CFReleaseNull(error); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + ok(applicants && CFArrayGetCount(applicants) == 2, "See two applicants %@ (%@)", applicants, error); + ok(SOSAccountRejectApplicants(alice_account, applicants, &error), "Everyone out the pool"); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + accounts_agree("alice and carole agree", alice_account, carole_account); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + ok(applicants && CFArrayGetCount(applicants) == 0, "See no applicants %@ (%@)", applicants, error); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole bails (%@)", error); + CFReleaseNull(error); + + // Everyone but bob sees that carole bails. + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 1, "updates"); + + + // Bob reapplies, but it's to an old circle. + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob asks again"); + CFReleaseNull(error); + + // Bob returns and we mix our split worlds up. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); + CFReleaseNull(error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + is(countPeers(bob_account), 2, "Bob sees 2 valid peers after admission from re-apply"); + + accounts_agree("alice and bob agree", alice_account, bob_account); + accounts_agree_internal("alice and carole agree", alice_account, carole_account, false); + + + // Rejected Application Scenario + ok(SOSAccountJoinCircles_wTxn(david_account, &error), "Dave Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + accounts_agree_internal("alice and david agree", alice_account, david_account, false); + + SOSAccountPurgePrivateCredential(alice_account); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountRejectApplicants(alice_account, applicants, &error), "Alice rejects (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + accounts_agree_internal("alice and carole still agree after david is rejected", alice_account, carole_account, false); + + cfpassword = CFDataCreate(NULL, kAccountPasswordString, kAccountPasswordStringLen); + + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identiy joins (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); + + accounts_agree_internal("carole&alice pair", carole_account, alice_account, false); + + is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); + + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_56_account_apply(int argc, char *const *argv) +{ + plan_tests(181); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-57-1-account-last-standing.m b/keychain/securityd/Regressions/secd-57-1-account-last-standing.m new file mode 100644 index 00000000..d455b327 --- /dev/null +++ b/keychain/securityd/Regressions/secd-57-1-account-last-standing.m @@ -0,0 +1,161 @@ +// +// secd-57-1-account-last-standing.c +// sec +// +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +static bool acceptApplicants(SOSAccount* account, CFIndex count) { + bool retval = false; + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + ok(applicants && CFArrayGetCount(applicants) == count, "See %ld applicants %@ (%@)", count, applicants, error); + CFReleaseNull(error); + require_quiet(CFArrayGetCount(applicants) == count, xit); + ok((retval=SOSAccountAcceptApplicants(account, applicants, &error)), "Accept applicants into the fold"); + CFReleaseNull(error); +xit: + CFReleaseNull(applicants); + return retval; +} + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(alice_account , &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + ok([alice_account isInCircle:&error], "Alice is back in the circle (%@)", error); + CFReleaseNull(error); + + is(countActivePeers(alice_account), 2, "Alice sees 2 active peers"); + is(countPeers(alice_account), 1, "Alice sees 1 valid peer"); + + // Have Alice leave the circle just as Bob tries to join. + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + + is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 1, "updates"); + ok(SOSAccountTryUserCredentials(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 1, "updates"); + + ok(SOSAccountJoinCircles_wTxn(carole_account , &error), "Carole applies (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 2, "updates"); + ok(acceptApplicants(alice_account, 1), "Alice accepts Carole"); + is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 3, "updates"); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); + + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); + ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob applies (%@)", error); + is(ProcessChangesUntilNoChange(changes, bob_account, NULL), 2, "updates"); + CFReleaseNull(error); + + is(countActivePeers(bob_account), 2, "Bob sees 2 active peers"); + is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); + + + CFReleaseNull(cfpassword); + + alice_account = nil; + SOSTestCleanup(); +} + +int secd_57_1_account_last_standing(int argc, char *const *argv) +{ + plan_tests(45); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-57-account-leave.m b/keychain/securityd/Regressions/secd-57-account-leave.m new file mode 100644 index 00000000..6e1710d1 --- /dev/null +++ b/keychain/securityd/Regressions/secd-57-account-leave.m @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +/* + static void trim_retirements_from_circle(SOSAccount* account) { + SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { + SOSCircleRemoveRetired(circle, NULL); + }); + } + */ + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account , applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + SOSAccountPurgePrivateCredential(alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + accounts_agree("Alice bails", bob_account, alice_account); + + { + CFArrayRef concurring = SOSAccountCopyConcurringPeers(alice_account, &error); + + ok(concurring && CFArrayGetCount(concurring) == 2, "See two concurring %@ (%@)", concurring, error); + CFReleaseNull(error); + CFReleaseNull(concurring); + } + + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(alice_account , &error), "Alice re-applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + is(countActivePeers(bob_account), 3, "Bob sees 2 active peers"); + is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See alice's reapp. %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + + is(countActivePeers(bob_account), 3, "Bob sees 3 active peers"); + is(countPeers(bob_account), 2, "Bob sees 2 valid peers"); + + is(countActivePeers(alice_account), 3, "Alice sees 2 active peers"); + is(countPeers(alice_account), 1, "Alice sees 1 valid peers"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + accounts_agree("Alice rejoined", bob_account, alice_account); + accounts_agree_internal("Alice rejoined, carole noticed", bob_account, carole_account, false); + + ok(SOSAccountJoinCircles_wTxn(carole_account , &error), "Carole applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + accounts_agree_internal("Carole applied", bob_account, alice_account, false); + accounts_agree_internal("Carole applied - 2", bob_account, carole_account, false); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See Carole's eapp. %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts carole (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); + // david ends up with a 3 peerinfo member circle. + + accounts_agree_internal("Carole joined", bob_account, alice_account, false); + accounts_agree_internal("Carole joined - 2", bob_account, carole_account, false); + + // Now test lost circle change when two leave simultaneously, needing us to see the retirement tickets + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + ok([carole_account.trust leaveCircle:carole_account err:&error], "carole Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + is(countPeers(bob_account), 1, "Bob sees 1 valid peer"); + is(countActivePeers(bob_account), 4, "Bob sees 4 active peers"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + is(SOSAccountGetLastDepartureReason(carole_account, &error), kSOSWithdrewMembership, "Carole affirms she left on her own."); + + ok(SOSAccountAssertUserCredentialsAndUpdate(david_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + is(countPeers(david_account), 1, "david sees 1 peers"); + is(countActivePeers(david_account), 4, "david sees 4 active peers"); + + ok(SOSAccountJoinCircles_wTxn(david_account , &error), "David applies (%@)", error); + CFReleaseNull(error); + is(countPeers(david_account), 1, "david sees 1 peers"); + is(countActivePeers(david_account), 4, "david sees 4 active peers"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See David's app. %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account , applicants, &error), "Bob accepts carole (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + is(countPeers(bob_account), 2, "Bob sees 2 valid peer"); + is(countActivePeers(bob_account), 3, "Bob sees 3 active peers"); + + + // Now see that bob can call leave without his private key + SOSAccountPurgeIdentity(bob_account); // Hopefully this actually purges, no errors to process + + ok([bob_account.trust leaveCircle:bob_account err:&error], "bob Leaves w/o credentials (%@)", error); + CFReleaseNull(error); + + ok(![bob_account isInCircle:&error], "bob knows he's out (%@)", error); + CFReleaseNull(error); + alice_account = nil; + bob_account = nil; + + SOSTestCleanup(); +} + +int secd_57_account_leave(int argc, char *const *argv) +{ + plan_tests(191); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + secd_test_clear_testviews(); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-58-password-change.m b/keychain/securityd/Regressions/secd-58-password-change.m new file mode 100644 index 00000000..3135d5b7 --- /dev/null +++ b/keychain/securityd/Regressions/secd-58-password-change.m @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" +#include "SecdTestKeychainUtilities.h" + + +static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef password) { + CFErrorRef error = NULL; + bool retval; + ok((retval = SOSAccountAssertUserCredentialsAndUpdate(account, acct_name, password, &error)), "Credential setting (%@)", error); + CFReleaseNull(error); + return retval; +} + +static bool ResetToOffering(SOSAccount* account) { + CFErrorRef error = NULL; + bool retval; + ok((retval = SOSAccountResetToOffering_wTxn(account, &error)), "Reset to offering (%@)", error); + CFReleaseNull(error); + return retval; +} + +static bool JoinCircle(SOSAccount* account) { + CFErrorRef error = NULL; + bool retval; + ok((retval = SOSAccountJoinCircles_wTxn(account, &error)), "Join Circle (%@)", error); + CFReleaseNull(error); + return retval; +} + +static bool AcceptApplicants(SOSAccount* account, CFIndex cnt) { + CFErrorRef error = NULL; + bool retval = false; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + + ok((retval = (applicants && CFArrayGetCount(applicants) == cnt)), "See applicants %@ (%@)", applicants, error); + if(retval) ok((retval = SOSAccountAcceptApplicants(account, applicants, &error)), "Accept Applicants (%@)", error); + CFReleaseNull(applicants); + CFReleaseNull(error); + return retval; +} + +static void tests(void) +{ + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + + /* Set Initial Credentials and Parameters for the Syncing Circles ---------------------------------------*/ + ok(AssertCreds(bob_account, cfaccount, cfpassword), "Setting credentials for Bob"); + // Bob wins writing at this point, feed the changes back to alice. + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + ok(AssertCreds(alice_account, cfaccount, cfpassword), "Setting credentials for Alice"); + ok(AssertCreds(carol_account, cfaccount, cfpassword), "Setting credentials for Carol"); + CFReleaseNull(cfpassword); + + /* Make Alice First Peer -------------------------------------------------------------------------------*/ + ok(ResetToOffering(alice_account), "Reset to offering - Alice as first peer"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + /* Bob Joins -------------------------------------------------------------------------------------------*/ + ok(JoinCircle(bob_account), "Bob Applies"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + /* Alice Accepts -------------------------------------------------------------------------------------------*/ + ok(AcceptApplicants(alice_account, 1), "Alice Accepts Bob's Application"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "4 updates"); + accounts_agree("bob&alice pair", bob_account, alice_account); + + /* Carol Applies -------------------------------------------------------------------------------------------*/ + ok(JoinCircle(carol_account), "Carol Applies"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + is(countPeers(alice_account), 2, "See two peers"); + + + /* Change Password ------------------------------------------------------------------------------------------*/ + CFDataRef cfnewpassword = CFDataCreate(NULL, (uint8_t *) "ooFooFooF", 10); + + ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); + is(countPeers(bob_account), 2, "There are two valid peers - iCloud and Bob"); + is(countActivePeers(bob_account), 3, "There are three active peers - bob, alice, and iCloud"); + is(countActiveValidPeers(bob_account), 2, "There is two active valid peer - Bob and iCloud"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + is(countPeers(alice_account), 2, "There are two peers - bob and alice"); + is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + is(countPeers(alice_account), 2, "There are two peers - bob and alice"); + is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); + + ok(AssertCreds(carol_account , cfaccount, cfnewpassword), "Credential resetting for Carol"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); + + ok(AcceptApplicants(alice_account , 1), "Alice Accepts Carol's Application"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); + + accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); + accounts_agree_internal("bob&carol pair", bob_account, carol_account, false); + accounts_agree_internal("carol&alice pair", alice_account, carol_account, false); + + + /* Change Password 2 ----------------------------------------------------------------------------------------*/ + CFReleaseNull(cfnewpassword); + cfnewpassword = CFDataCreate(NULL, (uint8_t *) "ffoffoffo", 10); + + /* Bob */ + ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); + + is(countPeers(bob_account), 3, "There are three peers - Alice, Carol, Bob"); + is(countActivePeers(bob_account), 4, "There are four active peers - bob, alice, carol and iCloud"); + is(countActiveValidPeers(bob_account), 2, "There is two active valid peer - Bob and iCloud"); + + + /* Alice */ + ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 3, "updates"); + + is(countPeers(alice_account), 3, "There are three peers - Alice, Carol, Bob"); + is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); + is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); + + + /* Carol */ + ok(AssertCreds(carol_account , cfaccount, cfnewpassword), "Credential resetting for Carol"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); + + is(countPeers(carol_account), 3, "There are three peers - Alice, Carol, Bob"); + is(countActivePeers(carol_account), 4, "There are four active peers - bob, alice, carol and iCloud"); + is(countActiveValidPeers(carol_account), 4, "There are three active valid peers - alice, bob, carol, and icloud"); + + accounts_agree_internal("bob&alice pair", bob_account, alice_account, false); + + /* Change Password 3 - cause a parm lost update collision ----------------------------------------------------*/ + CFReleaseNull(cfnewpassword); + cfnewpassword = CFDataCreate(NULL, (uint8_t *) "cococococ", 10); + + ok(AssertCreds(bob_account , cfaccount, cfnewpassword), "Credential resetting for Bob"); + ok(AssertCreds(alice_account , cfaccount, cfnewpassword), "Credential resetting for Alice"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "updates"); + + is(countPeers(alice_account), 3, "There are three peers - Alice, Carol, Bob"); + is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); + is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); + + CFReleaseNull(cfnewpassword); + alice_account = nil; + bob_account = nil; + carol_account = nil; + SOSTestCleanup(); +} + +int secd_58_password_change(int argc, char *const *argv) +{ + plan_tests(211); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-59-account-cleanup.m b/keychain/securityd/Regressions/secd-59-account-cleanup.m new file mode 100644 index 00000000..dcdb0699 --- /dev/null +++ b/keychain/securityd/Regressions/secd-59-account-cleanup.m @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSKVSKeys.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef circle_name = CFSTR("TestSource"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circle_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circle_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), circle_name); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + accounts_agree("Alice bails", bob_account, alice_account); + accounts_agree("Alice bails", bob_account, carole_account); + + [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + + { + CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts Carole (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); + + accounts_agree("Carole joins", bob_account, carole_account); + + [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + is(countPeers(bob_account), 2, "Active peers after forced cleanup"); + is(countActivePeers(bob_account), 3, "Inactive peers after forced cleanup"); + + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_59_account_cleanup(int argc, char *const *argv) +{ + plan_tests(91); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-60-account-cloud-identity.m b/keychain/securityd/Regressions/secd-60-account-cloud-identity.m new file mode 100644 index 00000000..3fbb31d2 --- /dev/null +++ b/keychain/securityd/Regressions/secd-60-account-cloud-identity.m @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +static bool purgeICloudIdentity(SOSAccount* account) { + bool retval = false; + SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef([account.trust getCircle:NULL], NULL); + if(!icfpi) return false; + retval = SOSFullPeerInfoPurgePersistentKey(icfpi, NULL); + CFReleaseNull(icfpi); + return retval; +} + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + /*----- normal join after restore -----*/ + + ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); + + is(countApplicants(alice_account), 0, "See no applicants"); + + is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + accounts_agree_internal("Carole's in", bob_account, alice_account, false); + accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); + + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + /*----- join - join after restore -----*/ + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole normally joins (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + is(countApplicants(alice_account), 1, "See one applicant"); + + ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); + + + is(countApplicants(alice_account), 0, "See no applicants"); + + is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + accounts_agree_internal("Carole's in", bob_account, alice_account, false); + accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); + + /* Break iCloud identity FPI in all peers */ + + ok(purgeICloudIdentity(alice_account), "remove iCloud private key"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + // fix this as if the timed event had triggered in handleUpdateCircles + bool fixedIdentities = [alice_account.trust fixICloudIdentities:alice_account circle:alice_account.trust.trustedCircle]; + ok(fixedIdentities, "failed to fix icloud identity"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); + + /*----- join - join after restore -----*/ + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole normally joins (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + is(countApplicants(alice_account), 1, "See one applicant"); + + ok(SOSAccountJoinCirclesAfterRestore_wTxn(carole_account, &error), "Carole cloud identity joins (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); + + + is(countApplicants(alice_account), 0, "See no applicants"); + + is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + accounts_agree_internal("Carole's in", bob_account, alice_account, false); + accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); + + //join after piggybacking the icloud identity?? + CFMutableArrayRef identityArray = SOSAccountCopyiCloudIdentities(alice_account); + + NSMutableArray *encodedIdenities = [NSMutableArray array]; + CFIndex i, count = CFArrayGetCount(identityArray); + for (i = 0; i < count; i++) { + SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identityArray, i); + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, NULL)); + if (data) + [encodedIdenities addObject:data]; + } + + //store in keychain as the piggy icloud + [encodedIdenities enumerateObjectsUsingBlock:^(NSData *v_data, NSUInteger idx, BOOL *stop) { + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecUseDataProtectionKeychain : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.sos", + (id)kSecAttrLabel : @"Cloud Identity - piggy", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecUseTombstones : (id)kCFBooleanTrue, + (id)kSecValueData : v_data, + } mutableCopy]; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + + if(status == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + NSMutableDictionary* update = [@{ + (id)kSecValueData: v_data, + } mutableCopy]; + query[(id)kSecValueData] = nil; + + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + ok(status == 0, "Grabbed icloud identity from the keychain %@", error); + } + }]; + + + //now grab this grom the keychain + NSMutableDictionary* query2 = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecUseDataProtectionKeychain : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.sos", + (id)kSecAttrLabel : @"Cloud Identity - piggy", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecUseTombstones : (id)kCFBooleanTrue, + (id)kSecReturnData : (id)kCFBooleanTrue, + } mutableCopy]; + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query2, &result); + ok(status == 0, "Grabbed icloud identity from the keychain %@", error); + ok(result != NULL, "result from sec item copy matching query %@", error); + + NSDictionary *keyAttributes = @{ + (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, + (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, + }; + + + SecKeyRef privKey = SecKeyCreateWithData(result, (__bridge CFDictionaryRef)keyAttributes, NULL); + + ok(privKey != NULL, "Private key is NULL"); + SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey); + ok(publicKey != NULL, "Private key is NULL"); + + CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); + ok(public_key_hash != NULL, "hash is not null"); + + CFReleaseNull(publicKey); + + SOSAccount* margaret_account = CreateAccountForLocalChanges(CFSTR("margaret"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(margaret_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + ok(SOSAccountJoinCirclesAfterRestore_wTxn(margaret_account, &error), "Carole cloud identity joins (%@)", error); + + CFReleaseNull(identityArray); + CFReleaseNull(changes); + CFReleaseNull(error); + CFReleaseNull(public_key_hash); + CFReleaseNull(cfpassword); + CFReleaseNull(privKey); + + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_60_account_cloud_identity(int argc, char *const *argv) +{ + plan_tests(159); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m b/keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m new file mode 100644 index 00000000..ac6b75c1 --- /dev/null +++ b/keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +/* + static void trim_retirements_from_circle(SOSAccount* account) { + SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { + SOSCircleRemoveRetired(circle, NULL); + }); + } + */ +static bool accept_applicants(SOSAccount* account, int count) { + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + bool retval = false; + ok(applicants, "Have Applicants"); + if(!applicants) goto errout; + is(CFArrayGetCount(applicants), count, "See applicants %@ (%@)", applicants, error); + if(CFArrayGetCount(applicants) != count) goto errout; + ok(retval = SOSAccountAcceptApplicants(account, applicants, &error), "Account accepts (%@)", error); +errout: + CFReleaseNull(error); + CFReleaseNull(applicants); + return retval; +} + + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges ( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges ( CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges ( CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges ( CFSTR("David"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(david_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); + + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + + ok(accept_applicants(alice_account, 1), "Alice Accepts Application"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); + + // ============================== Alice and Bob are in the Account. ============================================ + + + ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); + + ok(accept_applicants(alice_account, 1), "Alice Accepts Application"); + + // Let everyone concur. + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 3, "updates"); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + + ok(peers && CFArrayGetCount(peers) == 3, "See three peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + // SOSAccountPurgePrivateCredential(alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); + + + ok(SOSAccountJoinCircles_wTxn(david_account, &error), "David Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); + + ok(accept_applicants(carole_account, 1), "Carole Accepts Application"); + + // ============================== We added Carole and David while Bob was in a drawer. Alice has left ============================================ + + // ============================== Bob comes out of the drawer seeing alice left and doesn't recognize the remainder. ============================================ + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); + + CFReleaseNull(error); + is([carole_account getCircleStatus:&error], kSOSCCInCircle, "Carole still in Circle (%@)", error); + CFReleaseNull(error); + is([david_account getCircleStatus:&error], kSOSCCInCircle, "David still in Circle (%@)", error); + CFReleaseNull(error); + is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in Circle (%@)", error); + CFReleaseNull(error); + is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSLeftUntrustedCircle, "Bob affirms he left because he doesn't know anyone."); + CFReleaseNull(error); + is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice is not in Circle (%@)", error); + CFReleaseNull(error); + is(SOSAccountGetLastDepartureReason(alice_account, &error), kSOSWithdrewMembership, "Alice affirms she left by request."); + CFReleaseNull(error); + + CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_61_account_leave_not_in_kansas_anymore(int argc, char *const *argv) +{ + plan_tests(82); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-62-account-backup.m b/keychain/securityd/Regressions/secd-62-account-backup.m new file mode 100644 index 00000000..8205fdd9 --- /dev/null +++ b/keychain/securityd/Regressions/secd-62-account-backup.m @@ -0,0 +1,283 @@ + +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include +#include + +#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#if !TARGET_OS_SIMULATOR +#include "SOSAccountTesting.h" +#endif +#include "SecdTestKeychainUtilities.h" + +#if !TARGET_OS_SIMULATOR + +static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) +{ + __block CFDataRef result = NULL; + CFStringPerformWithUTF8CFData(string, ^(CFDataRef stringAsData) { + result = SOSCopyDeviceBackupPublicKey(stringAsData, error); + }); + return result; +} +#endif + +static void tests(void) +{ +#if !TARGET_OS_SIMULATOR + + __block CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + + CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); + CFDataRef bob_backup_key = CopyBackupKeyForString(CFSTR("Bob Backup Entropy"), &error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); + CFReleaseNull(error); + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); + CFReleaseNull(error); + + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice's key in backup before sync?"); + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); + + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); + + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice in backup after sync?"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "IS bob in the backup after sync"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); + CFReleaseNull(error); + + // + //Bob leaves the circle + // + ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); + CFReleaseNull(error); + + //Alice should kick Bob out of the backup! + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Bob left the circle, Alice is not in the backup"); + + ok(SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is last backup peer"); + CFReleaseNull(error); + ok(!SOSAccountIsLastBackupPeer(bob_account, &error), "Bob is not last backup peer"); + CFReleaseNull(error); + + ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); + + SOSAccountTrustClassic *bobTrust = bob_account.trust; + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); + + //Bob gets back into the circle + ok(SOSAccountJoinCircles_wTxn(bob_account, &error)); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + + //enables view + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is the not the last backup peer - Bob still registers as one"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); + CFReleaseNull(error); + + // + //removing backup key for bob account + // + + ok(SOSAccountRemoveBackupPublickey_wTxn(bob_account, &error), "Removing Bob's backup key (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); + + // + // Setting new backup public key for Bob + // + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); + CFReleaseNull(error); + + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); + + //bob is in his own backup + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); + //alice does not have bob in her backup + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key should be in the backup"); + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Alice is in the backup"); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); + ok(SOSAccountIsBackupRingEmpty(alice_account, kTestView1), "Alice should not be in the backup"); + + + CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +#endif + +} + +int secd_62_account_backup(int argc, char *const *argv) +{ +#if !TARGET_OS_SIMULATOR + plan_tests(95); +#else + plan_tests(1); +#endif + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + secd_test_setup_testviews(); // for running this test solo + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-63-account-resurrection.m b/keychain/securityd/Regressions/secd-63-account-resurrection.m new file mode 100644 index 00000000..5e0ef6d0 --- /dev/null +++ b/keychain/securityd/Regressions/secd-63-account-resurrection.m @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +typedef void (^stir_block)(int expected_iterations); +typedef int (^execute_block)(void); + +static void stirBetween(stir_block stir, ...) { + va_list va; + va_start(va, stir); + + execute_block execute = NULL; + + while ((execute = va_arg(va, execute_block)) != NULL) + stir(execute()); +} + +static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) +{ + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + + SKIP: { + skip("Empty applicant array", 2, applicants); + + is(CFArrayGetCount(applicants), expected, "Applicants: %@ (%@)", applicants, error); + CFReleaseNull(error); + + ok(SOSAccountAcceptApplicants(account , applicants, &error), "Accepting all (%@)", error); + CFReleaseNull(error); + } + + CFReleaseNull(applicants); +} + + +static void tests(void) +{ + __block CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + const CFStringRef data_source_name = CFSTR("TestSource"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); + + SOSAccount* alice_resurrected = NULL; + + __block CFDataRef frozen_alice = NULL; + + + stirBetween(^(int expected){ + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), expected, "stirring"); + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "bob credential setting (%@)", error); + + return 1; + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "alice credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "carole credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + return 2; + }, ^{ + ok(SOSAccountJoinCircles_wTxn(bob_account , &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + return 2; + }, ^{ + VerifyCountAndAcceptAllApplicants(alice_account, 1); + + return 3; + }, ^{ + accounts_agree("bob&alice pair", bob_account, alice_account); + is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSNeverLeftCircle, "Bob affirms he hasn't left."); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + return 1; + }, ^{ + + NSError *ns_error = nil; + frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); + ok(frozen_alice, "Copy encoded %@", ns_error); + ns_error = nil; + + SOSAccountPurgePrivateCredential(alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + return 2; + }, ^{ + + accounts_agree("Alice bails", bob_account, alice_account); + + { + CFArrayRef concurring = SOSAccountCopyConcurringPeers(alice_account, &error); + + ok(concurring && CFArrayGetCount(concurring) == 2, "See two concurring %@ (%@)", concurring, error); + CFReleaseNull(error); + CFReleaseNull(concurring); + } + + return 1; + }, + NULL); + + alice_resurrected = CreateAccountForLocalChangesFromData(frozen_alice, CFSTR("Alice risen"), data_source_name); + // This is necessary from the change that makes accounts not inflate if the private key was lost - alice_resurected now + // Starts as a brand new account, so this whole series of tests needs to amount to "is this brand new"? + // The trigger is alice leaving the circle - that kills the deviceKey. + ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL); + + stirBetween(^(int expected){ + is(ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL), expected, "stirring"); + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_resurrected, cfaccount, cfpassword, &error), "alice_resurrected credential setting (%@)", error); + CFReleaseNull(error); + return 1; + }, ^{ + ok(![alice_resurrected isInCircle:&error], "Ressurrected not in circle: %@", error); + CFReleaseNull(error); + + ok(SOSAccountJoinCircles_wTxn(alice_resurrected, &error), "Risen-alice Applies (%@)", error); + CFReleaseNull(error); + return 2; + }, ^{ + VerifyCountAndAcceptAllApplicants(bob_account, 1); + return 3; + }, + NULL); + + CFReleaseNull(frozen_alice); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_63_account_resurrection(int argc, char *const *argv) +{ + plan_tests(73); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-64-circlereset.m b/keychain/securityd/Regressions/secd-64-circlereset.m new file mode 100644 index 00000000..6c905c29 --- /dev/null +++ b/keychain/securityd/Regressions/secd-64-circlereset.m @@ -0,0 +1,144 @@ +// +// secd-64-circlereset.c +// sec +// +// Created by Richard Murphy on 7/22/15. +// +// + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int64_t getCurrentGenCount(SOSAccount* account) { + SOSAccountTrustClassic* trust = account.trust; + return SOSCircleGetGenerationSint(trust.trustedCircle); +} + +static bool SOSAccountResetWithGenCountValue(SOSAccount* account, int64_t gcount, CFErrorRef* error) { + if (!SOSAccountHasPublicKey(account, error)) + return false; + __block bool result = true; + SOSAccountTrustClassic* trust = account.trust; + + result &= [account.trust resetAllRings:account err:error]; + + trust.fullPeerInfo = nil; + [trust setDepartureCode:kSOSWithdrewMembership]; + + result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { + SOSGenCountRef gencount = SOSGenerationCreateWithValue(gcount); + result = SOSCircleResetToEmpty(circle, error); + SOSCircleSetGeneration(circle, gencount); + CFReleaseNull(gencount); + return result; + }]; + + if (!result) { + secerror("error: %@", error ? *error : NULL); + } + + return result; +} + +static SOSCircleRef SOSCircleCreateWithGenCount(int64_t gcount) { + SOSCircleRef c = SOSCircleCreate(kCFAllocatorDefault, CFSTR("a"), NULL); + SOSGenCountRef gencount = SOSGenerationCreateWithValue(gcount); + SOSCircleSetGeneration(c, gencount); + CFReleaseNull(gencount); + return c; +} + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSCircleRef c1 = SOSCircleCreateWithGenCount(1); + SOSCircleRef c99 = SOSCircleCreateWithGenCount(99); + ok(SOSCircleIsOlderGeneration(c1, c99), "Is Comparison working correctly?", NULL); + CFReleaseNull(c1); + CFReleaseNull(c99); + + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + + // Setup Circle with Bob and Alice in it + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + accounts_agree("bob&alice pair", bob_account, alice_account); + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + uint64_t cnt = getCurrentGenCount(alice_account); + + ok(SOSAccountResetWithGenCountValue(alice_account, cnt-1, &error), "Alice resets the circle to empty with old value"); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + is([bob_account getCircleStatus:&error], 0, "Bob Survives bad circle post"); + is([alice_account getCircleStatus:&error], 1, "Alice does not survive bad circle post"); + + CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_64_circlereset(int argc, char *const *argv) +{ + plan_tests(35); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-65-account-retirement-reset.m b/keychain/securityd/Regressions/secd-65-account-retirement-reset.m new file mode 100644 index 00000000..a406f2ab --- /dev/null +++ b/keychain/securityd/Regressions/secd-65-account-retirement-reset.m @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +typedef void (^stir_block)(int expected_iterations); +typedef int (^execute_block)(void); + +static void stirBetween(stir_block stir, ...) { + va_list va; + va_start(va, stir); + + execute_block execute = NULL; + + while ((execute = va_arg(va, execute_block)) != NULL) + stir(execute()); +} + +__unused static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) +{ + CFErrorRef error = NULL; + CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); + + SKIP: { + skip("Empty applicant array", 2, applicants); + + is(CFArrayGetCount(applicants), expected, "Applicants: %@ (%@)", applicants, error); + CFReleaseNull(error); + + ok(SOSAccountAcceptApplicants(account , applicants, &error), "Accepting all (%@)", error); + CFReleaseNull(error); + } + + CFReleaseNull(applicants); +} + + +static void tests(void) +{ + __block CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + const CFStringRef data_source_name = CFSTR("TestSource"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); + + SOSAccount* alice_resurrected = NULL; + + __block CFDataRef frozen_alice = NULL; + + + stirBetween(^(int expected){ + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), expected, "stirring"); + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "bob credential setting (%@)", error); + + return 1; + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "alice credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "carole credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account , &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + return 2; + }, ^{ + NSError *ns_error = nil; + frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); + ok(frozen_alice, "Copy encoded %@", ns_error); + ns_error = nil; + + SOSAccountPurgePrivateCredential(alice_account); + + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + + return 2; + }, ^{ + ok(SOSAccountResetToOffering_wTxn(bob_account , &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + return 2; + }, + NULL); + + alice_resurrected = CreateAccountForLocalChangesFromData(frozen_alice, CFSTR("Alice risen"), data_source_name); + // This is necessary from the change that makes accounts not inflate if the private key was lost - alice_resurected now + // Starts as a brand new account, so this whole series of tests needs to amount to "is this brand new"? + // The trigger is alice leaving the circle - that kills the deviceKey. + ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL); + + stirBetween(^(int expected){ + is(ProcessChangesUntilNoChange(changes, alice_resurrected, bob_account, carole_account, NULL), expected, "stirring"); + }, ^{ + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_resurrected, cfaccount, cfpassword, &error), "alice_resurrected credential setting (%@)", error); + CFReleaseNull(error); + return 1; + }, ^{ + ok(![alice_resurrected isInCircle:&error], "Ressurrected not in circle: %@", error); + CFReleaseNull(error); + + ok([bob_account isInCircle:&error], "Should be in circle: %@", error); + CFReleaseNull(error); + + return 1; + }, + NULL); + + CFReleaseNull(frozen_alice); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_65_account_retirement_reset(int argc, char *const *argv) +{ + plan_tests(28); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-66-account-recovery.m b/keychain/securityd/Regressions/secd-66-account-recovery.m new file mode 100644 index 00000000..60664cb8 --- /dev/null +++ b/keychain/securityd/Regressions/secd-66-account-recovery.m @@ -0,0 +1,375 @@ +// +// secd-66-account-recovery.c +// Security +// +// Created by Richard Murphy on 10/5/16. +// +// + +#include + +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "SecdTestKeychainUtilities.h" + +#if TARGET_OS_SIMULATOR + +int secd_66_account_recovery(int argc, char *const *argv) { + plan_tests(1); + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + return 0; +} + +#else + +#include "SOSAccountTesting.h" + +static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) +{ + __block CFDataRef result = NULL; + CFStringPerformWithUTF8CFData(string, ^(CFDataRef stringAsData) { + result = SOSCopyDeviceBackupPublicKey(stringAsData, error); + }); + return result; +} + + +static inline bool SOSAccountSetRecoveryKey_wTxn(SOSAccount* acct, CFDataRef recoveryPub, CFErrorRef* error) { + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountSetRecoveryKey(txn.account, recoveryPub, error); + }]; + return result; +} + +static inline bool SOSAccountSOSAccountRemoveRecoveryKey_wTxn(SOSAccount* acct, CFErrorRef* error) { + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountRemoveRecoveryKey(txn.account, error); + }]; + return result; +} + +// 6 test cases +static void registerRecoveryKeyNow(CFMutableDictionaryRef changes, SOSAccount* registrar, SOSAccount* observer, CFDataRef recoveryPub, bool recKeyFirst) { + CFErrorRef error = NULL; + + is(ProcessChangesUntilNoChange(changes, registrar, observer, NULL), 1, "updates"); + + if(recoveryPub) { + ok(SOSAccountSetRecoveryKey_wTxn(registrar, recoveryPub, &error), "Set Recovery Key"); + CFReleaseNull(error); + } else { + ok(SOSAccountSOSAccountRemoveRecoveryKey_wTxn(registrar, &error), "Clear Recovery Key"); + CFReleaseNull(error); + } + ok(error == NULL, "Error shouldn't be %@", error); + CFReleaseNull(error); + ProcessChangesUntilNoChange(changes, registrar, observer, NULL); + + CFDataRef registrar_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, registrar, &error); + CFReleaseNull(error); + CFDataRef observer_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, observer, &error); + CFReleaseNull(error); + + if(recoveryPub) { + ok(registrar_recKey, "Registrar retrieved recKey"); + ok(observer_recKey, "Observer retrieved recKey"); + ok(CFEqualSafe(registrar_recKey, observer_recKey), "recKeys are the same"); + ok(CFEqualSafe(registrar_recKey, recoveryPub), "recKeys are as expected"); + } else { + ok((!registrar_recKey && !observer_recKey), "recKeys are NULL"); + } + CFReleaseNull(observer_recKey); + CFReleaseNull(registrar_recKey); +} + +static void tests(bool recKeyFirst) +{ + __block CFErrorRef error = NULL; + CFStringRef sock_drawer_key = CFSTR("AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW"); + SecRecoveryKey *sRecKey = NULL; + CFDataRef fullKeyBytes = NULL; + CFDataRef pubKeyBytes = NULL; + + sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString*)sock_drawer_key, NULL); + ok(sRecKey, "Create SecRecoveryKey from String"); + if(sRecKey) { + fullKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupFullKey(sRecKey)); + pubKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupPublicKey(sRecKey)); + ok(fullKeyBytes && pubKeyBytes, "Got KeyPair from SecRecoveryKey"); + } + if(!(fullKeyBytes && pubKeyBytes)) { + diag("Cannot Proceed - couldn't make usable recoveryKey from sock-drawer-key"); + CFReleaseNull(fullKeyBytes); + CFReleaseNull(pubKeyBytes); + return; + } + + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef cfdsid = CFSTR("DSIDFooFoo"); + + secd_test_setup_testviews(); // for running this test solo + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccountAssertDSID(alice_account, cfdsid); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccountAssertDSID(bob_account, cfdsid); + + CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); + CFDataRef bob_backup_key = CopyBackupKeyForString(CFSTR("Bob Backup Entropy"), &error); + + // Start Circle + ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + if(recKeyFirst) registerRecoveryKeyNow(changes, alice_account, bob_account, pubKeyBytes, recKeyFirst); + + + is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); + CFReleaseNull(error); + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); + CFReleaseNull(error); + + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup before sync?"); + + if(!recKeyFirst) { + SOSBackupSliceKeyBagRef bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); + CFReleaseNull(error); + ok(!SOSBSKBHasRecoveryKey(bskb), "BSKB should not have recovery key"); + CFReleaseNull(bskb); + } + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); + + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); + + + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); + CFReleaseNull(error); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup after sync?"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "IS bob in the backup after sync"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); + CFReleaseNull(error); + + // + //Bob leaves the circle + // + ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); + CFReleaseNull(error); + + //Alice should kick Bob out of the backup! + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Bob left the circle, Alice is in the backup"); + + ok(SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is last backup peer"); + CFReleaseNull(error); + ok(!SOSAccountIsLastBackupPeer(bob_account, &error), "Bob is not last backup peer"); + CFReleaseNull(error); + + //ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); + SOSAccountTrustClassic* bobTrust = bob_account.trust; + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); + + //Bob gets back into the circle + ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Re-Joins"); + + //enables view + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + CFReleaseNull(error); + + ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is the not the last backup peer - Bob still registers as one"); + CFReleaseNull(error); + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + ok(!SOSAccountIsLastBackupPeer(alice_account, &error), "Alice is not last backup peer"); + CFReleaseNull(error); + + // + //removing backup key for bob account + // + + ok(SOSAccountRemoveBackupPublickey_wTxn(bob_account, &error), "Removing Bob's backup key (%@)", error); + int nchanges = (recKeyFirst) ? 2: 2; + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), nchanges, "updates"); + + ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); + + // + // Setting new backup public key for Bob + // + + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); + CFReleaseNull(error); + + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); + ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); + + //bob is in his own backup + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); + //alice does not have bob in her backup + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); + + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key should be in the backup"); + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Alice is in the backup"); + + if(!recKeyFirst) registerRecoveryKeyNow(changes, alice_account, bob_account, pubKeyBytes, recKeyFirst); + + ok(SOSAccountRecoveryKeyIsInBackupAndCurrentInView(alice_account, kTestView1), "Recovery Key is also in the backup"); + ok(SOSAccountRecoveryKeyIsInBackupAndCurrentInView(bob_account, kTestView1), "Recovery Key is also in the backup"); + + SOSBackupSliceKeyBagRef bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); + CFReleaseNull(error); + + ok(SOSBSKBHasRecoveryKey(bskb), "BSKB should have recovery key"); + + CFDataRef wrappingKey = CFStringCreateExternalRepresentation(kCFAllocatorDefault, sock_drawer_key, kCFStringEncodingUTF8, 0); + ok(wrappingKey, "Made wrapping key from with sock drawer key"); + bskb_keybag_handle_t bskbHandle = SOSBSKBLoadAndUnlockWithWrappingSecret(bskb, wrappingKey, &error); + ok(bskbHandle, "Made bskbHandle with recover key"); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + + // Testing reset (Null) recoveryKey ========= + + CFReleaseNull(bskb); + CFReleaseNull(wrappingKey); + + registerRecoveryKeyNow(changes, alice_account, bob_account, NULL, recKeyFirst); + + ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(alice_account, kTestView1), "Recovery Key is not in the backup"); + ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(bob_account, kTestView1), "Recovery Key is not in the backup"); + + bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); + CFReleaseNull(error); + + ok(!SOSBSKBHasRecoveryKey(bskb), "BSKB should not have recovery key"); + + //========= + + + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); + ok(SOSAccountIsBackupRingEmpty(alice_account, kTestView1), "Alice should not be in the backup"); + + CFReleaseNull(fullKeyBytes); + CFReleaseNull(pubKeyBytes); + CFReleaseNull(bskb); + + CFReleaseNull(cfpassword); + CFReleaseNull(wrappingKey); + bob_account = nil; + alice_account = nil; + + SOSTestCleanup(); +} + +int secd_66_account_recovery(int argc, char *const *argv) { + plan_tests(278); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(true); + tests(false); + + return 0; +} + +#endif diff --git a/keychain/securityd/Regressions/secd-668-ghosts.m b/keychain/securityd/Regressions/secd-668-ghosts.m new file mode 100644 index 00000000..957c30ae --- /dev/null +++ b/keychain/securityd/Regressions/secd-668-ghosts.m @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// secd-668-ghosts.c +// sec +// + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#include "secd_regressions.h" +#include "SOSAccountTesting.h" +#include "SecdTestKeychainUtilities.h" + +/* + Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab") + have alice leave the circle + release bob, make a new bob - iOS and same serial number + try to join the circle - it should resetToOffering with ghost fix + + For phase 1 we expect the ghostfix to work with iOS devices, but not with MacOSX devices. + */ + +#if 0 +static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef ghostSerialID = CFSTR("abababababab"); + CFStringRef ghostIdsID = CFSTR("targetIDS"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass, ghostSerialID, ghostIdsID); + + // Start Circle + ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); + + // Alice Leaves + ok( [alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + accounts_agree("Alice bails", bob_account, alice_account); + is(countPeers(bob_account), 1, "There should only be 1 valid peer"); + // We're dropping all peers that are in the circle - leaving a circle with only one peer - and that's a ghost + + // Make new bob - same as the old bob except peerID + + SOSAccount* bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); + is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 1, "updates"); + + ok(SOSTestJoinWith(cfpassword, cfaccount, changes, bobFinal), "Application Made"); + CFReleaseNull(cfpassword); + + // Did ghostbuster work? + is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 2, "updates"); + if(expectGhostBusted) { // ghostbusting is currently disabled for MacOSX Peers + ok([bobFinal isInCircle:NULL], "Bob is in"); + } else { + ok(![bobFinal isInCircle:NULL], "Bob is not in"); + } + + is(countPeers(bobFinal), 1, "There should only be 1 valid peer"); + + CFReleaseNull(changes); + + bob_account = nil; + alice_account = nil; + bobFinal = nil; + SOSTestCleanup(); +} + +static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bool delayedPrivKey, bool pairJoin) { + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef ghostSerialID = CFSTR("abababababab"); + CFStringRef ghostIdsID = CFSTR("targetIDS"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + + // Start Circle + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + SOSTestMakeGhostInCircle(CFSTR("Bob1"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 2); + SOSTestMakeGhostInCircle(CFSTR("Bob2"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 3); + SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 4); + SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 5); + + SOSAccount* bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); + + if(pairJoin) { + SOSTestJoinThroughPiggyBack(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 6, true); + is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle"); + } else if(delayedPrivKey) { + SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, DROP_USERKEY, 6, true); + is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle"); + } else { + SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 2, true); + } + + if(pairJoin || delayedPrivKey) { // this allows the ghostbusting to be done in a delayed fashion for the instances where that is proper + SOSAccountTryUserCredentials(bobFinal_account, cfaccount, cfpassword, &error); + ok(SOSTestChangeAccountDeviceName(bobFinal_account, CFSTR("ThereCanBeOnlyOneBob")), "force an unrelated circle change"); + is(ProcessChangesUntilNoChange(changes, alice_account, bobFinal_account, NULL), 3, "updates"); + } + + CFReleaseNull(cfpassword); + + + ok([bobFinal_account isInCircle:NULL], "bobFinal_account is in"); + + is(countPeers(bobFinal_account), 2, "Expect ghostBobs to be gone"); + is(countPeers(alice_account), 2, "Expect ghostBobs to be gone"); + accounts_agree_internal("Alice and ThereCanBeOnlyOneBob are the only circle peers and they agree", alice_account, bobFinal_account, false); + + CFReleaseNull(changes); + + alice_account = nil; + bobFinal_account = nil; + + SOSTestCleanup(); +} + +static void iosICloudIdentity() { + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef ghostIdsID = CFSTR("targetIDS"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + + // Start Circle + ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); + + SOSCircleRef circle = [alice_account.trust getCircle:NULL]; + __block CFStringRef serial = NULL; + SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { + if(SOSPeerInfoIsCloudIdentity(peer)) { + serial = SOSPeerInfoCopySerialNumber(peer); + } + }); + + SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS, serial, ghostIdsID); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); + CFReleaseNull(cfpassword); + + circle = [alice_account.trust getCircle:&error]; + __block bool hasiCloudIdentity = false; + SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { + if(SOSPeerInfoIsCloudIdentity(peer)) { + hasiCloudIdentity = true; + } + }); + + ok(hasiCloudIdentity, "GhostBusting didn't mess with the iCloud Identity"); + + CFReleaseNull(changes); + alice_account = nil; + SOSTestCleanup(); +} +#endif // 0 + +int secd_68_ghosts(int argc, char *const *argv) +{ + plan_tests(1); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + +#if 0 + // changing ghostbusting. handleUpdateCircle version is going away. + hauntedCircle(SOSPeerInfo_iOS, true); + hauntedCircle(SOSPeerInfo_macOS, false); + multiBob(SOSPeerInfo_iOS, true, false, false); + multiBob(SOSPeerInfo_iOS, false, true, false); + multiBob(SOSPeerInfo_iOS, false, false, true); // piggyback join case + + iosICloudIdentity(); +#endif + return 0; +} diff --git a/keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m b/keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m new file mode 100644 index 00000000..93809dfd --- /dev/null +++ b/keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m @@ -0,0 +1,129 @@ +// +// secd-67-prefixedKeyIDs.c +// Security +// +// Created by Richard Murphy on 11/1/16. +// +// + +#include +// +// secd-66-account-recovery.c +// Security +// +// Created by Richard Murphy on 10/5/16. +// +// + +#include + +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + + +#include +#include +#include "SOSKeyedPubKeyIdentifier.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" + +#include +#include + + + +#include "SOSAccountTesting.h" +static void tests() { + CFErrorRef error = NULL; + int keySizeInBits = 256; + CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberIntType, &keySizeInBits); + + CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecAttrKeyType, kSecAttrKeyTypeEC, + kSecAttrKeySizeInBits, kzib, + NULL); + CFReleaseNull(kzib); + + + SecKeyRef key = SecKeyCreateRandomKey(keyattributes, &error); + CFReleaseNull(keyattributes); + SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(key); + CFDataRef pubKeyData = NULL; + SecKeyCopyPublicBytes(pubKey, &pubKeyData); + CFStringRef properPref = CFSTR("RK"); + CFStringRef shortPref = CFSTR("R"); + CFStringRef longPref = CFSTR("RKR"); + + ok(key, "Made private key"); + ok(pubKey, "Made public key"); + ok(pubKeyData, "Made public key data"); + + CFStringRef pkidseckey = SOSKeyedPubKeyIdentifierCreateWithSecKey(properPref, pubKey); + ok(pkidseckey, "made string"); + CFStringRef pkidseckeyshort = SOSKeyedPubKeyIdentifierCreateWithSecKey(shortPref, pubKey); + ok(!pkidseckeyshort, "didn't make string"); + CFStringRef pkidseckeylong = SOSKeyedPubKeyIdentifierCreateWithSecKey(longPref, pubKey); + ok(!pkidseckeylong, "didn't make string"); + + ok(SOSKeyedPubKeyIdentifierIsPrefixed(pkidseckey), "properly prefixed string was made"); + CFStringRef retPref = SOSKeyedPubKeyIdentifierCopyPrefix(pkidseckey); + ok(retPref, "got prefix"); + ok(CFEqualSafe(retPref, properPref), "prefix matches"); + CFReleaseNull(retPref); + CFStringRef retHpub = SOSKeyedPubKeyIdentifierCopyHpub(pkidseckey); + ok(retHpub, "got hash of pubkey"); + + + CFStringRef pkiddata = SOSKeyedPubKeyIdentifierCreateWithData(properPref, pubKeyData); + ok(pkiddata, "made string"); + ok(CFEqualSafe(pkiddata, pkidseckey), "strings match"); + + //diag("pkiddata %@", pkiddata); + //diag("retPref %@", retPref); + CFReleaseNull(retHpub); + CFReleaseNull(key); + CFReleaseNull(pubKey); + CFReleaseNull(pubKeyData); + CFReleaseNull(pkidseckey); + CFReleaseNull(pkidseckeyshort); + CFReleaseNull(pkidseckeylong); + CFReleaseNull(pkiddata); + + +} + +int secd_67_prefixedKeyIDs(int argc, char *const *argv) { + plan_tests(12); + + tests(); + return 0; +} + diff --git a/keychain/securityd/Regressions/secd-70-engine-corrupt.m b/keychain/securityd/Regressions/secd-70-engine-corrupt.m new file mode 100644 index 00000000..a229bcaa --- /dev/null +++ b/keychain/securityd/Regressions/secd-70-engine-corrupt.m @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// Test syncing between SecItemDataSource and SOSTestDataSource + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +#include "keychain/SecureObjectSync/SOSDigestVector.h" +#include "keychain/SecureObjectSync/SOSEngine.h" +#include "keychain/SecureObjectSync/SOSPeer.h" +#import "keychain/SecureObjectSync/SOSChangeTracker.h" +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" +#include +#include +#include + +#include +#include + +static int kTestTestCount = 121; + +static void nosha1(void) { + __block int iteration = 0; + __block CFErrorRef error = NULL; + SOSTestDeviceListTestSync("nosha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 10 items in first 10 sync messages + if (iteration <= 6) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + SOSTestDeviceAddGenericItem(source, account, CFSTR("nosha1")); + CFReleaseSafe(account); + // Corrupt the 4th item added + if (iteration == 4) { + ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { + ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { + ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error), + "Corrupting rowid 5 by zeroing sha1: %@", error); + CFReleaseNull(error); + }), "SecDbTransaction: %@", error); + CFReleaseNull(error); + }), "SecDbPerformWrite: %@", error); + CFReleaseNull(error); + return true; + } + return true; + } + + + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("Bad"), CFSTR("Good"), NULL); +} + +static void drop_item(void) { + __block int iteration = 0; + __block CFErrorRef error = NULL; + SOSTestDeviceListTestSync("drop_item", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 10 items in first 10 sync messages + if (iteration <= 6) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_item")); + CFReleaseSafe(account); + // Corrupt the 4th item added + if (iteration == 4) { + ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { + ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { + ok(SecDbExec(dbconn, CFSTR("DELETE FROM genp WHERE rowid=5;"), &error), + "Corrupting rowid 5 by deleting object: %@", error); + CFReleaseNull(error); + }), "SecDbTransaction: %@", error); + CFReleaseNull(error); + }), "SecDbPerformWrite: %@", error); + CFReleaseNull(error); + return true; + } + return true; + } + + + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("Abegail"), CFSTR("Billy"), NULL); +} + +static void drop_manifest(void) { + __block int iteration = 0; + SOSTestDeviceListTestSync("drop_manifest", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 5 items on Alice and 4 on Bob in first 9 sync messages + if (iteration <= 9) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration / 2); + SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_manifest")); + CFReleaseSafe(account); + // Corrupt the manifest after 4th item added + if (iteration == 4) { + SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); + SOSPeerRef peer = SOSEngineCopyPeerWithID(engine, SOSTestDeviceGetID(dest), NULL); + SOSManifestRef mf = SOSEngineCopyLocalPeerManifest(engine, peer, NULL); + CFReleaseNull(peer); + CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + SOSManifestForEach(mf, ^(CFDataRef e, bool *stop) { + SOSChangesAppendDelete(changes, e); + }); + ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "droped manifest from %@", source); + CFReleaseNull(changes); + CFReleaseNull(mf); + return true; + } + return true; + } + + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("Ann"), CFSTR("Ben"), NULL); +} + +static void add_sha1(void) { + TODO: { + //todo("this never stops syncing"); + __block int iteration = 0; + __block CFErrorRef error = NULL; + SOSTestDeviceListTestSync("add_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 9 items in first 9 sync messages + if (iteration <= 9) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + SOSTestDeviceAddGenericItem(source, account, CFSTR("add_sha1")); + CFReleaseSafe(account); + // Corrupt the manifest after 4th item added + if (iteration == 4) { + ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) { + ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) { + ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error), + "Corrupting rowid 5 by zeroing sha1: %@", error); + CFReleaseNull(error); + }), "SecDbTransaction: %@", error); + CFReleaseNull(error); + }), "SecDbPerformWrite: %@", error); + CFReleaseNull(error); + + SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); + uint8_t zeroDigest[20] = {}; + CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20); + CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + SOSChangesAppendAdd(changes, zDigest); + ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest"); + CFReleaseSafe(zDigest); + CFReleaseNull(changes); + return true; + } + return true; + } + + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("Andy"), CFSTR("Bill"), NULL); + } +} + +static void change_sha1(void) { +TODO: { + //todo("this never stops syncing"); + __block int iteration = 0; + __block CFErrorRef error = NULL; + SOSTestDeviceListTestSync("change_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 9 items in first 9 sync messages + if (iteration <= 9) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + CFStringRef server = CFSTR("change_sha1"); + // Corrupt the manifest after 4th item added + if (!SOSDataSourceWithAPI(source->ds, true, &error, ^(SOSTransactionRef txn, bool *commit) { + SOSObjectRef object = SOSDataSourceCreateGenericItem(source->ds, account, server); + ok(SOSDataSourceMergeObject(source->ds, txn, object, NULL, &error), "%@ added API object %@", SOSTestDeviceGetID(source), error ? (CFTypeRef)error : (CFTypeRef)CFSTR("ok")); + if (iteration == 3) { + sqlite_int64 rowid = SecDbItemGetRowId((SecDbItemRef)object, NULL); + CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=%lld;"), rowid); + ok(SecDbExec((SecDbConnectionRef)txn, sql, &error), + "Corrupting rowid %lld by zeroing sha1: %@", rowid, error); + CFReleaseNull(sql); + SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL); + CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + uint8_t zeroDigest[20] = {}; + CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20); + SOSChangesAppendAdd(changes, zDigest); + CFDataRef digest = SOSObjectCopyDigest(source->ds, object, NULL); + SOSChangesAppendDelete(changes, digest); + const uint8_t *d = CFDataGetBytePtr(digest); + ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest %lld %02X%02x%02x%02x", + rowid, d[0], d[1], d[2], d[3]); + CFReleaseSafe(zDigest); + CFReleaseSafe(digest); + CFReleaseNull(changes); + } + CFReleaseSafe(object); + CFReleaseNull(error); + })) + fail("ds transaction %@", error); + CFReleaseNull(error); + CFReleaseNull(account); + return true; + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + if (iteration >= 3) + pass("%@", source); + return false; + }, CFSTR("Alice"), CFSTR("Bob"), NULL); +} +} + +int secd_70_engine_corrupt(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + __security_simulatecrash_enable(false); + + /* custom keychain dir */ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + nosha1(); + drop_item(); + drop_manifest(); + add_sha1(); + change_sha1(); + + __security_simulatecrash_enable(true); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-70-engine-smash.m b/keychain/securityd/Regressions/secd-70-engine-smash.m new file mode 100644 index 00000000..62be20d5 --- /dev/null +++ b/keychain/securityd/Regressions/secd-70-engine-smash.m @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 581; + +// Smash together identical items, but mute the devices every once in a while. +// (Simulating packet loss.) +static void smash(void) { + __block int iteration=0; + SOSTestDeviceListTestSync("smash", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + if (iteration < 100 && iteration % 10 == 0) { + SOSTestDeviceSetMute(source, !SOSTestDeviceIsMute(source)); + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + if (iteration++ < 200) { + CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("smash-post-%d"), iteration); + SOSTestDeviceAddGenericItem(source, name, name); + SOSTestDeviceAddGenericItem(dest, name, name); + CFReleaseNull(name); + return true; + } + return false; + }, CFSTR("alice"), CFSTR("bob"), NULL); +} + +int secd_70_engine_smash(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + /* custom keychain dir */ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + smash(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-70-engine.m b/keychain/securityd/Regressions/secd-70-engine.m new file mode 100644 index 00000000..87ac71fd --- /dev/null +++ b/keychain/securityd/Regressions/secd-70-engine.m @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// Test syncing between SecItemDataSource and SOSTestDataSource + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +#include "keychain/SecureObjectSync/SOSEngine.h" +#include "keychain/SecureObjectSync/SOSPeer.h" +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" +#include +#include +#include + +#include +#include + +__unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) { + + CFMutableArrayRef trustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFMutableArrayRef untrustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef peerID = NULL; + const uint8_t expected[20] = { 0xea, 0x6c, 0x01, 0x4d, + 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, + 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }; + + const char resultSize = sizeof(expected); + + CFDataRef coder = CFDataCreate(kCFAllocatorDefault, expected, resultSize); + CFArrayForEachC(SOSEngineGetPeerIDs(engine), peerID){ + CFArrayAppendValue(trustedPeers, peerID); + }; + CFReleaseNull(coder); + + CFShow(trustedPeers); + // all trusted + SOSEngineCircleChanged(engine, myID,trustedPeers, untrustedPeers); + + // make first peer untrusted + peerID = (CFStringRef)CFArrayGetValueAtIndex(trustedPeers, 0); + CFArrayAppendValue(untrustedPeers, peerID); + CFArrayRemoveAllValue(trustedPeers, peerID); + //we should see peerState cleared out except for the coder! + SOSEngineCircleChanged(engine, myID, trustedPeers, untrustedPeers); + + CFArrayAppendValue(trustedPeers, peerID); + CFArrayRemoveAllValue(untrustedPeers, peerID); + + + return true; +} + +static void testsync3(const char *name, const char *test_directive, const char *test_reason) { + __block int iteration=0; + SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + if (iteration == 12 || iteration == 13) { + pass("pre-rcv %@", dest); + } + if (iteration == 19) { + pass("pre-send %@", source); + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + if (iteration == 10) { + pass("pre-add %@", source); + //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service")); + SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service")); + pass("post-add %@", source); + return true; // db changed + } else if (iteration == 12 || iteration == 15) { + pass("post-rcv %@", dest); + } + return false; + }, CFSTR("AAA"), CFSTR("BBB"), CFSTR("CCC"), NULL); +} + +static void testsync2(const char *name, const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), CFStringRef msg, ...) { + __block int iteration=0; + SOSTestDeviceListTestSync(name, test_directive, test_reason, kSOSPeerVersion, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + if (iteration == 96) { + pass("%@ before message", source); + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + iteration++; + if (iteration == 60) { + pass("%@ before addition", source); + //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service")); + SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service")); + pass("%@ after addition", source); + return true; + } + return false; + }, CFSTR("alice"), CFSTR("bob"), CFSTR("claire"), CFSTR("dave"),CFSTR("edward"), CFSTR("frank"), CFSTR("gary"), NULL); +} + +static void testsync(const char *name, const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), ...) { + __block int msg_index = 0; + __block int last_msg_index = 0; + va_list args; + va_start(args, bobInit); + CFArrayRef messages = CFArrayCreateForVC(kCFAllocatorDefault, &kCFTypeArrayCallBacks, args); + SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false, + ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + if (msg_index == 0) { + aliceInit(source->ds); + bobInit(dest->ds); + return true; + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + CFStringRef hexMsg = msg_index < CFArrayGetCount(messages) ? (CFStringRef)CFArrayGetValueAtIndex(messages, msg_index) : 0; + /* We are expecting a message and msg is it's digest. */ + if (message) { + msg_index++; + CFStringRef messageDigestStr = SOSMessageCopyDigestHex(message); + if (hexMsg) { + if (CFEqual(messageDigestStr, hexMsg)) { + pass("%s %@ handled message [%d] %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, message); + } else { + TODO: { + todo("manifest caching changed"); + fail("%s %@ received message [%d] digest %@ != %@ %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, messageDigestStr, hexMsg, message); + } + } + last_msg_index = msg_index; + } else { + TODO: { + todo("manifest caching changed"); + fail("%s %@ sent extra message [%d] with digest %@: %@", name, SOSEngineGetMyID(source->ds->engine), msg_index, messageDigestStr, message); + } + } + CFReleaseSafe(messageDigestStr); + //SOSCircleHandleCircleWithLock(source->ds->engine, SOSEngineGetMyID(source->ds->engine), CFDataCreate(kCFAllocatorDefault, 0, 0), NULL); + + } + return false; + }, CFSTR("alice"), CFSTR("bob"), NULL); + + if (msg_index < CFArrayGetCount(messages)) { + TODO: { + todo("manifest caching changed"); + fail("%s nothing sent expecting message [%d] digest %@", name, msg_index, CFArrayGetValueAtIndex(messages, msg_index)); + } + } else if (last_msg_index < msg_index) { + TODO: { + todo("manifest caching changed"); + fail("%s exchanged %d messages not in expected list", name, msg_index - last_msg_index); + } + } + + +} + +#if 0 +// Test syncing an empty circle with 1 to 10 devices and both version 0 and version 2 protocols +static void testsyncempty(void) { + CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + for (int deviceIX=0; deviceIX < 10; ++deviceIX) { + CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX); + CFArrayAppendValue(deviceIDs, deviceID); + CFReleaseSafe(deviceID); + if (deviceIX > 0) { + for (CFIndex version = 0; version < 3; version += 2) { + CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, NULL); + SOSTestDeviceListSync("syncempty", test_directive, test_reason, testDevices, NULL, NULL); + SOSTestDeviceListInSync("syncempty", test_directive, test_reason, testDevices); + SOSTestDeviceDestroyEngine(testDevices); + CFReleaseSafe(testDevices); + } + } + } + CFReleaseSafe(deviceIDs); +} +#endif + +static CFIndex syncmany_add(int iteration) { + if (iteration % 7 < 3 && iteration < 10) + return iteration % 17 + 200; + return 0; +} + +static void testsyncmany(const char *name, const char *test_directive, const char *test_reason, int devFirst, int devCount, int version, CFIndex (*should_add)(int iteration)) { + CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + for (int deviceIX=0; deviceIX < devCount; ++deviceIX) { + CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX); + CFArrayAppendValue(deviceIDs, deviceID); + CFReleaseSafe(deviceID); + if (deviceIX >= devFirst) { + CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, NULL); + __block int iteration = 0; + SOSTestDeviceListSync(name, test_directive, test_reason, testDevices, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + bool didAdd = false; + iteration++; + // Add 10 items in first 10 sync messages + CFIndex toAdd = should_add(iteration); + if (toAdd) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + didAdd = SOSTestDeviceAddGenericItems(source, toAdd, account, CFSTR("testsyncmany")); + CFReleaseSafe(account); + } + if (iteration == 279 || iteration == 459) + pass("pre-send[%d] %@", iteration, source); + + return didAdd; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + if (iteration == 262) + pass("post-rcv[%d] %@", iteration, dest); + + if (iteration == 272 || iteration == 279) + pass("post-send[%d] %@", iteration, source); + + return false; + }); + SOSTestDeviceListInSync(name, test_directive, test_reason, testDevices); + SOSTestDeviceDestroyEngine(testDevices); + CFReleaseSafe(testDevices); + } + } + CFReleaseSafe(deviceIDs); +} + +static void testsync2p(void) { + __block int iteration = 0; + SOSTestDeviceListTestSync("testsync2p", test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + iteration++; + // Add 10 items in first 10 sync messages + if (iteration <= 10) { + CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration); + SOSTestDeviceAddGenericItem(source, account, CFSTR("testsync2p")); + CFReleaseSafe(account); + return true; + } + return false; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("Atestsync2p"), CFSTR("Btestsync2p"), NULL); +} + +static void synctests(void) { +#if 0 + // TODO: Adding items gives us non predictable creation and mod dates so + // the message hashes can't be precomputed. + CFDictionaryRef item = CFDictionaryCreateForCFTypes + (0, + kSecClass, kSecClassGenericPassword, + kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, + kSecAttrSynchronizable, kCFBooleanTrue, + kSecAttrService, CFSTR("service"), + kSecAttrAccount, CFSTR("account"), + NULL); + SecItemAdd(item, NULL); + CFReleaseSafe(item); +#endif + +SKIP: + { + +#ifdef NO_SERVER + // Careful with this in !NO_SERVER, it'll destroy debug keychains. + WithPathInKeychainDirectory(CFSTR("keychain-2-debug.db"), ^(const char *keychain_path) { + unlink(keychain_path); + }); + + // Don't ever do this in !NO_SERVER, it'll destroy real keychains. + WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *keychain_path) { + unlink(keychain_path); + }); + + SecKeychainDbReset(NULL); +#else + skip("Keychain not reset", 0, false); +#endif + + testsync3("secd_70_engine3", test_directive, test_reason); + + // Sync between 2 empty dataSources + testsync("secd_70_engine", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) {}, + ^ (SOSDataSourceRef dataSource) {}, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + NULL); + + // Sync a dataSource with one object to an empty dataSource + testsync("secd_70_engine-alice1", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + }), "ds transaction failed %@", error); + CFReleaseSafe(object); + CFReleaseNull(error); + }, + ^ (SOSDataSourceRef dataSource) {}, + CFSTR("DDDB2DCEB7B36F0757F400251ECD11E377A0DCE8"), + CFSTR("B2777CC898AE381B3F375B27E4FD9757F6CE9948"), + CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"), + CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + //CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"), + //CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"), + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + NULL); + + // Sync a dataSource with one object to another dataSource with the same object + testsync("secd_70_engine-alice1bob1", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) { +#if 0 + CFErrorRef error = NULL; + // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... + CFDictionaryRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + CFReleaseNull(error); +#endif + }, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + }), "ds transaction failed %@", error); + CFReleaseSafe(object); + CFReleaseNull(error); + }, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"), + CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + NULL); + + // Sync a dataSource with one object to another dataSource with the same object + testsync("secd_70_engine-alice1bob2", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) { +#if 0 + CFErrorRef error = NULL; + // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... + SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + CFReleaseNull(error); +#endif + }, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + CFReleaseNull(error); + object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + }), "ds transaction failed %@", error); + CFReleaseNull(error); + }, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"), + CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), + + //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"), + //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"), + //CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"), + //CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"), + //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), + NULL); + + // Sync a dataSource with a tombstone object to another dataSource with the same object + TODO: { + todo(" Test case in sd-70-engine fails due to need for RowID"); + testsync("secd_70_engine-update", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + const char *password = "password1"; + CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password)); + // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... + SOSObjectRef object_to_find = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), true, NULL); + SOSObjectRef object = SOSDataSourceCopyObject(dataSource, object_to_find, &error); + SOSObjectRef old_object = NULL; + SKIP: { + skip("no object", 1, ok(object, "Finding object %@, error: %@", object_to_find, error)); + CFReleaseNull(data); + // TODO: Needs to be a SecDBItemRef for the SecItemDataSource... + old_object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ update object %@", SOSEngineGetMyID(dataSource->engine), error); + }), "ds transaction failed %@", error); + } + CFReleaseSafe(data); + CFReleaseSafe(old_object); + CFReleaseSafe(object); + CFReleaseNull(error); + }, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service")); + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + CFReleaseNull(error); + object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + }), "ds transaction failed %@", error); + CFReleaseNull(error); + }, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"), + CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), + + //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"), + //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"), + //CFSTR("137FD34E9BF11B4BA0620E8EBFAB8576BCCCF294"), + //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"), + NULL); + } + + // Sync a dataSource with one object to another dataSource with the same object + testsync("secd_70_engine-foreign-add", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) { + }, + ^ (SOSDataSourceRef dataSource) { + __block CFErrorRef error = NULL; + const char *password = "password1"; + CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password)); + __block SOSObjectRef object = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), false, data); + CFReleaseSafe(data); + ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) { + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + CFReleaseNull(error); + object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1")); + ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error); + CFReleaseSafe(object); + }), "ds transaction failed %@", error); + CFReleaseNull(error); + }, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("769F63675CEE9CB968BFD9CA48DB9079BFCAFB6C"), + CFSTR("818C24B9BC495940836B9C8F76517C838CEFFA98"), + + //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), + //CFSTR("607EEF976943FD781CFD2B3850E6DC7979AA61EF"), + //CFSTR("28434CD1B90CC205460557CAC03D7F12067F2329"), + //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"), + NULL); + } + + // Sync between 2 empty dataSources + testsync2("secd_70_engine2", test_directive, test_reason, + ^ (SOSDataSourceRef dataSource) {}, + ^ (SOSDataSourceRef dataSource) {}, + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"), + NULL); + + //testsyncempty(); + testsyncmany("syncmany", test_directive, test_reason, 9, 10, 0, syncmany_add); + testsyncmany("v2syncmany", test_directive, test_reason, 9, 10, 2, syncmany_add); + testsync2p(); +} + +int secd_70_engine(int argc, char *const *argv) +{ + plan_tests(1172); + + /* custom keychain dir */ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + synctests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-70-otr-remote.m b/keychain/securityd/Regressions/secd-70-otr-remote.m new file mode 100644 index 00000000..88735ab4 --- /dev/null +++ b/keychain/securityd/Regressions/secd-70-otr-remote.m @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include + +#include "secd_regressions.h" + +#include +#include +#include +#include +#include +#include + +#include +#include "keychain/SecureObjectSync/SOSCircle.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include "SOSCircle_regressions.h" +#include "SOSRegressionUtilities.h" +#include "SOSTestDataSource.h" +#include "SecOTRRemote.h" +#include "SOSAccount.h" +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + + +static void RegressionsLogError(CFErrorRef error) { + if (error == NULL) { + return; + } + CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error); + CFIndex errorCode = CFErrorGetCode(error); + CFStringRef errorDomain = CFErrorGetDomain(error); + CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey); + CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey); + if (previousError != NULL) { + RegressionsLogError(previousError); + } + char errorDomainStr[1024]; + char errorStringStr[1024]; + + CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8); + CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8); + printf("OTR: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr); + CFReleaseSafe(tempDictionary); +} + +static int kTestTestCount = 11; +static void tests(void) +{ + NSError* ns_testError = nil; + __block CFErrorRef testError = NULL; + + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + + CFStringRef circleName = CFSTR("Woot Circle"); + + /* DataSource */ + SOSDataSourceRef aliceDs = SOSTestDataSourceCreate(); + SOSDataSourceRef bobDs = SOSTestDataSourceCreate(); + + SOSDataSourceFactoryRef aliceDsf = SOSTestDataSourceFactoryCreate(); + SOSTestDataSourceFactorySetDataSource(aliceDsf, circleName, aliceDs); + + SOSDataSourceFactoryRef bobDsf = SOSTestDataSourceFactoryCreate(); + SOSTestDataSourceFactorySetDataSource(bobDsf, circleName, bobDs); + + CFDictionaryRef alice_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice Device")); + CFDictionaryRef bob_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Bob Device")); + + SOSAccount* alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf); + SOSAccount* bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf); + + SOSAccountAssertUserCredentialsAndUpdate(alice_account, CFSTR("alice"), cfpassword, &testError); + SOSAccountAssertUserCredentialsAndUpdate(bob_account, CFSTR("bob"), cfpassword, &testError); + + CFReleaseNull(cfpassword); + + SOSAccountJoinCircles_wTxn(alice_account, &testError); + SOSAccountJoinCircles_wTxn(bob_account, &testError); + + NSData* alice_account_data = [alice_account encodedData:&ns_testError]; + NSData* bob_account_data = [bob_account encodedData:&ns_testError];; + + CFArrayRef alice_peers = SOSAccountCopyPeers(alice_account, &testError); + CFArrayRef bob_peers = SOSAccountCopyPeers(bob_account, &testError); + + SOSPeerInfoRef alice_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(alice_peers, 0); + SOSPeerInfoRef bob_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(bob_peers, 0); + + CFStringRef alice_peer_id = SOSPeerInfoGetPeerID(alice_peer_info); + CFStringRef bob_peer_id = SOSPeerInfoGetPeerID(bob_peer_info); + + CFDataRef alice_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, alice_peer_id, kCFStringEncodingUTF8, '?'); + CFDataRef bob_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, bob_peer_id, kCFStringEncodingUTF8, '?'); + + bool aliceReady = false; + bool bobReady = false; + + CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) bob_account_data, bob_peer_external_form, (__bridge CFDataRef) alice_account_data, &testError); + RegressionsLogError(testError); + CFReleaseNull(testError); + + ok(aliceSideSession != NULL, "Make Alice side remote session"); + + CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) alice_account_data, alice_peer_external_form, (__bridge CFDataRef) bob_account_data, &testError); + RegressionsLogError(testError); + CFReleaseNull(testError); + + ok(bobSideSession != NULL, "Make Bob side remote session"); + + CFDataRef aliceSideSessionResult = NULL; + CFDataRef bobSideSessionResult = NULL; + CFDataRef aliceToBob = NULL; + CFDataRef bobToAlice = NULL; + + do { + bool aliceStatus = SecOTRSessionProcessPacketRemote(aliceSideSession, bobToAlice, &aliceSideSessionResult, &aliceToBob, &aliceReady, &testError); + ok (aliceStatus, "Alice sent packet OK"); + RegressionsLogError(testError); + CFReleaseNull(testError); + CFReleaseSafe(aliceSideSession); + aliceSideSession = aliceSideSessionResult; + + if (aliceReady) { + break; + } + + bool bobStatus = SecOTRSessionProcessPacketRemote(bobSideSession, aliceToBob, &bobSideSessionResult, &bobToAlice, &bobReady, &testError); + ok (bobStatus, "Bob sent packet OK"); + RegressionsLogError(testError); + CFReleaseNull(testError); + CFReleaseSafe(bobSideSession); + bobSideSession = bobSideSessionResult; + } while (1); + + ok(bobReady, "Bob finished negotiating at the same time as Alice."); + + CFReleaseNull(aliceSideSession); + CFReleaseNull(bobSideSession); + SOSDataSourceRelease(aliceDs, NULL); + SOSDataSourceFactoryRelease(aliceDsf); + + SOSDataSourceRelease(bobDs, NULL); + SOSDataSourceFactoryRelease(bobDsf); + + SecOTRFIPurgeAllFromKeychain(&testError); + RegressionsLogError(testError); + CFReleaseNull(bob_peer_external_form); + CFReleaseNull(alice_peer_external_form); + CFReleaseNull(alice_peers); + CFReleaseNull(bob_peers); + CFReleaseNull(aliceSideSession); + CFReleaseNull(bobSideSession); + CFReleaseNull(testError); +} + +int secd_70_otr_remote(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-71-engine-save-sample1.h b/keychain/securityd/Regressions/secd-71-engine-save-sample1.h new file mode 100644 index 00000000..b2916f85 --- /dev/null +++ b/keychain/securityd/Regressions/secd-71-engine-save-sample1.h @@ -0,0 +1,125 @@ + +/* + MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state + acct : engine-state + agrp : com.apple.security.sos + cdat : 2016-04-18 20:40:33 +0000 + mdat : 2016-04-18 20:40:33 +0000 + musr : // + pdmn : dk + svce : SOSDataSource-ak + sync : 0 + tomb : 0 +*/ + +static unsigned char es_mango_bin[] = { + 0x31, 0x82, 0x0a, 0x1b, 0x30, 0x20, 0x0c, 0x02, 0x69, 0x64, 0x0c, 0x1a, 0x68, 0x42, 0x79, 0x73, 0x6d, 0x66, 0x31, 0x73, 0x44, 0x4f, 0x63, 0x2f, + 0x6f, 0x4d, 0x56, 0x49, 0x51, 0x66, 0x45, 0x74, 0x4b, 0x69, 0x71, 0x65, 0x64, 0x6e, 0x30, 0x27, 0x0c, 0x07, 0x70, 0x65, 0x65, 0x72, 0x49, 0x44, + 0x73, 0x30, 0x1c, 0x0c, 0x1a, 0x79, 0x48, 0x6d, 0x77, 0x76, 0x76, 0x6f, 0x75, 0x44, 0x38, 0x65, 0x44, 0x4d, 0x74, 0x49, 0x48, 0x5a, 0x66, 0x39, + 0x75, 0x65, 0x75, 0x53, 0x58, 0x2f, 0x47, 0x30, 0x82, 0x03, 0xa3, 0x0c, 0x0d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x43, 0x61, 0x63, + 0x68, 0x65, 0x31, 0x82, 0x03, 0x90, 0x30, 0x18, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, + 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x04, 0x00, 0x30, 0x7c, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, + 0x0c, 0x5b, 0xe3, 0xaf, 0x06, 0x2c, 0x77, 0x5b, 0x04, 0x64, 0x5a, 0x57, 0x4b, 0xb4, 0xec, 0x90, 0xc3, 0xbb, 0xcc, 0x69, 0xee, 0x73, 0xcb, 0xfe, + 0x03, 0x91, 0x33, 0xae, 0x80, 0x72, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, + 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, + 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, 0xab, 0xa3, 0xca, 0x34, 0x29, 0x66, + 0xef, 0xf8, 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0x30, 0x82, 0x01, 0x6e, 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, + 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x04, 0x82, 0x01, 0x54, 0x07, 0x57, 0x1e, 0x96, + 0x78, 0xfd, 0x7d, 0x68, 0x81, 0x2e, 0x40, 0x9c, 0xc9, 0x6c, 0x1f, 0x54, 0x83, 0x4a, 0x09, 0x9a, 0x0c, 0x3a, 0x2d, 0x12, 0xcc, 0xe2, 0xea, 0x95, + 0xf4, 0x50, 0x5e, 0xa5, 0x2f, 0x2c, 0x98, 0x2b, 0x2a, 0xde, 0xe3, 0xda, 0x14, 0xd4, 0x71, 0x2c, 0x00, 0x03, 0x09, 0xbf, 0x63, 0xd5, 0x4a, 0x98, + 0xb6, 0x1a, 0xa1, 0xd9, 0x63, 0xc4, 0x0e, 0x0e, 0x25, 0x31, 0xc8, 0x3b, 0x28, 0xca, 0x5b, 0xe6, 0xda, 0x0d, 0x26, 0x40, 0x0c, 0x3c, 0x77, 0xa6, + 0x18, 0xf7, 0x11, 0xdd, 0x3c, 0xc0, 0xbf, 0x86, 0xcc, 0xba, 0xf8, 0xaa, 0x33, 0x32, 0x97, 0x32, 0x68, 0xb3, 0x0e, 0xeb, 0xf2, 0x1c, 0xd8, 0x18, + 0x4d, 0x9c, 0x84, 0x27, 0xca, 0x13, 0xde, 0xcc, 0xc7, 0xbb, 0x83, 0xc8, 0x00, 0x09, 0xa2, 0xef, 0x45, 0xcc, 0xc0, 0x7f, 0x58, 0x63, 0x15, 0xc8, + 0x0c, 0xee, 0xee, 0xf5, 0xd5, 0x35, 0x2f, 0xd0, 0x00, 0xaa, 0xe6, 0xd9, 0xcb, 0xb4, 0x29, 0x4d, 0x59, 0x59, 0xfd, 0x00, 0x19, 0x82, 0x25, 0xaf, + 0x9a, 0xbd, 0x09, 0xb3, 0x41, 0xa2, 0xfd, 0xc2, 0x78, 0xe9, 0xfd, 0x14, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, + 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, + 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, + 0x95, 0xc9, 0xd4, 0xd8, 0xa8, 0xbc, 0xa2, 0xe8, 0x24, 0x2a, 0xb0, 0xd4, 0x09, 0xf6, 0x71, 0xf2, 0x98, 0xb6, 0xdc, 0xae, 0x9b, 0xc4, 0x23, 0x8c, + 0x09, 0xe0, 0x75, 0x48, 0xce, 0xfb, 0x30, 0x00, 0x98, 0x60, 0x6f, 0x9e, 0x4f, 0x23, 0x0c, 0x99, 0xab, 0xa3, 0xca, 0x34, 0x29, 0x66, 0xef, 0xf8, + 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0xb4, 0xfe, 0xfb, 0x84, 0xf8, 0xcf, 0x75, 0xc0, 0xc6, 0x9c, 0x59, 0x53, + 0x2c, 0x35, 0x4d, 0x17, 0x5a, 0x59, 0xf9, 0x61, 0xba, 0x4d, 0x4d, 0xfa, 0x01, 0x7f, 0xd8, 0x19, 0x22, 0x88, 0xf1, 0x42, 0x78, 0xae, 0x76, 0x71, + 0x2e, 0x12, 0x7d, 0x65, 0xfe, 0x61, 0x6c, 0x7e, 0x4f, 0xd0, 0x71, 0x36, 0x44, 0xf7, 0xc9, 0xa7, 0xab, 0xa1, 0xce, 0x06, 0x56, 0x94, 0xa9, 0x68, + 0x30, 0x82, 0x01, 0x82, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, + 0xdc, 0xad, 0x04, 0x82, 0x01, 0x68, 0x07, 0x57, 0x1e, 0x96, 0x78, 0xfd, 0x7d, 0x68, 0x81, 0x2e, 0x40, 0x9c, 0xc9, 0x6c, 0x1f, 0x54, 0x83, 0x4a, + 0x09, 0x9a, 0x0c, 0x3a, 0x2d, 0x12, 0xcc, 0xe2, 0xea, 0x95, 0xf4, 0x50, 0x5e, 0xa5, 0x2f, 0x2c, 0x98, 0x2b, 0x2a, 0xde, 0xe3, 0xda, 0x14, 0xd4, + 0x71, 0x2c, 0x00, 0x03, 0x09, 0xbf, 0x63, 0xd5, 0x4a, 0x98, 0xb6, 0x1a, 0xa1, 0xd9, 0x63, 0xc4, 0x0e, 0x0e, 0x25, 0x31, 0xc8, 0x3b, 0x28, 0xca, + 0x5b, 0xe6, 0xda, 0x0d, 0x26, 0x40, 0x0c, 0x3c, 0x77, 0xa6, 0x18, 0xf7, 0x11, 0xdd, 0x3c, 0xc0, 0xbf, 0x86, 0xcc, 0xba, 0xf8, 0xaa, 0x33, 0x32, + 0x97, 0x32, 0x68, 0xb3, 0x0e, 0xeb, 0xf2, 0x1c, 0xd8, 0x18, 0x4d, 0x9c, 0x84, 0x27, 0xca, 0x13, 0xde, 0xcc, 0xc7, 0xbb, 0x83, 0xc8, 0x00, 0x09, + 0xa2, 0xef, 0x45, 0xcc, 0xc0, 0x7f, 0x58, 0x63, 0x15, 0xc8, 0x0c, 0xee, 0xee, 0xf5, 0xd5, 0x35, 0x2f, 0xd0, 0x00, 0xaa, 0xe6, 0xd9, 0xcb, 0xb4, + 0x29, 0x4d, 0x59, 0x59, 0xfd, 0x00, 0x19, 0x82, 0x25, 0xaf, 0x9a, 0xbd, 0x09, 0xb3, 0x41, 0xa2, 0xfd, 0xc2, 0x78, 0xe9, 0xfd, 0x14, 0x5a, 0x57, + 0x4b, 0xb4, 0xec, 0x90, 0xc3, 0xbb, 0xcc, 0x69, 0xee, 0x73, 0xcb, 0xfe, 0x03, 0x91, 0x33, 0xae, 0x80, 0x72, 0x65, 0xd6, 0xa5, 0x80, 0x03, 0xb8, + 0xd2, 0x05, 0x99, 0x7e, 0xab, 0x96, 0x39, 0x0a, 0xab, 0x20, 0x7e, 0x63, 0xa2, 0xe2, 0x70, 0xa4, 0x76, 0xca, 0xb5, 0xb2, 0xd9, 0xd2, 0xf7, 0xb0, + 0xe5, 0x55, 0x12, 0xaa, 0x95, 0x7b, 0x58, 0xd5, 0x65, 0x8e, 0x7e, 0xf9, 0x07, 0xb0, 0x69, 0xb8, 0x3a, 0xa6, 0xba, 0x94, 0x17, 0x90, 0xa3, 0xc3, + 0xc4, 0xa6, 0x82, 0x92, 0xd5, 0x9d, 0x95, 0xc9, 0xd4, 0xd8, 0xa8, 0xbc, 0xa2, 0xe8, 0x24, 0x2a, 0xb0, 0xd4, 0x09, 0xf6, 0x71, 0xf2, 0x98, 0xb6, + 0xdc, 0xae, 0x9b, 0xc4, 0x23, 0x8c, 0x09, 0xe0, 0x75, 0x48, 0xce, 0xfb, 0x30, 0x00, 0x98, 0x60, 0x6f, 0x9e, 0x4f, 0x23, 0x0c, 0x99, 0xab, 0xa3, + 0xca, 0x34, 0x29, 0x66, 0xef, 0xf8, 0x2e, 0x1a, 0xca, 0xeb, 0x69, 0x1f, 0xd6, 0xe2, 0x07, 0x72, 0xe1, 0x7e, 0xb4, 0xfe, 0xfb, 0x84, 0xf8, 0xcf, + 0x75, 0xc0, 0xc6, 0x9c, 0x59, 0x53, 0x2c, 0x35, 0x4d, 0x17, 0x5a, 0x59, 0xf9, 0x61, 0xba, 0x4d, 0x4d, 0xfa, 0x01, 0x7f, 0xd8, 0x19, 0x22, 0x88, + 0xf1, 0x42, 0x78, 0xae, 0x76, 0x71, 0x2e, 0x12, 0x7d, 0x65, 0xfe, 0x61, 0x6c, 0x7e, 0x4f, 0xd0, 0x71, 0x36, 0x44, 0xf7, 0xc9, 0xa7, 0xab, 0xa1, + 0xce, 0x06, 0x56, 0x94, 0xa9, 0x68, 0x30, 0x82, 0x06, 0x25, 0x0c, 0x09, 0x70, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x82, 0x06, + 0x16, 0x30, 0x81, 0xd5, 0x0c, 0x0f, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x56, 0x30, 0x2d, 0x74, 0x6f, 0x6d, 0x62, 0x31, 0x81, 0xc1, + 0x30, 0x0e, 0x0c, 0x09, 0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x01, 0x01, 0x00, 0x30, 0x11, 0x0c, 0x0c, 0x73, 0x65, 0x6e, 0x64, + 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x01, 0x01, 0x01, 0x30, 0x12, 0x0c, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x6e, + 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x00, 0x30, 0x14, 0x0c, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x02, 0x01, 0x00, 0x30, 0x1a, 0x0c, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, 0xd1, 0x11, 0x0c, 0x0f, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x56, 0x30, 0x2d, 0x74, 0x6f, 0x6d, 0x62, 0x30, 0x2a, 0x0c, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x6e, + 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x16, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, 0x0c, 0x5b, 0xe3, + 0xaf, 0x06, 0x2c, 0x77, 0x5b, 0x30, 0x2a, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, + 0x65, 0x73, 0x74, 0x04, 0x14, 0xf9, 0xb5, 0x93, 0x70, 0xa4, 0x73, 0x3f, 0x0d, 0x17, 0x4e, 0x8d, 0x22, 0x0c, 0x5b, 0xe3, 0xaf, 0x06, 0x2c, 0x77, + 0x5b, 0x30, 0x82, 0x05, 0x3a, 0x0c, 0x1a, 0x79, 0x48, 0x6d, 0x77, 0x76, 0x76, 0x6f, 0x75, 0x44, 0x38, 0x65, 0x44, 0x4d, 0x74, 0x49, 0x48, 0x5a, + 0x66, 0x39, 0x75, 0x65, 0x75, 0x53, 0x58, 0x2f, 0x47, 0x31, 0x82, 0x05, 0x1a, 0x30, 0x0e, 0x0c, 0x09, 0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x65, + 0x6e, 0x64, 0x01, 0x01, 0x00, 0x30, 0x11, 0x0c, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x01, 0x01, 0x00, + 0x30, 0x14, 0x0c, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x02, 0x01, 0x03, 0x30, 0x27, + 0x0c, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x30, 0x29, 0x0c, 0x11, 0x75, 0x6e, 0x77, 0x61, 0x6e, + 0x74, 0x65, 0x64, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x04, 0x14, 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, 0x30, 0x2a, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x2d, + 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, + 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, 0x30, 0x3e, 0x0c, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x30, 0x2c, 0x04, 0x14, 0xcc, 0xf1, 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, + 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x30, 0x40, + 0x0c, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x30, 0x2c, 0x04, 0x14, 0xcc, 0xf1, + 0x79, 0xff, 0x71, 0x8c, 0x10, 0xf1, 0x51, 0xe7, 0x40, 0x9e, 0xdf, 0x1a, 0x06, 0xf0, 0xdf, 0x10, 0xdc, 0xad, 0x04, 0x14, 0x2e, 0x69, 0xc2, 0xf7, + 0xf3, 0xe0, 0x14, 0x07, 0x5b, 0x30, 0x00, 0x4c, 0xe0, 0xec, 0x6c, 0x1a, 0xd4, 0x19, 0xeb, 0xf5, 0x30, 0x82, 0x01, 0x16, 0x0c, 0x05, 0x76, 0x69, + 0x65, 0x77, 0x73, 0xd1, 0x82, 0x01, 0x0b, 0x0c, 0x04, 0x57, 0x69, 0x46, 0x69, 0x0c, 0x07, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x54, 0x56, 0x0c, 0x07, + 0x48, 0x6f, 0x6d, 0x65, 0x4b, 0x69, 0x74, 0x0c, 0x07, 0x50, 0x43, 0x53, 0x2d, 0x46, 0x44, 0x45, 0x0c, 0x09, 0x50, 0x43, 0x53, 0x2d, 0x4e, 0x6f, + 0x74, 0x65, 0x73, 0x0c, 0x09, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x45, 0x73, 0x63, 0x72, 0x6f, 0x77, 0x0c, 0x0a, 0x50, 0x43, 0x53, 0x2d, 0x50, 0x68, 0x6f, 0x74, + 0x6f, 0x73, 0x0c, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x61, 0x67, 0x56, 0x30, 0x0c, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x43, + 0x61, 0x72, 0x64, 0x73, 0x0c, 0x0b, 0x50, 0x43, 0x53, 0x2d, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x43, + 0x6c, 0x6f, 0x75, 0x64, 0x4b, 0x69, 0x74, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x46, 0x65, 0x6c, 0x64, 0x73, 0x70, 0x61, 0x72, 0x0c, 0x0c, 0x50, + 0x43, 0x53, 0x2d, 0x4d, 0x61, 0x69, 0x6c, 0x64, 0x72, 0x6f, 0x70, 0x0c, 0x0c, 0x50, 0x43, 0x53, 0x2d, 0x69, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x0c, 0x0d, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x53, 0x79, 0x6e, 0x63, 0x61, 0x62, 0x6c, 0x65, 0x0c, 0x0d, 0x50, 0x43, 0x53, 0x2d, 0x4d, 0x61, + 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x0c, 0x0e, 0x69, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x0c, + 0x0f, 0x50, 0x43, 0x53, 0x2d, 0x69, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x44, 0x72, 0x69, 0x76, 0x65, 0x0c, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, + 0x75, 0x69, 0x74, 0x79, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x30, 0x82, 0x02, 0xc1, 0x0c, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x04, 0x82, 0x02, + 0xb6, 0x30, 0x82, 0x02, 0xb2, 0x04, 0x82, 0x02, 0xab, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x0c, 0x6b, 0x65, 0x79, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x04, 0x46, 0x62, 0x20, 0xcd, 0xee, 0x34, 0x9b, 0xb8, 0x68, 0x98, 0x21, 0xa6, 0xfc, 0x3a, 0x7c, 0xc3, + 0x77, 0x5d, 0x58, 0x39, 0xaf, 0xd6, 0x3c, 0xc6, 0x1c, 0xf9, 0x1e, 0xa8, 0xdb, 0x93, 0xba, 0xdd, 0xc6, 0x29, 0x6e, 0x86, 0xd9, 0x54, 0xc2, 0xe3, + 0x3d, 0x5f, 0x3b, 0x13, 0x87, 0xe1, 0xad, 0x4e, 0x06, 0x12, 0xab, 0xc0, 0x5e, 0x60, 0x4e, 0xf8, 0x2c, 0x37, 0x97, 0xa9, 0x5d, 0xc8, 0x25, 0x12, + 0x30, 0x45, 0x81, 0x43, 0x00, 0x41, 0x04, 0x70, 0xbc, 0xaa, 0x24, 0x80, 0xbf, 0x11, 0x7e, 0xeb, 0x2c, 0x4f, 0xe2, 0x86, 0xf3, 0x38, 0xab, 0x48, + 0x3c, 0xe5, 0xd7, 0xdc, 0x69, 0xb7, 0x81, 0x71, 0x83, 0x9b, 0xf3, 0xf7, 0xa0, 0x96, 0x0b, 0xe8, 0xcd, 0xef, 0xf7, 0x26, 0x0a, 0x7a, 0xc1, 0x22, + 0x7d, 0xa0, 0x00, 0x13, 0x2a, 0x95, 0xee, 0x89, 0x83, 0x9b, 0x7a, 0xf0, 0x56, 0x24, 0x28, 0x89, 0x86, 0x2e, 0x3a, 0x06, 0xca, 0xea, 0x7d, 0x67, + 0x0c, 0x42, 0x15, 0x56, 0x55, 0xc2, 0x39, 0x13, 0x89, 0x31, 0x73, 0xf1, 0x26, 0xce, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x41, 0x04, 0x3a, 0x81, 0x2c, 0x93, 0xa5, 0xe2, 0x51, 0x73, 0xe3, 0xe8, 0xe4, 0xa1, 0x4b, 0xaf, 0xf9, 0xfe, 0x5c, 0x34, 0x2b, 0xde, 0xc1, 0x0a, + 0xe7, 0x14, 0x41, 0x4c, 0xbd, 0x93, 0xc5, 0x8e, 0x2e, 0x57, 0x0d, 0xcf, 0x68, 0x85, 0x89, 0xe8, 0x47, 0xfc, 0xf1, 0x57, 0xcb, 0xcf, 0x55, 0x6b, + 0x30, 0xf9, 0x95, 0x30, 0x73, 0x05, 0x90, 0x26, 0xad, 0x67, 0x6b, 0x52, 0x0a, 0x14, 0x35, 0x66, 0x6c, 0x68, 0x00, 0x00, 0x00, 0x20, 0xb7, 0x75, + 0x89, 0x6c, 0xa0, 0xf3, 0xb8, 0x5c, 0xcb, 0x42, 0x76, 0x5c, 0xfa, 0x23, 0xbc, 0x31, 0x25, 0x2c, 0xff, 0xbf, 0xab, 0x42, 0x93, 0xe3, 0xfe, 0xa5, + 0xab, 0xa1, 0x8b, 0xb9, 0xfb, 0x5d, 0x00, 0x00, 0x00, 0x41, 0x04, 0x32, 0xa0, 0x73, 0xc6, 0x84, 0x50, 0x7c, 0xd6, 0xad, 0x0f, 0x4e, 0x8e, 0x89, + 0xbb, 0x87, 0xe1, 0x41, 0xad, 0xc3, 0xfc, 0x10, 0x6a, 0x03, 0x2e, 0x80, 0x87, 0x57, 0xf0, 0x28, 0xbc, 0xd3, 0x2b, 0x70, 0xf5, 0x71, 0x33, 0x03, + 0x92, 0xa7, 0x6f, 0x85, 0xa3, 0x51, 0xc5, 0xa5, 0xea, 0xd3, 0xd1, 0x5d, 0xbf, 0xf1, 0x94, 0x1e, 0xb9, 0x14, 0x76, 0x6a, 0xa5, 0x6e, 0xbb, 0x3a, + 0x84, 0xa9, 0xd4, 0x00, 0x00, 0x00, 0x20, 0x69, 0x79, 0x82, 0x88, 0xd1, 0x99, 0x93, 0x6e, 0x8d, 0x67, 0x02, 0x00, 0xb1, 0xe5, 0x09, 0x90, 0x1c, + 0xa0, 0x9d, 0x4c, 0xb5, 0x4c, 0x8c, 0x21, 0x4b, 0x51, 0x16, 0x4a, 0x85, 0x43, 0x11, 0x51, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, + 0x04, 0x51, 0xbc, 0xc5, 0xb7, 0xa1, 0xa1, 0xf0, 0x8c, 0x32, 0xb0, 0xe0, 0x37, 0x71, 0x60, 0x7a, 0x52, 0x67, 0x92, 0x24, 0x13, 0xa1, 0x57, 0x24, + 0x7d, 0x04, 0x86, 0x97, 0x70, 0xb0, 0xfd, 0xbd, 0xda, 0x73, 0xea, 0x21, 0x59, 0xaa, 0x5e, 0x93, 0xcd, 0x92, 0xbb, 0x23, 0x9d, 0x28, 0x67, 0x78, + 0xa4, 0x6f, 0xa5, 0x98, 0xcd, 0x43, 0x7b, 0xf1, 0xf2, 0xf3, 0x65, 0xa0, 0xa3, 0x7d, 0xd9, 0xb1, 0x91, 0x00, 0x00, 0x00, 0x41, 0x04, 0xd5, 0x55, + 0x5f, 0xa3, 0x0d, 0xfa, 0x00, 0xea, 0x45, 0xf2, 0x3d, 0x27, 0xc8, 0xa5, 0x44, 0x7c, 0xa7, 0xc0, 0x01, 0x62, 0x26, 0xab, 0x44, 0x4b, 0xe1, 0xf6, + 0x89, 0x2a, 0x2b, 0x8c, 0x52, 0xaa, 0x0c, 0x1b, 0xfa, 0xf8, 0x3d, 0x1b, 0xbe, 0xc1, 0x29, 0x08, 0xdf, 0xa7, 0x30, 0x89, 0x0b, 0x5a, 0xdd, 0xcf, + 0xd6, 0x2e, 0x1a, 0x63, 0x81, 0x39, 0x0c, 0x61, 0x1a, 0x64, 0x0c, 0x0d, 0xb3, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xad, 0xc2, 0xb3, 0xe0, 0x47, 0xbe, 0xbd, 0x4f, 0xe1, 0x4b, 0xd9, 0x2c, 0x5d, 0x08, + 0x88, 0xb2, 0x0f, 0x2a, 0xf5, 0x9a, 0x15, 0xa3, 0xb7, 0x3b, 0xd8, 0xe6, 0x48, 0x33, 0x30, 0x51, 0x26, 0x6a, 0x31, 0x99, 0x24, 0x63, 0xa8, 0xaa, + 0xa7, 0x46, 0xdd, 0xcf, 0x62, 0xec, 0x98, 0x97, 0xbe, 0xe0, 0xd3, 0x41, 0x15, 0x58, 0x42, 0x62, 0xd8, 0x55, 0x02, 0xc4, 0x46, 0x5c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00 +}; +unsigned int es_mango_bin_len = 2591; diff --git a/keychain/securityd/Regressions/secd-71-engine-save.m b/keychain/securityd/Regressions/secd-71-engine-save.m new file mode 100644 index 00000000..1f9eabf1 --- /dev/null +++ b/keychain/securityd/Regressions/secd-71-engine-save.m @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// Test save and restore of SOSEngine states + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +#include "keychain/SecureObjectSync/SOSEngine.h" +#include "keychain/SecureObjectSync/SOSPeer.h" +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" +#include +#include +#include + +#include +#include + +static int kTestTestCount = 8; + +/* + Attributes for a v0 engine-state genp item + + MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state + acct : engine-state + agrp : com.apple.security.sos + cdat : 2016-04-18 20:40:33 +0000 + mdat : 2016-04-18 20:40:33 +0000 + musr : // + pdmn : dk + svce : SOSDataSource-ak + sync : 0 + tomb : 0 + */ + +#include "secd-71-engine-save-sample1.h" + +static bool verifyV2EngineState(SOSDataSourceRef ds, CFStringRef myPeerID) { + bool rx = false; + CFErrorRef error = NULL; + SOSTransactionRef txn = NULL; + CFDataRef basicEngineState = NULL; + CFDictionaryRef engineState = NULL; + + SKIP: { + CFDataRef basicEngineState = SOSDataSourceCopyStateWithKey(ds, kSOSEngineStatev2, kSecAttrAccessibleAlwaysPrivate, txn, &error); + skip("Failed to get V2 engine state", 2, basicEngineState); + ok(basicEngineState, "SOSDataSourceCopyStateWithKey:kSOSEngineStatev2"); + engineState = derStateToDictionaryCopy(basicEngineState, &error); + skip("Failed to DER decode V2 engine state", 1, basicEngineState); + CFStringRef engID = (CFStringRef)asString(CFDictionaryGetValue(engineState, CFSTR("id")), &error); + ok(CFEqualSafe(myPeerID, engID),"Check myPeerID"); + rx = true; + } + + CFReleaseSafe(basicEngineState); + CFReleaseSafe(engineState); + CFReleaseSafe(error); + return rx; +} + +static bool verifyV2PeerStates(SOSDataSourceRef ds, CFStringRef myPeerID, CFArrayRef peers) { + bool rx = false; + __block CFErrorRef error = NULL; + SOSTransactionRef txn = NULL; + CFDictionaryRef peerStateDict = NULL; + CFDataRef data = NULL; + __block CFIndex peerCount = CFArrayGetCount(peers) - 1; // drop myPeerID + + SKIP: { + data = SOSDataSourceCopyStateWithKey(ds, kSOSEnginePeerStates, kSOSEngineProtectionDomainClassD, txn, &error); + skip("Failed to get V2 peerStates", 3, data); + + peerStateDict = derStateToDictionaryCopy(data, &error); + skip("Failed to DER decode V2 peerStates", 2, peerStateDict); + ok(peerStateDict, "SOSDataSourceCopyStateWithKey:kSOSEnginePeerStates"); + + // Check that each peer passed in exists in peerStateDict + CFArrayForEach(peers, ^(const void *key) { + CFStringRef peerID = (CFStringRef)asString(key, &error); + if (!CFEqualSafe(myPeerID, peerID)) { + if (CFDictionaryContainsKey(peerStateDict, peerID)) + peerCount--; + } + }); + ok(peerCount==0,"Peers exist in peer list (%ld)", (CFArrayGetCount(peers) - 1 - peerCount)); + rx = true; + } + + CFReleaseSafe(peerStateDict); + CFReleaseSafe(data); + CFReleaseSafe(error); + return rx; +} + +static bool checkV2EngineStates(SOSTestDeviceRef td, CFStringRef myPeerID, CFArrayRef peers) { + bool rx = true; + CFErrorRef error = NULL; + SOSTransactionRef txn = NULL; + CFDictionaryRef manifestCache = NULL; + CFDataRef data = NULL; +// CFMutableDictionaryRef codersDict = NULL; // SOSEngineLoadCoders + + rx &= verifyV2EngineState(td->ds, myPeerID); + + data = SOSDataSourceCopyStateWithKey(td->ds, kSOSEngineManifestCache, kSOSEngineProtectionDomainClassD, txn, &error); + manifestCache = derStateToDictionaryCopy(data, &error); + CFReleaseNull(data); + + rx &= verifyV2PeerStates(td->ds, myPeerID, peers); + + CFReleaseSafe(manifestCache); + return rx; +} + +static void testSaveRestore(void) { + CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayAppendValue(deviceIDs, CFSTR("lemon")); + CFArrayAppendValue(deviceIDs, CFSTR("lime")); + CFArrayAppendValue(deviceIDs, CFSTR("orange")); + bool bx = false; + int version = 2; + CFErrorRef error = NULL; + __block int devIdx = 0; + CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, ^(SOSDataSourceRef ds) { + // This block is called before SOSEngineLoad + if (devIdx == 0) { + // Test migration of v0 to v2 engine state + CFDataRef engineStateData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, es_mango_bin, es_mango_bin_len, kCFAllocatorNull); + SOSTestDeviceAddV0EngineStateWithData(ds, engineStateData); + CFReleaseSafe(engineStateData); + } + devIdx++; + }); + + CFStringRef sourceID = (CFStringRef)CFArrayGetValueAtIndex(deviceIDs, 0); + SOSTestDeviceRef source = (SOSTestDeviceRef)CFDictionaryGetValue(testDevices, sourceID); + + ok(SOSTestDeviceEngineSave(source, &error),"SOSTestDeviceEngineSave: %@",error); + + bx = SOSTestDeviceEngineLoad(source, &error); + ok(bx,"SOSTestEngineLoad: %@",error); + + bx = checkV2EngineStates(source, sourceID, deviceIDs); + ok(bx,"getV2EngineStates: %@",error); + + bx = SOSTestDeviceEngineSave(source, &error); + ok(bx,"SOSTestDeviceEngineSave v2: %@",error); + + SOSTestDeviceDestroyEngine(testDevices); + CFReleaseSafe(deviceIDs); + CFReleaseSafe(testDevices); + CFReleaseSafe(error); +} + +int secd_71_engine_save(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + testSaveRestore(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-74-engine-beer-servers.m b/keychain/securityd/Regressions/secd-74-engine-beer-servers.m new file mode 100644 index 00000000..d814afdf --- /dev/null +++ b/keychain/securityd/Regressions/secd-74-engine-beer-servers.m @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 646; + +// Add 1000 items on each device. Then delete 1000 items on each device. +static void beer_servers(void) { + __block int iteration=0; + __block int objectix=0; + __block CFMutableArrayRef objectNames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + const size_t itemDataSize = 1024; + const int peerCount = 4; + const int edgeCount = peerCount * (peerCount - 1); + const int itemsPerPeer = 1000; + const int itemsPerIteration = 100; + const int itemChunkCount = (itemsPerPeer / itemsPerIteration); + const int deleteIteration = edgeCount * (itemChunkCount + 30); + const int idleIteration = 616; //deleteIteration + edgeCount * (itemChunkCount + 10); + + CFMutableDataRef itemData = CFDataCreateMutable(kCFAllocatorDefault, itemDataSize); + CFDataSetLength(itemData, itemDataSize); + SOSTestDeviceListTestSync("beer_servers", test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + bool result = false; + if (iteration <= edgeCount * itemChunkCount) { + if (iteration % (peerCount - 1) == 0) { + for (int j = 0; j < itemsPerIteration; ++j) { + CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-pre-%d"), SOSTestDeviceGetID(source), objectix++); + CFArrayAppendValue(objectNames, name); + SOSTestDeviceAddGenericItemWithData(source, name, name, itemData); + CFReleaseNull(name); + } + } + result = true; + } else if (iteration == deleteIteration) { + //diag("deletion starting"); + } else if (deleteIteration < iteration && iteration <= deleteIteration + edgeCount * itemChunkCount) { + if (iteration % (peerCount - 1) == 0) { + for (int j = 0; j < itemsPerIteration; ++j) { + CFStringRef name = CFArrayGetValueAtIndex(objectNames, --objectix); + SOSTestDeviceAddGenericItemTombstone(source, name, name); + } + result = true; + } + } else if (idleIteration == iteration) { + //diag("idle starting"); + } else if (617 == iteration) { + //diag("interesting"); + } + iteration++; + return result || iteration < deleteIteration; + }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }, CFSTR("becks"), CFSTR("corona"), CFSTR("heineken"), CFSTR("spaten"), NULL); + CFRelease(objectNames); + CFRelease(itemData); +} + +int secd_74_engine_beer_servers(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + /* custom keychain dir */ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + beer_servers(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-75-engine-views.m b/keychain/securityd/Regressions/secd-75-engine-views.m new file mode 100644 index 00000000..6e65d3c3 --- /dev/null +++ b/keychain/securityd/Regressions/secd-75-engine-views.m @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h" +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" +#include +#include "keychain/SecureObjectSync/SOSPeer.h" + +static int kTestTestCount = 53; + +// Add 1000 items on each device. Then delete 1000 items on each device. +static void test_engine_views(void) { + __block int iteration=0; + __block int objectix=0; + __block CFMutableArrayRef objectNames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + const size_t itemDataSize = 1024; + const int peerCount = 4; + const int edgeCount = peerCount * (peerCount - 1); + const int itemsPerPeer = 1000; + const int itemsPerIteration = 100; + const int itemChunkCount = (itemsPerPeer / itemsPerIteration); + const int deleteIteration = edgeCount * (itemChunkCount + 30); + const int idleIteration = 616; //deleteIteration + edgeCount * (itemChunkCount + 10); + + CFMutableDataRef itemData = CFDataCreateMutable(kCFAllocatorDefault, itemDataSize); + CFDataSetLength(itemData, itemDataSize); + + const char *name = "engine_views"; + //const char *test_directive + //const char *test_reason + CFIndex version = 0; + bool(^pre)(SOSTestDeviceRef source, SOSTestDeviceRef dest) = ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { + bool result = false; + if (iteration <= edgeCount * itemChunkCount) { + if (iteration % (peerCount - 1) == 0) { + for (int j = 0; j < itemsPerIteration; ++j) { + CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-pre-%d"), SOSTestDeviceGetID(source), objectix++); + CFArrayAppendValue(objectNames, name); + SOSTestDeviceAddGenericItemWithData(source, name, name, itemData); + CFReleaseNull(name); + } + } + result = true; + } else if (iteration == deleteIteration) { + //diag("deletion starting"); + } else if (deleteIteration < iteration && iteration <= deleteIteration + edgeCount * itemChunkCount) { + if (iteration % (peerCount - 1) == 0) { + for (int j = 0; j < itemsPerIteration; ++j) { + CFStringRef name = CFArrayGetValueAtIndex(objectNames, --objectix); + SOSTestDeviceAddGenericItemTombstone(source, name, name); + } + result = true; + } + } else if (idleIteration == iteration) { + //diag("idle starting"); + } else if (617 == iteration) { + //diag("interesting"); + } + iteration++; + return result || iteration < deleteIteration; + }; + bool(^post)(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) = ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { + return false; + }; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault, CFSTR("becks"), CFSTR("corona"), CFSTR("heineken"), CFSTR("spaten"), NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFMutableDictionaryRef testDevices = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + CFDictionarySetValue(testDevices, deviceID, device); + CFReleaseNull(device); + } + CFDictionarySetValue(testDevices, CFSTR("@devicesIDs"), deviceIDs); + CFReleaseNull(deviceIDs); + + SOSTestDeviceListSync(name, test_directive, test_reason, testDevices, pre, post); + SOSTestDeviceListInSync(name, test_directive, test_reason, testDevices); + SOSTestDeviceDestroyEngine(testDevices); + CFReleaseNull(testDevices); + + CFReleaseNull(views); + CFReleaseNull(objectNames); + CFReleaseNull(itemData); +} + +int secd_75_engine_views(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + /* custom keychain dir */ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + test_engine_views(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-76-idstransport.m b/keychain/securityd/Regressions/secd-76-idstransport.m new file mode 100644 index 00000000..164c56f0 --- /dev/null +++ b/keychain/securityd/Regressions/secd-76-idstransport.m @@ -0,0 +1,315 @@ +// +// secd-76-idstransport.c +// sec +// +// + +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include +#include "SecdTestKeychainUtilities.h" +#import "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" +#include +#include +#include "SOSTestDevice.h" + + + +static int kTestTestCount = 73; + +static void tests() +{ + CFErrorRef error = NULL; + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); + SOSAccountTrustClassic *aliceTrust = alice_account.trust; + SOSAccountTrustClassic *bobTrust = bob_account.trust; + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(NULL != alice_account, "Alice Created"); + ok(NULL != bob_account, "Bob Created"); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + //creating test devices + CFIndex version = 0; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFReleaseNull(views); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + + if(CFEqualSafe(deviceID, (__bridge CFTypeRef)(alice_account.peerID))){ + alice_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); + } + else{ + bob_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); + } + CFReleaseNull(device); + } + CFReleaseNull(deviceIDs); + CFReleaseNull(peerMetas); + + SOSUnregisterAllTransportMessages(); + CFArrayRemoveAllValues(message_transports); + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error]; + + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; + ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); + ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); + + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; + + ok(result, "Alice account update circle with transport type"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + result &= [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; + + ok(result, "Bob account update circle with transport type"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); + ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); + ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); + + CFReleaseNull(alice_transportType); + CFReleaseNull(bob_accountTransportType); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); + CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); + ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); + + ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); + CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); + ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("DSID"),&error), "Setting IDS device ID"); + CFStringRef dsid = SOSAccountCopyDeviceID(alice_account, &error); + ok(CFEqualSafe(dsid, CFSTR("DSID")), "Getting IDS device ID"); + CFReleaseNull(dsid); + + ok(SOSAccountStartPingTest(alice_account, CFSTR("hai there!"), &error), "Ping test"); + ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); + SOSTransportMessageIDSTestClearChanges((SOSMessageIDSTest*)alice_account.ids_message_transport); + + ok(SOSAccountSendIDSTestMessage(alice_account, CFSTR("hai again!"), &error), "Send Test Message"); + ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); + + CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); + CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII); + CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII); + + //test IDS message handling + CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] + == kHandleIDSMessageDontHandle, "sending empty message dictionary"); + + CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending device ID only"); + + CFReleaseNull(messageDict); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peer ID only"); + + CFReleaseNull(messageDict); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDataRef data = CFDataCreate(kCFAllocatorDefault, 0, 0); + CFDictionaryAddValue(messageDict, dataKey, data); + ok( [alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data only"); + + CFReleaseNull(messageDict); + CFReleaseNull(data); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + data = CFDataCreate(kCFAllocatorDefault, 0, 0); + CFDictionaryAddValue(messageDict, dataKey, data); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending data and peerid only"); + + CFReleaseNull(messageDict); + CFReleaseNull(data); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + data = CFDataCreate(kCFAllocatorDefault, 0, 0); + CFDictionaryAddValue(messageDict, dataKey, data); + CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data and deviceid only"); + + CFReleaseNull(messageDict); + CFReleaseNull(data); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peerid and deviceid only"); + + CFReleaseNull(messageDict); + CFReleaseNull(data); + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + data = CFDataCreate(kCFAllocatorDefault, 0, 0); + CFDictionaryAddValue(messageDict, dataKey, data); + CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, SOSPeerInfoGetPeerID(bob_account.peerInfo)); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); + + CFReleaseNull(messageDict); + CFReleaseNull(data); + + messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + data = CFDataCreate(kCFAllocatorDefault, 0, 0); + CFDictionaryAddValue(messageDict, dataKey, data); + CFStringRef BobDeviceID = SOSPeerInfoCopyDeviceID(bob_account.peerInfo); + CFDictionaryAddValue(messageDict, deviceIDKey, BobDeviceID); + CFReleaseNull(BobDeviceID); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); + + CFReleaseNull(data); + CFReleaseNull(dataKey); + CFReleaseNull(deviceIDKey); + CFReleaseNull(sendersPeerIDKey); + + CFReleaseNull(alice_dsid); + CFReleaseNull(bob_dsid); + CFReleaseNull(changes); + + SOSTestCleanup(); +} +int secd_76_idstransport(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-80-views-alwayson.m b/keychain/securityd/Regressions/secd-80-views-alwayson.m new file mode 100644 index 00000000..57bc8d44 --- /dev/null +++ b/keychain/securityd/Regressions/secd-80-views-alwayson.m @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// secd-80-views-alwayson.c +// Security +// +// +// + + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" + +#include "secd_regressions.h" +#include "SOSAccountTesting.h" +#include "SecdTestKeychainUtilities.h" + +static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { + CFErrorRef error = NULL; + SOSViewResultCode vcode = 9999; + switch(action) { + case kSOSCCViewQuery: + vcode = [account.trust viewStatus:account name:view err:&error]; + break; + case kSOSCCViewEnable: + case kSOSCCViewDisable: // fallthrough + vcode = [account.trust updateView:account name:view code:action err:&error]; + break; + default: + break; + } + is(vcode, expected, "%s (%@)", label, error); + CFReleaseNull(error); +} + +/* + Make a circle with two peers - alice and bob + Check for ContinuityUnlock View on Alice - it should be there + turn off ContinuityUnlock on Alice + Change the password with Bob - makeing Alice invalid + Update Alice with the new password + see that ContinuityUnlock is automatically back on because it's "always on" + */ + +static void alwaysOnTest() +{ + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfpasswordNew = CFDataCreate(NULL, (uint8_t *) "FooFooFo2", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + + // Start Circle + ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); + CFReleaseNull(cfpassword); + + testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); + testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewDisable, "Not expected to disable kSOSViewContinuityUnlock - it's always-on"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpasswordNew, NULL), "Bob changes the password"); + testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected kSOSViewContinuityUnlock is on for alice still"); + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpasswordNew, NULL), "Alice sets the new password"); + CFReleaseNull(cfpasswordNew); + testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); + + CFReleaseNull(changes); + + SOSTestCleanup(); +} + +int secd_80_views_alwayson(int argc, char *const *argv) +{ + plan_tests(35); + secd_test_clear_testviews(); + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + alwaysOnTest(); + return 0; +} diff --git a/keychain/securityd/Regressions/secd-80-views-basic.m b/keychain/securityd/Regressions/secd-80-views-basic.m new file mode 100644 index 00000000..db10961b --- /dev/null +++ b/keychain/securityd/Regressions/secd-80-views-basic.m @@ -0,0 +1,180 @@ +// +// secd-80-views-basic.c +// sec +// +// Created by Richard Murphy on 1/26/15. +// +// + +#include +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + + +#include +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSFullPeerInfo.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" + + +static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { + CFErrorRef error = NULL; + SOSViewResultCode vcode = 9999; + switch(action) { + case kSOSCCViewQuery: + vcode = [account.trust viewStatus:account name:view err:&error]; + break; + case kSOSCCViewEnable: + case kSOSCCViewDisable: // fallthrough + vcode = [account.trust updateView:account name:view code:action err:&error]; + break; + default: + break; + } + is(vcode, expected, "%s (%@)", label, error); + CFReleaseNull(error); +} + +static void testViewLists(void) { + CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); + CFSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault); + CFSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial); + CFSetRef alwaysOnViews = SOSViewCopyViewSet(kViewSetAlwaysOn); + CFSetRef backupRequiredViews = SOSViewCopyViewSet(kViewSetRequiredForBackup); + CFSetRef V0Views = SOSViewCopyViewSet(kViewSetV0); + + is(CFSetGetCount(allViews), 24, "make sure count of allViews is correct"); + is(CFSetGetCount(defaultViews), 20, "make sure count of defaultViews is correct"); + is(CFSetGetCount(initialViews), 0, "make sure count of initialViews is correct"); + is(CFSetGetCount(alwaysOnViews), 20, "make sure count of alwaysOnViews is correct"); + is(CFSetGetCount(backupRequiredViews), 3, "make sure count of backupRequiredViews is correct"); + is(CFSetGetCount(V0Views), 6, "make sure count of V0Views is correct"); + + CFReleaseNull(allViews); + CFReleaseNull(defaultViews); + CFReleaseNull(initialViews); + CFReleaseNull(alwaysOnViews); + CFReleaseNull(backupRequiredViews); + CFReleaseNull(V0Views); +} + +static int kTestTestCount = 38; +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFSetRef nullSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); + SOSDataSourceRef test_source = SOSTestDataSourceCreate(); + SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); + + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); + + ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + ok(SOSAccountJoinCircles_wTxn(account, &error), "Join circle: %@", error); + + ok(NULL != account, "Created"); + + ok(SOSAccountCheckHasBeenInSync_wTxn(account), "In sync already"); + + testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychain"); + // Default views no longer includes kSOSViewAppleTV + testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV"); + testView(account, kSOSCCViewMember, kSOSViewPCSPhotos, kSOSCCViewQuery, "Expected no view capability for kSOSViewPCSPhotos"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected no view capability for kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCNoSuchView, CFSTR("FOO"), kSOSCCViewQuery, "Expected no such view for FOO"); + + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewEnable, "Expected to enable kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewDisable, "Expected cannot disable kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); + + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewEnable, "Expected to enable kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewEnable, "Expected to enable kSOSViewKeychainV0"); + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewEnable, "Expected to enable kSOSViewAppleTV"); + + testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); + testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychainV0"); + testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV"); + + ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0"); + testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0"); + + ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0"); + testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0"); + + SOSPeerInfoRef pi = account.peerInfo; + ok(pi, "should have the peerInfo"); + SOSViewResultCode vr = SOSViewsEnable(pi, kSOSViewKeychainV0, NULL); + + ok(vr == kSOSCCViewMember, "Set Virtual View manually"); + + ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0"); + testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there"); + + ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0"); + testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there"); + + SOSDataSourceRelease(test_source, NULL); + SOSDataSourceFactoryRelease(test_factory); + + SOSTestCleanup(); +} + +int secd_80_views_basic(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + secd_test_clear_testviews(); + testViewLists(); + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-81-item-acl-stress.m b/keychain/securityd/Regressions/secd-81-item-acl-stress.m new file mode 100644 index 00000000..59d4d9a9 --- /dev/null +++ b/keychain/securityd/Regressions/secd-81-item-acl-stress.m @@ -0,0 +1,366 @@ +// +// si-81-item-acl.c +// sec +// +// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include + +#include "secd_regressions.h" + +#if USE_KEYSTORE +#include +#include "SecdTestKeychainUtilities.h" +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR +#include +#endif + +#endif + +enum ItemAttrType { + kBoolItemAttr, + kNumberItemAttr, + kStringItemAttr, + kDataItemAttr, + kBlobItemAttr, + kDateItemAttr, + kAccessabilityItemAttr, + kAccessGroupItemAttr, +}; + +extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); + +#if LA_CONTEXT_IMPLEMENTED +static keybag_handle_t test_keybag; +static const char *passcode = "password"; + +static bool changePasscode(const char *old_passcode, const char *new_passcode) +{ + size_t old_passcode_len = 0; + size_t new_passcode_len = 0; + + if (old_passcode) + old_passcode_len = strlen(old_passcode); + + if (new_passcode) + new_passcode_len = strlen(new_passcode); + + kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); + return status == 0; +} +#endif + +static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { + va_list ap; + va_start(ap, each); + CFStringRef attr; + while((attr = va_arg(ap, CFStringRef)) != NULL) { + enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); + each(attr, atype); + } + va_end(ap); +} + +static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { + CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); + if (!iclass) { + return; + } else if (CFEqual(iclass, kSecClassGenericPassword)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrAccount, kStringItemAttr, + kSecAttrService, kStringItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassInternetPassword)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrAccount, kStringItemAttr, + kSecAttrSecurityDomain, kStringItemAttr, + kSecAttrServer, kStringItemAttr, + kSecAttrProtocol, kNumberItemAttr, + kSecAttrAuthenticationType, kNumberItemAttr, + kSecAttrPort, kNumberItemAttr, + kSecAttrPath, kStringItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassCertificate)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrCertificateType, kNumberItemAttr, + kSecAttrIssuer, kDataItemAttr, + kSecAttrSerialNumber, kDataItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassKey)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies + kSecAttrApplicationLabel, kDataItemAttr, + kSecAttrApplicationTag, kDataItemAttr, + kSecAttrKeyType, kNumberItemAttr, + kSecAttrKeySizeInBits, kNumberItemAttr, + kSecAttrEffectiveKeySize, kNumberItemAttr, + kSecAttrStartDate, kDateItemAttr, + kSecAttrEndDate, kDateItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassIdentity)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrCertificateType, kNumberItemAttr, + kSecAttrIssuer, kDataItemAttr, + kSecAttrSerialNumber, kDataItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies + kSecAttrApplicationLabel, kDataItemAttr, + kSecAttrApplicationTag, kDataItemAttr, + kSecAttrKeyType, kNumberItemAttr, + kSecAttrKeySizeInBits, kNumberItemAttr, + kSecAttrEffectiveKeySize, kNumberItemAttr, + kSecAttrStartDate, kDateItemAttr, + kSecAttrEndDate, kDateItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } +} + +#if LA_CONTEXT_IMPLEMENTED +CF_RETURNS_RETAINED +static CFErrorRef createCFError(CFStringRef message, CFIndex code) +{ + const void* keysPtr[1]; + const void* messagesPtr[1]; + + keysPtr[0] = kCFErrorLocalizedDescriptionKey; + messagesPtr[0] = message; + return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, CFSTR(kLAErrorDomain), code, keysPtr, messagesPtr, 1); +} +#endif + +static void fillItem(CFMutableDictionaryRef item, uint32_t num) +{ + ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { + CFTypeRef value = NULL; + switch (atype) { + case kBoolItemAttr: + value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); + CFRetain(value); + break; + case kNumberItemAttr: + value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); + break; + case kStringItemAttr: + case kBlobItemAttr: + value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num); + break; + case kDataItemAttr: + { + char buf[50]; + int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num); + value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); + break; + } + case kDateItemAttr: + value = NULL; // Don't mess with dates on create. + break; + case kAccessabilityItemAttr: + { break; } + case kAccessGroupItemAttr: + { + CFStringRef accessGroups[] = { + NULL, + CFSTR("com.apple.security.sos"), // Secd internally uses this + }; + value = accessGroups[num % array_size(accessGroups)]; + break; + } + } + if (value) + CFDictionarySetValue(item, attr, value); + CFReleaseSafe(value); + }); + + CFDictionarySetValue(item, kSecValueData, (__bridge CFDataRef)[NSData dataWithBytes:"some data" length:9]); +} + +static void tests(bool isPasscodeSet) +{ + CFErrorRef (^okBlock)(void) = ^ { + return (CFErrorRef)NULL; + }; + +#if LA_CONTEXT_IMPLEMENTED + CFErrorRef (^errorNotInteractiveBlock)(void) = ^ { + return createCFError(CFSTR(""), kLAErrorNotInteractive); + }; +#endif + + CFArrayRef classArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecClassInternetPassword, kSecClassGenericPassword, kSecClassKey, kSecClassCertificate, NULL); + CFArrayRef protectionClassArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlwaysPrivate, + kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, + kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL); + + __block uint32_t pass = 0; + CFArrayForEach(classArray, ^(CFTypeRef itemClass) { + CFArrayForEach(protectionClassArray, ^(CFTypeRef protectionClass) { + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, itemClass, NULL); + fillItem(item, ++pass); + + LASetErrorCodeBlock(okBlock); + SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(aclRef, "Create SecAccessControlRef"); + ok(SecAccessControlSetProtection(aclRef, protectionClass, NULL), "Set protection"); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL), "Set operation decrypt to true"); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL), "Set operation delete to true"); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL), "Set operation encrypt to true"); + + LASetErrorCodeBlock(okBlock); + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); +#if LA_CONTEXT_IMPLEMENTED + ok_status(SecItemAdd(item, NULL), "add local "); + ok_status(SecItemCopyMatching(item, NULL), "find local"); + ok_status(SecItemDelete(item), "delete local"); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local"); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue); + is_status(SecItemAdd(item, NULL), errSecParam, "add sync"); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find sync"); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + + if(isPasscodeSet) { + SecAccessControlRef aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL); + ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction"); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef); + ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); + LASetErrorCodeBlock(errorNotInteractiveBlock); + is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI"); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "find local - acl with authentication UI"); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); + LASetErrorCodeBlock(okBlock); + ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI"); + + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); + ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); + LASetErrorCodeBlock(errorNotInteractiveBlock); + is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI"); + LASetErrorCodeBlock(okBlock); + ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI"); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); + + SecAccessControlRef aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL); + ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation"); + CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL); + ok(constraint); + ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete"); + CFReleaseSafe(constraint); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef); + ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); + LASetErrorCodeBlock(errorNotInteractiveBlock); + is_status(SecItemDelete(item), errSecInteractionNotAllowed, "delete local - acl with authentication UI"); + + if (CFEqual(protectionClass, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); + ok(changePasscode(passcode, NULL)); + LASetErrorCodeBlock(okBlock); + ok_status(SecItemDelete(item), "delete local - acl with authentication UI"); + ok(changePasscode(NULL, passcode)); + + CFReleaseSafe(aclWithUIRef); + CFReleaseSafe(aclWithDeleteConstraintRef); + + aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); + ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction"); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef); + ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); + changePasscode(passcode, NULL); + ok_status(SecItemDelete(item), "delete local - AKPU"); + changePasscode(NULL, passcode); + + aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); + ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation"); + constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL); + ok(constraint); + ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete"); + CFReleaseSafe(constraint); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef); + ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); + changePasscode(passcode, NULL); + ok_status(SecItemDelete(item), "delete local - AKPU + prot odel"); + changePasscode(NULL, passcode); + + CFReleaseNull(aclWithUIRef); + CFReleaseNull(aclWithDeleteConstraintRef); + } + CFReleaseNull(aclWithUIRef); + CFReleaseNull(aclWithDeleteConstraintRef); + } +#endif + CFReleaseNull(item); + CFReleaseNull(aclRef); + }); + }); + + CFRelease(classArray); + CFRelease(protectionClassArray); +} + +int secd_81_item_acl_stress(int argc, char *const *argv) +{ +#if LA_CONTEXT_IMPLEMENTED + secd_test_setup_temp_keychain(__FUNCTION__, ^{ + keybag_state_t state; + int passcode_len=(int)strlen(passcode); + + ok(kAKSReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &test_keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(test_keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(test_keybag); + }); + + bool isPasscodeSet = true; +#else + bool isPasscodeSet = false; +#endif + + plan_tests(isPasscodeSet?776:140); + + tests(isPasscodeSet); + +#if LA_CONTEXT_IMPLEMENTED + SecItemServerResetKeychainKeybag(); +#endif + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-81-item-acl.m b/keychain/securityd/Regressions/secd-81-item-acl.m new file mode 100644 index 00000000..30eddba5 --- /dev/null +++ b/keychain/securityd/Regressions/secd-81-item-acl.m @@ -0,0 +1,501 @@ +// +// si-81-item-acl.c +// sec +// +// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include + +#include "secd_regressions.h" + +#if USE_KEYSTORE +#include +#include +#include "SecdTestKeychainUtilities.h" + +#include "OSX/utilities/SecAKSWrappers.h" + +#if LA_CONTEXT_IMPLEMENTED +static keybag_handle_t test_keybag; +static const char *passcode1 = "passcode1"; +static const char *passcode2 = "passcode2"; + +static bool changePasscode(const char *old_passcode, const char *new_passcode) +{ + size_t old_passcode_len = 0; + size_t new_passcode_len = 0; + + if (old_passcode) + old_passcode_len = strlen(old_passcode); + + if (new_passcode) + new_passcode_len = strlen(new_passcode); + + kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); + return status == 0; +} + +#endif +#endif + + +enum ItemAttrType { + kBoolItemAttr, + kNumberItemAttr, + kStringItemAttr, + kDataItemAttr, + kBlobItemAttr, + kDateItemAttr, + kAccessabilityItemAttr, + kAccessGroupItemAttr, +}; + +extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void)); + +static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { + va_list ap; + va_start(ap, each); + CFStringRef attr; + while((attr = va_arg(ap, CFStringRef)) != NULL) { + enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); + each(attr, atype); + } + va_end(ap); +} + +static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { + CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); + if (!iclass) { + return; + } else if (CFEqual(iclass, kSecClassGenericPassword)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrAccount, kStringItemAttr, + kSecAttrService, kStringItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassInternetPassword)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrAccount, kStringItemAttr, + kSecAttrSecurityDomain, kStringItemAttr, + kSecAttrServer, kStringItemAttr, + kSecAttrProtocol, kNumberItemAttr, + kSecAttrAuthenticationType, kNumberItemAttr, + kSecAttrPort, kNumberItemAttr, + kSecAttrPath, kStringItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassCertificate)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrCertificateType, kNumberItemAttr, + kSecAttrIssuer, kDataItemAttr, + kSecAttrSerialNumber, kDataItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassKey)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies + kSecAttrApplicationLabel, kDataItemAttr, + kSecAttrApplicationTag, kDataItemAttr, + kSecAttrKeyType, kNumberItemAttr, + kSecAttrKeySizeInBits, kNumberItemAttr, + kSecAttrEffectiveKeySize, kNumberItemAttr, + kSecAttrStartDate, kDateItemAttr, + kSecAttrEndDate, kDateItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } else if (CFEqual(iclass, kSecClassIdentity)) { + WithEachString(each, + kSecAttrAccessible, kAccessabilityItemAttr, + kSecAttrAccessGroup, kAccessGroupItemAttr, + kSecAttrCertificateType, kNumberItemAttr, + kSecAttrIssuer, kDataItemAttr, + kSecAttrSerialNumber, kDataItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies + kSecAttrApplicationLabel, kDataItemAttr, + kSecAttrApplicationTag, kDataItemAttr, + kSecAttrKeyType, kNumberItemAttr, + kSecAttrKeySizeInBits, kNumberItemAttr, + kSecAttrEffectiveKeySize, kNumberItemAttr, + kSecAttrStartDate, kDateItemAttr, + kSecAttrEndDate, kDateItemAttr, + kSecAttrSynchronizable, kBoolItemAttr, + NULL); + } +} + +static void fillItem(CFMutableDictionaryRef item, uint32_t num) +{ + ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { + CFTypeRef value = NULL; + switch (atype) { + case kBoolItemAttr: + value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); + CFRetain(value); + break; + case kNumberItemAttr: + value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); + break; + case kStringItemAttr: + case kBlobItemAttr: + value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num); + break; + case kDataItemAttr: + { + char buf[50]; + int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num); + value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); + break; + } + case kDateItemAttr: + value = NULL; // Don't mess with dates on create. + break; + case kAccessabilityItemAttr: + { break; } + case kAccessGroupItemAttr: + { + CFStringRef accessGroups[] = { + NULL, + CFSTR("com.apple.security.sos"), // Secd internally uses this + }; + value = accessGroups[num % array_size(accessGroups)]; + break; + } + } + if (value) + CFDictionarySetValue(item, attr, value); + CFReleaseSafe(value); + }); + + CFDictionarySetValue(item, kSecValueData, (__bridge CFDataRef)[NSData dataWithBytes:"some data" length:9]); +} + +#if LA_CONTEXT_IMPLEMENTED +CF_RETURNS_RETAINED +static CFErrorRef createCFError(CFStringRef message, CFIndex code) +{ + const void* keysPtr[1]; + const void* messagesPtr[1]; + + keysPtr[0] = kCFErrorLocalizedDescriptionKey; + messagesPtr[0] = message; + return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, CFSTR(kLAErrorDomain), code, keysPtr, messagesPtr, 1); +} + +#if TARGET_OS_IPHONE +static void set_app_password(ACMContextRef acmContext) +{ + CFDataRef appPwdData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("Application password"), kCFStringEncodingUTF8, 0); + ACMCredentialRef acmCredential = NULL; + ok_status(ACMCredentialCreate(kACMCredentialTypePassphraseEntered, &acmCredential), "Create ACM credential"); + ACMPassphrasePurpose purpose = kACMPassphrasePurposeGeneral; + ok_status(ACMCredentialSetProperty(acmCredential, kACMCredentialPropertyPassphrase, CFDataGetBytePtr(appPwdData), CFDataGetLength(appPwdData)), "Set ACM credential property - passphrase"); + ok_status(ACMCredentialSetProperty(acmCredential, kACMCredentialPropertyPassphrasePurpose, &purpose, sizeof(purpose)), "Set ACM credential property - purpose"); + ok_status(ACMContextAddCredentialWithScope(acmContext, acmCredential, kACMScopeContext), "aad ACM credential to ACM context"); + ACMCredentialDelete(acmCredential); + CFReleaseSafe(appPwdData); +} +#endif + +static void item_with_application_password(uint32_t *item_num) +{ +#if TARGET_OS_IPHONE + CFErrorRef (^okBlock)(void) = ^ { + return (CFErrorRef)NULL; + }; + + CFErrorRef (^authFailedBlock)(void) = ^ { + return createCFError(CFSTR(""), kLAErrorAuthenticationFailed); + }; + + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); + fillItem(item, (*item_num)++); + + LASetErrorCodeBlock(okBlock); + SecAccessControlRef aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlApplicationPassword, NULL); + ok(aclRef, "Create SecAccessControlRef"); + + ACMContextRef acmContext = NULL; + ok_status(ACMContextCreate(&acmContext), "Create ACM context"); + set_app_password(acmContext); + + __block CFDataRef credRefData = NULL; + ACMContextGetExternalForm(acmContext, ^(const void *externalForm, size_t dataBufferLength) { + credRefData = CFDataCreate(kCFAllocatorDefault, externalForm, dataBufferLength); + }); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + ok_status(SecItemAdd(item, NULL), "add local - acl with application password"); + ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password"); + ok_status(SecItemDelete(item), "delete local - acl with application password"); + + CFReleaseSafe(aclRef); + + LASetErrorCodeBlock(okBlock); + aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); + SecAccessControlSetRequirePassword(aclRef, true); + ok(aclRef, "Create SecAccessControlRef"); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); + ok_status(SecItemAdd(item, NULL), "add local - acl with application password and user present"); + LASetErrorCodeBlock(authFailedBlock); + CFDictionarySetValue(item, kSecReturnData, kCFBooleanTrue); + is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password and user present"); + CFDictionaryRemoveValue(item, kSecReturnData); + LASetErrorCodeBlock(okBlock); + set_app_password(acmContext); + ok_status(SecItemDelete(item), "delete local - acl with application password and user present"); + CFReleaseSafe(aclRef); + + LASetErrorCodeBlock(okBlock); + aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); + SecAccessControlSetRequirePassword(aclRef, true); + SecAccessConstraintRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR(kACMPolicyDeviceOwnerAuthentication), NULL); + SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, constraint, NULL); + CFRelease(constraint); + ok(aclRef, "Create SecAccessControlRef"); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + ok_status(SecItemAdd(item, NULL), "add local - acl with application password and user present"); + LASetErrorCodeBlock(authFailedBlock); + is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password and user present"); + set_app_password(acmContext); + is_status(SecItemDelete(item), errSecAuthFailed, "delete local - acl with application password and user present"); + + CFRelease(item); + CFReleaseSafe(aclRef); + + // Update tests for item with application password: + + // Prepare query for item without ACL. + item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); + fillItem(item, (*item_num)++); + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + + // Add test item without ACL and check that it can be found. + ok_status(SecItemAdd(item, NULL), "add local - no acl"); + ok_status(SecItemCopyMatching(item, NULL), "find local - no acl"); + + // Update test item by adding ACL with application password flag. + CFMutableDictionaryRef update = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAlwaysPrivate, kSecAccessControlApplicationPassword, NULL); + CFDictionarySetValue(update, kSecAttrAccessControl, aclRef); + set_app_password(acmContext); + CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); + LASetErrorCodeBlock(okBlock); + ok_status(SecItemUpdate(item, update), "update local - acl with application password"); + + LASetErrorCodeBlock(authFailedBlock); + ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password"); + CFDictionaryRemoveValue(item, kSecUseCredentialReference); + is_status(SecItemCopyMatching(item, NULL), errSecAuthFailed, "find local - acl with application password (without ACM context)"); + CFDictionarySetValue(item, kSecUseCredentialReference, credRefData); + ok_status(SecItemCopyMatching(item, NULL), "find local - acl with application password (with ACM context)"); + + // Try to update item with ACL with application password with the same password (it will fail because ACM context is not allowd for update attributes). + CFDictionarySetValue(update, kSecUseCredentialReference, credRefData); + LASetErrorCodeBlock(okBlock); + is_status(SecItemUpdate(item, update), errSecNoSuchAttr, "update local - add application password"); + + CFDictionaryRemoveValue(update, kSecUseCredentialReference); + LASetErrorCodeBlock(okBlock); + ok_status(SecItemUpdate(item, update), "update local - updated with the same application password"); + LASetErrorCodeBlock(authFailedBlock); + ok_status(SecItemCopyMatching(item, NULL), "find local - updated with the same application password"); // LA authFailedBlock is not called. + + CFReleaseSafe(aclRef); + // Update item with ACL without application password. + aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAlwaysPrivate, 0, NULL); + CFDictionarySetValue(update, kSecAttrAccessControl, aclRef); + + LASetErrorCodeBlock(okBlock); + ok_status(SecItemUpdate(item, update), "update local - remove application password"); + + CFDictionaryRemoveValue(item, kSecUseCredentialReference); + LASetErrorCodeBlock(authFailedBlock); + ok_status(SecItemCopyMatching(item, NULL), "find local - acl without application password"); // LA authFailedBlock is not called. + + ok_status(SecItemDelete(item), "delete local - acl without application password"); + + CFRelease(update); + CFRelease(item); + CFReleaseSafe(aclRef); + + ACMContextDelete(acmContext, true); + CFReleaseSafe(credRefData); +#endif +} + +static void item_with_invalid_acl(uint32_t *item_num) +{ + CFErrorRef (^errorParamBlock)(void) = ^ { + return createCFError(CFSTR(""), kLAErrorParameter); + }; + + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); + fillItem(item, (*item_num)++); + + SecAccessControlRef invalidAclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(invalidAclRef, "Create invalid SecAccessControlRef"); + ok(SecAccessControlSetProtection(invalidAclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL), "Set protection"); + CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("invalidPolicy"), NULL); + ok(constraint, "Create invalid constraint"); + ok(SecAccessControlAddConstraintForOperation(invalidAclRef, kAKSKeyOpDecrypt, constraint, NULL), "Add invalid constraint"); + CFReleaseSafe(constraint); + + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + CFDictionarySetValue(item, kSecAttrAccessControl, invalidAclRef); + + LASetErrorCodeBlock(errorParamBlock); + is_status(SecItemAdd(item, NULL), errSecParam, "do not add local with invalid acl"); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after add failed"); + + CFReleaseSafe(invalidAclRef); + CFRelease(item); +} + +static void item_with_acl_caused_maxauth(uint32_t *item_num) +{ + CFErrorRef (^okBlock)(void) = ^ { + return (CFErrorRef)NULL; + }; + + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); + fillItem(item, (*item_num)++); + + SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(aclRef, "Create SecAccessControlRef"); + ok(SecAccessControlSetProtection(aclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL)); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrpyt, kCFBooleanFalse, NULL)); + + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + + __security_simulatecrash_enable(false); + + LASetErrorCodeBlock(okBlock); + diag("this will cause an internal assert - on purpose"); + is_status(SecItemAdd(item, NULL), errSecAuthFailed, "max auth attempts failed"); + + is(__security_simulatecrash_enable(true), 1, "Expecting simcrash max auth threshold passed"); + + CFReleaseSafe(aclRef); + CFRelease(item); +} + +static void item_with_akpu(uint32_t *item_num) +{ + CFErrorRef (^okBlock)(void) = ^ { + return (CFErrorRef)NULL; + }; + + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassGenericPassword, NULL); + fillItem(item, (*item_num)++); + + SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL); + ok(aclRef, "Create SecAccessControlRef"); + ok(SecAccessControlSetProtection(aclRef, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL)); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrpyt, kCFBooleanTrue, NULL)); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL)); + ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL)); + + CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse); + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + + LASetErrorCodeBlock(okBlock); + ok_status(SecItemAdd(item, NULL), "add item with akpu"); + ok_status(SecItemCopyMatching(item, NULL), "find item with akpu"); + changePasscode(passcode1, NULL); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); + is_status(SecItemAdd(item, NULL), errSecNotAvailable, "cannot add item with akpu without passcode"); + changePasscode(NULL, passcode2); + is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); + ok_status(SecItemAdd(item, NULL), "add item with akpu"); + + changePasscode(passcode2, passcode1); + CFReleaseSafe(aclRef); + CFRelease(item); +} +#endif + +static void item_with_skip_auth_ui(uint32_t *item_num) +{ + CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL); + fillItem(item, (*item_num)++); + + SecAccessControlRef aclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlDevicePasscode, NULL); + ok(aclRef, "Create SecAccessControlRef"); + + CFDictionarySetValue(item, kSecAttrAccessControl, aclRef); + CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip); + is_status(SecItemAdd(item, NULL), errSecParam, "add local - invalid kSecUseAuthenticationUISkip"); + is_status(SecItemDelete(item), errSecParam, "delete local - invalid kSecUseAuthenticationUISkip"); + + CFReleaseNull(aclRef); + CFRelease(item); +} + +int secd_81_item_acl(int argc, char *const *argv) +{ + uint32_t item_num = 1; +#if LA_CONTEXT_IMPLEMENTED + secd_test_setup_temp_keychain(__FUNCTION__, ^{ + keybag_state_t state; + int passcode_len=(int)strlen(passcode1); + + ok(kAKSReturnSuccess==aks_create_bag(passcode1, passcode_len, kAppleKeyStoreDeviceBag, &test_keybag), "create keybag"); + ok(kAKSReturnSuccess==aks_get_lock_state(test_keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(test_keybag); + }); +#if TARGET_OS_IPHONE + plan_tests(70); +#else + plan_tests(29); +#endif + item_with_skip_auth_ui(&item_num); + item_with_invalid_acl(&item_num); + item_with_application_password(&item_num); + item_with_acl_caused_maxauth(&item_num); + item_with_akpu(&item_num); +#else + plan_tests(3); + item_with_skip_auth_ui(&item_num); +#endif + +#if LA_CONTEXT_IMPLEMENTED + SecItemServerResetKeychainKeybag(); +#endif + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-82-persistent-ref.m b/keychain/securityd/Regressions/secd-82-persistent-ref.m new file mode 100644 index 00000000..3d033767 --- /dev/null +++ b/keychain/securityd/Regressions/secd-82-persistent-ref.m @@ -0,0 +1,72 @@ +// +// secd-82-persistent-ref.c +// sec +// +// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. +// +// + +#include +#include +#include + +#include "secd_regressions.h" +#include "SecdTestKeychainUtilities.h" + +int secd_82_persistent_ref(int argc, char *const *argv) +{ + plan_tests(5); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_82_persistent_ref", NULL); + + CFMutableDictionaryRef attrs = NULL; + CFMutableDictionaryRef query = NULL; + CFDataRef data = NULL; + CFTypeRef result = NULL; + CFArrayRef array = NULL; + CFIndex i, n; + CFDictionaryRef item = NULL; + + attrs = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); + CFDictionarySetValue( attrs, kSecClass, kSecClassGenericPassword ); + CFDictionarySetValue( attrs, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate ); + CFDictionarySetValue( attrs, kSecAttrLabel, CFSTR( "TestLabel" ) ); + CFDictionarySetValue( attrs, kSecAttrDescription, CFSTR( "TestDescription" ) ); + CFDictionarySetValue( attrs, kSecAttrAccount, CFSTR( "TestAccount" ) ); + CFDictionarySetValue( attrs, kSecAttrService, CFSTR( "TestService" ) ); + data = CFDataCreate( NULL, (const uint8_t *) "\x00\x01\x02", 3 ); + CFDictionarySetValue( attrs, kSecValueData, data ); + CFReleaseNull( data ); + + is(SecItemAdd(attrs, NULL), errSecSuccess); + CFReleaseNull( attrs ); + + query = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); + CFDictionarySetValue( query, kSecClass, kSecClassGenericPassword ); + CFDictionarySetValue( query, kSecAttrSynchronizable, kSecAttrSynchronizableAny );; + CFDictionarySetValue( query, kSecAttrAccount, CFSTR( "TestAccount" ) ); + CFDictionarySetValue( query, kSecReturnAttributes, kCFBooleanTrue ); + CFDictionarySetValue( query, kSecReturnPersistentRef, kCFBooleanTrue ); + CFDictionarySetValue( query, kSecMatchLimit, kSecMatchLimitAll ); + + is(SecItemCopyMatching(query, &result), errSecSuccess); + CFReleaseNull( query ); + array = (CFArrayRef) result; + + SKIP: { + skip("No results from SecItemCopyMatching", 2, array && (CFArrayGetTypeID() == CFGetTypeID(array))); + n = CFArrayGetCount( array ); + is(n, 1); + for( i = 0; i < n; ++i ) + { + item = (CFDictionaryRef) CFArrayGetValueAtIndex(array, i); + + ok((CFDataRef) CFDictionaryGetValue(item, kSecValuePersistentRef)); + } + } + CFReleaseNull( result ); + + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-83-item-match-policy.m b/keychain/securityd/Regressions/secd-83-item-match-policy.m new file mode 100644 index 00000000..76040252 --- /dev/null +++ b/keychain/securityd/Regressions/secd-83-item-match-policy.m @@ -0,0 +1,234 @@ +// +// secd-81-item-match-policy.m +// sec + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + +#import +#import +#import +#import +#import + + +#import "secd_regressions.h" +#import "SecdTestKeychainUtilities.h" +#import "secd-83-item-match.h" + +//Test SSL SMIME2 +NSString *secdTestSMIME1BASE64String = @"MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMTELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MUBhcHBsZS5jb20wHhcNMTYwNDA3MDYzNDM0WhcNMTcwNDA3MDYzNDM0WjBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMTELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MUBhcHBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHedMsbVecoqyZwoTTE85bm3QImVz45HYFGKq/L6E5dVPamiiMRZ2BX1XnIdthbIRZhg7OU0zk2KiQKyg+bjnk+l3ZW/C6N3sAx4blq/UemOg6XtdI1Iq/HwLw5qJW8hiy9INA2nMJnSXZrnM6Ezsj92l0PQ2+8oOa95sLfi2e9NJZONESY/XNyc6tclaUYHSQR+BAzllKRorrqvpa3T2o6lmcUG+29TsRUHth6OHZLccMoA6ITk8Eq/vlAsaH4BnD7rFfBwcE/GhkkbZrmH1xaFziEIwMx3uvhsQCpspt50Pf9RWcsj3/bD4aIPUNLRkyn49ZE6MhOmMp7p5UCXapAgMBAAGjSjBIMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAeBgNVHREEFzAVgRN0ZXN0Y2VydDFAYXBwbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAm3pbBBqrzR3tTwZrjLORH72PY3f/4IvhYNadP3A70Smln0xC+BIjxqTPP1YXcvwY2PfIaNkXrxaqM8/mbR5MjiDQ7SZz5jfYTuJP6+Z9Y9nL2S/62DyhVwJcRskrDCArkaXz1b2n6yEWCw4L5uJmwdRruW5D7mF10f2GtNvGlq5Wj7csKjw6Pwh8kgG3lnGqrWaNfiJku49lbAugZr2bryQvzxi3q0Kk0LBlxVt1fMae/H/cO9nwlqe+mOclJ96zRPWnXKNMduDf00OIp131gqAknXQwSJZoI2mvX9deFdaaS21T1COhvPN+dL7D5umX85NGzoLN2svzihAhMkIK+"; +//Test SSL SMIME2 +NSString *secdTestSMIME2BASE64String = @"MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMjELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MkBhcHBsZS5jb20wHhcNMTYwNDA3MDYzNjUzWhcNMTcwNDA3MDYzNjUzWjBHMRQwEgYDVQQDDAtUZXN0IFNNSU1FMjELMAkGA1UEBhMCQ1oxIjAgBgkqhkiG9w0BCQEWE3Rlc3RjZXJ0MkBhcHBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk4emo4RNYI7WXtdOjFBgxIaLf80zTH0peza4PMJO7fC+KtStC4KpvRWbIhm+CcvJjpT4jpScKuHisMgfPxfEcK7jv8kRU7waAaW3H5o56YBX+Qen+fA18ulrwwzEHO4KBK7kXT9oSLy1m09u17yf46x3NPshrg0JpTh4F1jPtEK7HPZnzoJMx8i69Rd9zfddm+Gs0TPFtqaUQ9wuKeKr/Vda9kaPo98UabpiXx94sy/rtlULiUY8Nh993KUDcGPI2LTmQSeR8EB37AEoeBm8mRR9IGdZNvkDPEXIoilw1HVMsczxCEVV0HOAcFh+HfvVsWGYySentCpOe95r4/CSbAgMBAAGjSjBIMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAeBgNVHREEFzAVgRN0ZXN0Y2VydDJAYXBwbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAAVic5KfpUoy7Bu8dZ8qc+1RM/wXscK/2906/ZD7cndFSM2X7x+oRB78mtbmHlvfDC5FC5OAlxpY9S5ITtK/R67wi6LwOK3TkoQzevSqAkl8ylTfh3Sp/bwCRpVJo1yFCBdNnq4clEktu2+W6YSczjrDieN6CvhRE+AQ3sYNpxeaRJUS8PtNdPmYNnPdLK9VLB8Fg2WIHTAYV1nvai8Dvj1Fk6ukJGQxLJmXs6qUT8O+VE0CiVI5wspX+XSO/FSXiYLzFsLSRQNdWOO6U0zJlVpa1UoiRZCiVHnkDcYAMKB66hNUvRPtZYAguH7Ipg5bSld6fr8b43Vt2lkDM1iZAK"; +//Test SSL client1 +NSString *secdTestSSLClient1BASE64String = @"MIIDPTCCAiWgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBMMRkwFwYDVQQDDBBUZXN0IFNTTCBjbGllbnQxMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQzQGFwcGxlLmNvbTAeFw0xNjA0MDcwNjM5NDBaFw0xNzA0MDcwNjM5NDBaMEwxGTAXBgNVBAMMEFRlc3QgU1NMIGNsaWVudDExCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDNAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKF0N/zPBmahsQwcSrCqiUavXVLj5DEVricqEmOPd77Zr3CVf4B/zDEFqyLh2cg15WBlYV0hG8TDa49yOlJ8JZ8d58n/0A0p6Qq27/S1qc7DvpwVqSwwUl5S3DXSrVBxnJKz20Q3f2yNnHv3hJvp7dMI4C+rQK/uSy2syJalTSVUXMLjQegfv3EVBVTL8omb4Myo7HbjYhEUw/faM9NXwUNs0foR2cRvpkqJPi7r6gM/a+4T2SlSst0U+ByPgaFy2QJPPuzQSEa7vA5fmsMDSQ7BHnla1YVjloWh4LHdB32BGmjIwyHYfn5hqKl37V+oASqLeWVD1cK/2dG6nl2AmQIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEIs0r+XYOl2Tt1dcRVgTXoFT8w4xAJ7JeErhBqEbhPnQ4i/7GGnd20wL3keCLeLvIJm+KOI+OMjLft276MGn6VEN33o8GKt53m0Mz/mS36xdmAdxBu0t1dh2bnBRYh+asD2gz3AFnlUDOC5DqRZ5yz0FwK9UPpN6KqBZc0YbzS/p/cc3UkzywdAX01RTzmxqGgrl5CPruIECRSieykl7fgmqitlLnYms/QvaS963cFvIM6XJdXltbED6GkVc39ab/lXFYfkSC4Wx2LGeP5NEBqeEfLpKHFOuNVo6dks8OGXXfW14jhCRaLJi6P3kh9jfTXAvW8Fw0mGoNciTLPKTK4="; +//Test SSL client2 +NSString *secdTestSSLClient2BASE64String = @"MIIDPTCCAiWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBMMRkwFwYDVQQDDBBUZXN0IFNTTCBjbGllbnQyMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ0QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQxMDFaFw0xNzA0MDcwNjQxMDFaMEwxGTAXBgNVBAMMEFRlc3QgU1NMIGNsaWVudDIxCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDRAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAneZGoEDMw7ZdqT5jVA+omajFDixAd9HB5kaw1kUxd6MuFTn95WhLyI84oa8FvmbxGXZ2zBxtZF3hrm2xHPJB0bwpCfzR0GlaoZKbgUzvRx8x+i/+tEkbFnlOlmU1ZW7cGWyu6bI60rfPZ5VwEe6/JgFaKTRdOACxzIaYDJhS2S2LSzgrom27k424LbCWtfwaqEuiPtF3hGmuCAfrdxJ9Pr/qBcKCjkbWdrtIYhsEJzN8oLwdLduy8jM+fiAXwW1skEgIQa7Bo4zJRIsT6fG0U/0HeSESxGfghN3dBCaWGM7yB1Cahrk8pfalhs5IFmFhNy/+UtpBYhO1DGbr4ijfHQIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAFrDD3o6uG8lU1NxLa+i0zSihFDv0b3y516AScUAf6jpuW0Wfhpqb/U1Gk91Zo2ZBFtQ5WniLf4wGZRFeeUOv6PTHdkBz7PtYa/nzyXOlUBdTuZ0w52e2+mEJfCpwhR7MVBvs3QmtXpg7H/lSePbbun/tl8fYRMzcycLWH9Yrz+TluNdS9/Qa3SRgXo4JUKGl8F/nvXohuz2JyGLk43l3Cq9z68IKv7c8SA448E9d+MwwsYc2YcHf9aZAwu81aP5c3XOSaWvP3uzATxb/w6tIhs7O8iHgyq7mRy2iQqACDxpcILKGEu4advaBPmB14kSz/HUS4VahafayXxhCQPqYtc="; +//secdtest1.apple.com +NSString *secdTestSSLServer1BASE64String = @"MIIDYzCCAkugAwIBAgIBBTANBgkqhkiG9w0BAQsFADBPMRwwGgYDVQQDDBNzZWNkdGVzdDEuYXBwbGUuY29tMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ1QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQ3MThaFw0xNzA0MDcwNjQ3MThaME8xHDAaBgNVBAMME3NlY2R0ZXN0MS5hcHBsZS5jb20xCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDVAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxWOhlJjFJ+Fyp0KRCb4Dx20TMf+/gYaNwN9/i0+YNi3wb5mAepO7gN8VoZhYf+fWO6eUGzxFwggCK5b2plZ5dW/3su5B/K5onYxE7wWPsHGfw/rolpkp84fgj2aSUBQnOuwhFvot1dmFUeh55SaIv56sLw5aIbW/xWP6Mhc8kpf8ji5xpFA5JZxmbBZi4iG4E4395DD3lXE1jN4B3aY6gknnA6BYvngvxH/2whitKTDKCqsnWPxGqbJ5kg+0julkgYVEPlfdus/MNTB/c6llKiqIkwNuzPPaHq9VRNnPctEljVJcch7ZwqbluTY+AwRGXuY0RpJ9S6+uEPaQbuDX3QIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwHgYDVR0RBBcwFYITc2VjZHRlc3QxLmFwcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAfJqxsLI03nm9YSVeOqcyOB+Cj41WmNCgaSvftGmPtmz4QLbEYTYDqrv2zTvTtmS5Z1ugy6XeA4sUx9j9oKJq9+FRkfxQTDOHz7e8dqUvF0ToLPRo0dlGv55FsbVgOM8vKCeqra12FWvSUHXhUn7tC+lQDDiDs5st4NkVRgRsCYHUIfYtYBWABd5Z6kWAR33qysxbxx4cHLGb/1CCfsPF+/IQYS1sF9u+q/Jvbe6Oylyb1qxoe4dcsub4AYgS+yHItcQeZksItwYWLdAQUat7r6bbMLp+EN2DJRzrIQl+Kf3nzSKRBW6HTJR19+6D/pum0q8A0A3chsMW34rvMS469w=="; +//secdtest2.apple.com +NSString *secdTestSSLServer2BASE64String = @"MIIDYzCCAkugAwIBAgIBBjANBgkqhkiG9w0BAQsFADBPMRwwGgYDVQQDDBNzZWNkdGVzdDIuYXBwbGUuY29tMQswCQYDVQQGEwJDWjEiMCAGCSqGSIb3DQEJARYTdGVzdGNlcnQ2QGFwcGxlLmNvbTAeFw0xNjA0MDcwNjQ1NTFaFw0xNzA0MDcwNjQ1NTFaME8xHDAaBgNVBAMME3NlY2R0ZXN0Mi5hcHBsZS5jb20xCzAJBgNVBAYTAkNaMSIwIAYJKoZIhvcNAQkBFhN0ZXN0Y2VydDZAYXBwbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmI95AUYia7UATWdqAUHQGge1vK11u5CXuQm0rpvKMTwzSD/HkEX6jFnCoJ4J+3FUpeY70ZhWfnwiumGmMB6RfI3S2jIWvyrMgIRkiPhiLh5ZDmV6K/w2MVzOEiPRKPVcxgLJm8CF2/EdJnCMmJG8pvWyTwahW43WT7oAj5KdnqSCtysEZ5pOKR+U4S89x0mUuGXc6K3xVWSfM0Az2tepWc11dtuLWPSe5vCU3JuZzFfXsUqgHInWnBNjPfQrgI9LE5EIqslA5dAZLLlr4+OLCmENi6qwQ6GIvzR9S30gAk4Mo/H+RUeqqimkMD8JUL9D72FQdqcC1cFgsADbxslLgwIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwHgYDVR0RBBcwFYITc2VjZHRlc3QyLmFwcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAC3BDk+HtpO+FKmgx0BfNz4gXR3NjDoe0Ms2toC2YAzR33Z/VycBjLbQ0gfQHyGHYQPYzGgurYPypyzUqKJJVFClmj/VXaNANiFhegHPXRKPyFuw5wbxKE2tgCq3sJ+x4RbDoyGXZz+7bfvWbjynpgiXWWx1V1ABop1UByiYTWp7zVDLTEzYfVGkisr0sV3qoMrKxYBgjUJjXM6p5DeIFr8HaB6lSSqSlCek3oMBfgjEIurpU3LhcGeOn2ItFS8F3wj1YqLvxzgzn3LfPjUOENXI+Fy8lPgibiEeqAcT7//NwleuNQfYL5eGVzuAxcNG9b1NeDkG5t1RQgUL5JwP8bg=="; + +void addTestCertificates(void) { + NSData *certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSMIME1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + SecCertificateRef certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); + + certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSMIME2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); + + certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLClient1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); + + certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLClient2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); + + certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLServer1BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); + + certDerData = [[NSData alloc] initWithBase64EncodedString:secdTestSSLServer2BASE64String options:NSDataBase64DecodingIgnoreUnknownCharacters]; + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certDerData); + ok_status(SecItemAdd((__bridge CFDictionaryRef) @{ (id)kSecValueRef : (__bridge id) certRef }, NULL), "Add tet certificate"); + CFRelease(certRef); +} + +static void test(id returnKeyName) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"]; + [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"us_EN"]]; + NSDate *validDate = [dateFormatter dateFromString: @"2016-04-07 16:00:00 GMT"]; + NSDate *dateBefore = [dateFormatter dateFromString: @"2016-04-06 16:00:00 GMT"]; + NSDate *dateAfter = [dateFormatter dateFromString: @"2017-04-08 16:00:00 GMT"]; + + CFTypeRef result = NULL; + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 6); + CFReleaseNull(result); +#if TARGET_OS_IPHONE + SecPolicyRef policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, NULL); +#else + SecPolicyRef policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES }); +#endif + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 2); + CFReleaseNull(policy); + CFReleaseNull(result); + +#if TARGET_OS_IPHONE + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ +#else + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, +#endif + (id)kSecPolicyName : @"testcert1@apple.com" }); + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 1); + CFReleaseNull(result); + + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 1); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateBefore, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateAfter, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(policy); + CFReleaseNull(result); +#if TARGET_OS_IPHONE + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, NULL); +#else + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES }); +#endif + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 2); + CFReleaseNull(policy); + CFReleaseNull(result); + +#if TARGET_OS_IPHONE + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ +#else + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, +#endif + (id)kSecPolicyName : @"secdtest1.apple.com" }); + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 1); + CFReleaseNull(result); + + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 1); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateBefore, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateAfter, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(policy); + CFReleaseNull(result); + +#if TARGET_OS_IPHONE + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ +#else + policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)@{ (id)kSecPolicyKU_DigitalSignature : @YES, +#endif + (id)kSecPolicyClient : @YES }); + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 2); + CFReleaseNull(result); + + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 2); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateBefore, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : dateAfter, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(policy); + CFReleaseNull(result); +} + +int secd_83_item_match_policy(int argc, char *const *argv) +{ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + plan_tests(103); + + @autoreleasepool { + addTestCertificates(); + NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; + for (id returnKeyName in returnKeyNames) + test(returnKeyName); + } + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-83-item-match-trusted.m b/keychain/securityd/Regressions/secd-83-item-match-trusted.m new file mode 100644 index 00000000..0231610b --- /dev/null +++ b/keychain/securityd/Regressions/secd-83-item-match-trusted.m @@ -0,0 +1,51 @@ +// +// secd-83-item-match-trusted.m +// sec + + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + +#import +#import +#import +#import + + +#import "secd_regressions.h" +#import "SecdTestKeychainUtilities.h" +#import "secd-83-item-match.h" + +static void test(id returnKeyName) { + CFTypeRef result = NULL; + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 6); + CFReleaseNull(result); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchTrustedOnly : @YES, + returnKeyName : @YES }, &result), errSecItemNotFound); + CFReleaseNull(result); +} + +int secd_83_item_match_trusted(int argc, char *const *argv) +{ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + plan_tests(19); + + @autoreleasepool { + addTestCertificates(); + NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; + for (id returnKeyName in returnKeyNames) + test(returnKeyName); + } + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-83-item-match-valid-on-date.m b/keychain/securityd/Regressions/secd-83-item-match-valid-on-date.m new file mode 100644 index 00000000..7922de7a --- /dev/null +++ b/keychain/securityd/Regressions/secd-83-item-match-valid-on-date.m @@ -0,0 +1,68 @@ +// +// secd-83-item-match-valid-on-date.m +// sec + +/* + * This is to fool os services to not provide the Keychain manager + * interface tht doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + +#import +#import +#import +#import + + +#import "secd_regressions.h" +#import "SecdTestKeychainUtilities.h" +#import "secd-83-item-match.h" + +static void test(id returnKeyName) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"]; + [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"us_EN"]]; + NSDate *validDate = [dateFormatter dateFromString: @"2016-04-07 16:00:00 GMT"]; + NSDate *dateBefore = [dateFormatter dateFromString: @"2016-04-06 16:00:00 GMT"]; + NSDate *dateAfter = [dateFormatter dateFromString: @"2017-04-08 16:00:00 GMT"]; + + CFTypeRef result = NULL; + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 6); + CFReleaseNull(result); + + ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchValidOnDate : validDate, + returnKeyName : @YES }, &result)); + ok(result && CFArrayGetCount(result) == 6); + + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchValidOnDate : dateBefore, + returnKeyName : @YES }, &result), errSecItemNotFound); + ok(result && CFArrayGetCount(result) == 6); + is_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchValidOnDate : dateAfter, + returnKeyName : @YES }, &result), errSecItemNotFound); + ok(result && CFArrayGetCount(result) == 6); +} + +int secd_83_item_match_valid_on_date(int argc, char *const *argv) +{ + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + plan_tests(39); + + @autoreleasepool { + addTestCertificates(); + NSArray *returnKeyNames = @[(id)kSecReturnAttributes, (id)kSecReturnData, (id)kSecReturnRef, (id)kSecReturnPersistentRef]; + for (id returnKeyName in returnKeyNames) + test(returnKeyName); + } + + return 0; +} diff --git a/keychain/securityd/Regressions/secd-83-item-match.h b/keychain/securityd/Regressions/secd-83-item-match.h new file mode 100644 index 00000000..cae87a88 --- /dev/null +++ b/keychain/securityd/Regressions/secd-83-item-match.h @@ -0,0 +1,10 @@ +// +// secd-83-item-match.h +// sec + +#ifndef secd_83_item_match_h +#define secd_83_item_match_h + +void addTestCertificates(void); + +#endif /* secd_83_item_match_h */ diff --git a/keychain/securityd/Regressions/secd-95-escrow-persistence.m b/keychain/securityd/Regressions/secd-95-escrow-persistence.m new file mode 100644 index 00000000..80c23aea --- /dev/null +++ b/keychain/securityd/Regressions/secd-95-escrow-persistence.m @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static void tests(void) +{ + CFErrorRef error = NULL; + + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); + CFReleaseNull(error); + CFReleaseSafe(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); + + withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { + CFStringAppend(timeDescription, decription); + }); + CFStringAppend(timeDescription, CFSTR("]")); + + int tries = 5; + + CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &tries); + + CFMutableArrayRef escrowTimeAndTries = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayAppendValue(escrowTimeAndTries, timeDescription); + CFArrayAppendValue(escrowTimeAndTries, attempts); + CFDictionaryRef escrowRecord = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("account label"), escrowTimeAndTries, NULL); + + CFMutableDictionaryRef record = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(record, CFSTR("12345"), escrowRecord); + + SOSFullPeerInfoRef alice_fpi = alice_account.fullPeerInfo; + ok(SOSFullPeerInfoAddEscrowRecord(alice_fpi, CFSTR("12345"), escrowRecord, &error), "Adding Escrow records to Alice FPI(%@)", error); + CFDictionaryRef fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(alice_fpi)); + ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Alice's FPI has escrow (%@)", error); + + ok(SOSAccountAddEscrowRecords(bob_account, CFSTR("12345"), escrowRecord, &error), "Adding escrow to Bob's account (%@)", error); + CFReleaseNull(fpi_escrow); + + fpi_escrow = (CFDictionaryRef)SOSAccountGetValue(bob_account, kSOSEscrowRecord, NULL); + ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset to offering (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + ok(SOSAccountHasPublicKey(bob_account, &error), "Has Public Key" ); + + ok([bob_account.trust resetAccountToEmpty:bob_account transport:bob_account.circle_transport err:&error], "Reset to offering (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountAddEscrowRecords(bob_account, CFSTR("12345"), escrowRecord, &error), "Adding escrow to Bob's account (%@)", error); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + SOSAccountTrustClassic *bobTrust = bob_account.trust; + CFDictionaryRef bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); + ok(bob_fpi_escrow == NULL, "Bob's FPI escrow should be null"); + CFReleaseNull(bob_fpi_escrow); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); + ok(bob_fpi_escrow && CFEqualSafe(CFDictionaryGetValue(bob_fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); + CFReleaseNull(bob_fpi_escrow); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicants %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Accept bob into the fold"); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + fpi_escrow = (CFDictionaryRef)SOSAccountGetValue(bob_account, kSOSEscrowRecord, NULL); + ok(isNull(fpi_escrow), "Bob's escrow records in the account object should be gone"); + + CFReleaseNull(record); + CFReleaseNull(escrowRecord); + CFReleaseNull(timeDescription); + CFReleaseNull(attempts); + SOSTestCleanup(); + +} + +int secd_95_escrow_persistence(int argc, char *const *argv) +{ + plan_tests(41); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd60-account-cloud-exposure.m b/keychain/securityd/Regressions/secd60-account-cloud-exposure.m new file mode 100644 index 00000000..a9979d44 --- /dev/null +++ b/keychain/securityd/Regressions/secd60-account-cloud-exposure.m @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// secd60-account-cloud-exposure.c +// sec +// + + + +#include +#include + +#include + +#include "keychain/SecureObjectSync/SOSAccount.h" +#include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" +#include +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static bool SOSAccountResetCircleToNastyOffering(SOSAccount* account, SecKeyRef userPriv, SOSPeerInfoRef pi, CFErrorRef *error) { + bool result = false; + SecKeyRef userPub = SecKeyCreatePublicFromPrivate(userPriv); + SOSAccountTrustClassic *trust = account.trust; + if(!SOSAccountHasCircle(account, error)){ + CFReleaseNull(userPub); + return result; + } + if(![account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error]){ + CFReleaseNull(userPub); + return result; + } + (void) [account.trust resetAllRings:account err:error]; + + [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { + bool result = false; + CFErrorRef localError = NULL; + SOSFullPeerInfoRef iCloudfpi = NULL; + + //sleep(10); + require_quiet(SOSCircleResetToEmpty(circle, error), err_out); + require_quiet([account.trust addiCloudIdentity:circle key:userPriv err:error], err_out); + require_quiet(iCloudfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, error), err_out); + + /* Add the defenders peerInfo to circle */ + require_quiet(SOSCircleRequestReadmission(circle, userPub, pi, error), err_out); + require_quiet(SOSCircleAcceptRequest(circle, userPriv, iCloudfpi, pi, error), err_out); + + [trust setDepartureCode:kSOSNeverLeftCircle]; + result = true; + SOSCircleRef copiedCircle = SOSCircleCopyCircle(kCFAllocatorDefault, circle, error); // I don't think this copy is necessary, but... + [trust setTrustedCircle:copiedCircle]; + CFReleaseNull(copiedCircle); + SOSAccountPublishCloudParameters(account, NULL); + trust.fullPeerInfo = nil; + + err_out: + if (result == false) { + secerror("error resetting circle (%@) to offering: %@", circle, localError); + } + if (localError && error && *error == NULL) { + *error = localError; + localError = NULL; + } + + CFReleaseNull(iCloudfpi); + CFReleaseNull(localError); + return result; + }]; + + result = true; + + return result; +} + +static bool SOSAccountResetToNastyOffering(SOSAccount* account, SOSPeerInfoRef pi, CFErrorRef* error) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); + if (!user_key) + return false; + + SOSAccountTrustClassic* trust = account.trust; + trust.fullPeerInfo = nil; + + return user_key && SOSAccountResetCircleToNastyOffering(account, user_key, pi, error); +} + +static bool performiCloudIdentityAttack(SOSAccount* attacker, SOSAccount* defender, SOSAccount* accomplice, CFMutableDictionaryRef changes) { + CFErrorRef error = NULL; + bool retval = false; // false means the attack succeeds + CFArrayRef applicants = NULL; + SOSAccountTrustClassic* defenderTrust = defender.trust; + + /*----- Carole makes bogus circle with fake iCloud identity and Alice's peerInfo but only signed with fake iCloud identity -----*/ + + require_action_quiet(SOSAccountResetToNastyOffering(attacker, defenderTrust.peerInfo, &error), testDone, retval = true); + CFReleaseNull(error); + + ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); + + /*----- Now use our fake iCloud identity to get in to the circle for real -----*/ + require_action_quiet(SOSAccountJoinCirclesAfterRestore_wTxn(attacker, &error), testDone, retval = true); + CFReleaseNull(error); + require_action_quiet(countPeers(attacker) == 2, testDone, retval = true); + + /*----- Let's see if carole can get bob into the circle and have alice believe it -----*/ + require_action_quiet(SOSAccountJoinCircles_wTxn(accomplice, &error), testDone, retval = true); + CFReleaseNull(error); + + ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); + + applicants = SOSAccountCopyApplicants(attacker, &error); + CFReleaseNull(error); + + if(CFArrayGetCount(applicants) > 0) { + require_action_quiet(SOSAccountAcceptApplicants(attacker, applicants, &error), testDone, retval = true); + } + + ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); + + require_action_quiet(countPeers(defender) == 3, testDone, retval = true); + require_action_quiet(countPeers(accomplice) == 3, testDone, retval = true); + require_action_quiet(countPeers(attacker) == 3, testDone, retval = true); + +testDone: + CFReleaseNull(applicants); + CFReleaseNull(error); + return retval; +} + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + + ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + + ok(performiCloudIdentityAttack(carole_account, alice_account, bob_account, changes), "Attack is defeated"); + + CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); +} + +int secd_60_account_cloud_exposure(int argc, char *const *argv) +{ + plan_tests(41); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd_77_ids_messaging.m b/keychain/securityd/Regressions/secd_77_ids_messaging.m new file mode 100644 index 00000000..a23cdabb --- /dev/null +++ b/keychain/securityd/Regressions/secd_77_ids_messaging.m @@ -0,0 +1,296 @@ +// +// secd_77_ids_messaging.c +// sec +// + +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include + +#include +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" +#include "SOSTestDevice.h" +#include "SOSTestDataSource.h" +#include +#include + +static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { + SOSAccountTrustClassic* trust = account.trust; + SOSPeerInfoRef mypi = trust.peerInfo; + CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); + + return myPeerID && CFEqualSafe(myPeerID, peerID); +} + +__unused static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){ + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + __block bool SyncingCompletedOverIDS = false; + __block CFErrorRef localError = NULL; + __block bool done = false; + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + + do{ + SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + ok(SyncingCompletedOverIDS, "synced items over IDS"); + if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)bob_account.ids_message_transport)) == 0){ + done = true; + break; + } + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + }while(done == false); + CFReleaseNull(changes); +} + +static void tests() +{ + CFErrorRef error = NULL; + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef dsName = CFSTR("Test"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), dsName); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), dsName); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(NULL != alice_account, "Alice Created"); + ok(NULL != bob_account, "Bob Created"); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + //creating test devices + CFIndex version = 0; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFReleaseNull(views); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + + if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ + alice_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); + } + else{ + bob_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); + } + + CFReleaseNull(device); + } + CFReleaseNull(deviceIDs); + CFReleaseNull(peerMetas); + + SOSUnregisterAllTransportMessages(); + CFArrayRemoveAllValues(message_transports); + + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error ]; + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; + + ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); + ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); + + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; + + ok(result, "Alice account update circle with transport type"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; + + ok(result, "Bob account update circle with transport type"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); + ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); + ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); + + CFReleaseNull(alice_transportType); + CFReleaseNull(bob_accountTransportType); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + + ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); + CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); + ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); + + ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); + CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); + ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + + ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); + + ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); + + + //ids_test_sync(alice_account, bob_account); + + CFReleaseNull(bob_dsid); + CFReleaseNull(alice_dsid); + CFReleaseNull(changes); + + SOSTestCleanup(); +} + +int secd_77_ids_messaging(int argc, char *const *argv) +{ + plan_tests(100); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/keychain/securityd/Regressions/secd_regressions.h b/keychain/securityd/Regressions/secd_regressions.h new file mode 100644 index 00000000..d3de4a06 --- /dev/null +++ b/keychain/securityd/Regressions/secd_regressions.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include "OSX/sec/Security/SecItemShim.h" + +ONE_TEST(secd_01_items) +ONE_TEST(secd_02_upgrade_while_locked) +ONE_TEST(secd_03_corrupted_items) +DISABLED_ONE_TEST(secd_04_corrupted_items) +ONE_TEST(secd_05_corrupted_items) +ONE_TEST(secd_20_keychain_upgrade) +ONE_TEST(secd_21_transmogrify) +DISABLED_ONE_TEST(secd_30_keychain_upgrade) //obsolete, needs updating +DISABLED_ONE_TEST(secd_31_keychain_unreadable) +OFF_ONE_TEST(secd_32_restore_bad_backup) +ONE_TEST(secd_33_keychain_ctk) +ONE_TEST(secd_33_keychain_backup) +ONE_TEST(secd_35_keychain_migrate_inet) +ONE_TEST(secd_36_ks_encrypt) +ONE_TEST(secd_37_pairing_initial_sync) +ONE_TEST(secd_40_cc_gestalt) +ONE_TEST(secd_50_account) +ONE_TEST(secd_49_manifests) +ONE_TEST(secd_50_message) +ONE_TEST(secd_51_account_inflate) +ONE_TEST(secd_52_account_changed) +ONE_TEST(secd_52_offering_gencount_reset) +DISABLED_ONE_TEST(secd_55_account_circle) +ONE_TEST(secd_55_account_incompatibility) +ONE_TEST(secd_56_account_apply) +ONE_TEST(secd_57_account_leave) +ONE_TEST(secd_57_1_account_last_standing) +ONE_TEST(secd_58_password_change) +ONE_TEST(secd_59_account_cleanup) +ONE_TEST(secd_60_account_cloud_identity) +ONE_TEST(secd_60_account_cloud_exposure) +ONE_TEST(secd_61_account_leave_not_in_kansas_anymore) +ONE_TEST(secd_62_account_backup) +ONE_TEST(secd_63_account_resurrection) +ONE_TEST(secd_64_circlereset) +ONE_TEST(secd_65_account_retirement_reset) +ONE_TEST(secd_66_account_recovery) +ONE_TEST(secd_67_prefixedKeyIDs) +ONE_TEST(secd_70_engine) +ONE_TEST(secd_70_engine_corrupt) +ONE_TEST(secd_70_engine_smash) +ONE_TEST(secd_71_engine_save) +ONE_TEST(secd_68_ghosts) +ONE_TEST(secd_155_otr_negotiation_monitor) + +DISABLED_ONE_TEST(secd_70_otr_remote) +ONE_TEST(secd_74_engine_beer_servers) +OFF_ONE_TEST(secd_75_engine_views) +ONE_TEST(secd_80_views_basic) +ONE_TEST(secd_80_views_alwayson) +#if TARGET_IPHONE_SIMULATOR +OFF_ONE_TEST(secd_81_item_acl_stress) +OFF_ONE_TEST(secd_81_item_acl) +#else +ONE_TEST(secd_81_item_acl_stress) +ONE_TEST(secd_81_item_acl) +#endif +ONE_TEST(secd_82_persistent_ref) +ONE_TEST(secd_83_item_match_policy) +ONE_TEST(secd_83_item_match_valid_on_date) +ONE_TEST(secd_83_item_match_trusted) +ONE_TEST(secd_95_escrow_persistence) +ONE_TEST(secd_154_engine_backoff) +ONE_TEST(secd_100_initialsync) +ONE_TEST(secd_130_other_peer_views) +ONE_TEST(secd_156_timers) +ONE_TEST(secd_200_logstate) +ONE_TEST(secd_201_coders) +ONE_TEST(secd_202_recoverykey) +ONE_TEST(secd_210_keyinterest) +DISABLED_ONE_TEST(secd_230_keybagtable) +#if TARGET_OS_OSX +ONE_TEST(sc_25_soskeygen) +#endif + diff --git a/keychain/securityd/Regressions/securityd_regressions.h b/keychain/securityd/Regressions/securityd_regressions.h new file mode 100644 index 00000000..0135bbb8 --- /dev/null +++ b/keychain/securityd/Regressions/securityd_regressions.h @@ -0,0 +1,7 @@ +/* To add a test: + 1) add it here + 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes + */ +#include + +ONE_TEST(sd_10_policytree) diff --git a/keychain/securityd/SFKeychainControlManager.h b/keychain/securityd/SFKeychainControlManager.h new file mode 100644 index 00000000..52f06c67 --- /dev/null +++ b/keychain/securityd/SFKeychainControlManager.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +XPC_RETURNS_RETAINED _Nullable xpc_endpoint_t SecServerCreateKeychainControlEndpoint(void); + +#ifdef __OBJC__ + +#import "SFKeychainControl.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SFKeychainControlManager : NSObject + ++ (instancetype)sharedManager; + +- (NSArray*)findCorruptedItemsWithError:(NSError**)error; +- (bool)deleteCorruptedItemsWithError:(NSError**)error; + +- (nullable xpc_endpoint_t)xpcControlEndpoint; + +NS_ASSUME_NONNULL_END + +@end + +#endif diff --git a/keychain/securityd/SFKeychainControlManager.m b/keychain/securityd/SFKeychainControlManager.m new file mode 100644 index 00000000..89e1ae5c --- /dev/null +++ b/keychain/securityd/SFKeychainControlManager.m @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SFKeychainControlManager.h" +#import "SecCFError.h" +#import "builtin_commands.h" +#import "debugging.h" +#import +#import +#import + +NSString* kSecEntitlementKeychainControl = @"com.apple.private.keychain.keychaincontrol"; + +XPC_RETURNS_RETAINED xpc_endpoint_t SecServerCreateKeychainControlEndpoint(void) +{ + return [[SFKeychainControlManager sharedManager] xpcControlEndpoint]; +} + +@implementation SFKeychainControlManager { + NSXPCListener* _listener; +} + ++ (instancetype)sharedManager +{ + static SFKeychainControlManager* manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[SFKeychainControlManager alloc] _init]; + }); + + return manager; +} + +- (instancetype)_init +{ + if (self = [super init]) { + _listener = [NSXPCListener anonymousListener]; + _listener.delegate = self; + [_listener resume]; + } + + return self; +} + +- (xpc_endpoint_t)xpcControlEndpoint +{ + return [_listener.endpoint _endpoint]; +} + +- (BOOL)listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection +{ + NSNumber* entitlementValue = [newConnection valueForEntitlement:kSecEntitlementKeychainControl]; + if (![entitlementValue isKindOfClass:[NSNumber class]] || !entitlementValue.boolValue) { + secerror("SFKeychainControl: Client pid (%d) doesn't have entitlement: %@", newConnection.processIdentifier, kSecEntitlementKeychainControl); + return NO; + } + + NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainControl)]; + [interface setClass:[NSError class] forSelector:@selector(rpcFindCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES]; + [interface setClass:[NSError class] forSelector:@selector(rpcDeleteCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES]; + newConnection.exportedInterface = interface; + newConnection.exportedObject = self; + [newConnection resume]; + return YES; +} + +- (NSArray*)findCorruptedItemsWithError:(NSError**)error +{ + NSMutableArray* corruptedItems = [[NSMutableArray alloc] init]; + NSMutableArray* underlyingErrors = [[NSMutableArray alloc] init]; + + CFTypeRef genericPasswords = NULL; + NSDictionary* genericPasswordsQuery = @{ (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecReturnPersistentRef : @(YES), + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecMatchLimit : (id)kSecMatchLimitAll }; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordsQuery, &genericPasswords); + CFErrorRef genericPasswordError = NULL; + if (status != errSecItemNotFound) { + SecError(status, &genericPasswordError, CFSTR("generic password query failed")); + if (genericPasswordError) { + [underlyingErrors addObject:CFBridgingRelease(genericPasswordError)]; + } + } + + CFTypeRef internetPasswords = NULL; + NSDictionary* internetPasswordsQuery = @{ (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecReturnPersistentRef : @(YES), + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecMatchLimit : (id)kSecMatchLimitAll }; + status = SecItemCopyMatching((__bridge CFDictionaryRef)internetPasswordsQuery, &internetPasswords); + CFErrorRef internetPasswordError = NULL; + if (status != errSecItemNotFound) { + SecError(status, &internetPasswordError, CFSTR("internet password query failed")); + if (internetPasswordError) { + [underlyingErrors addObject:CFBridgingRelease(internetPasswordError)]; + } + } + + CFTypeRef keys = NULL; + NSDictionary* keysQuery = @{ (id)kSecClass : (id)kSecClassKey, + (id)kSecReturnPersistentRef : @(YES), + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecMatchLimit : (id)kSecMatchLimitAll }; + status = SecItemCopyMatching((__bridge CFDictionaryRef)keysQuery, &keys); + CFErrorRef keyError = NULL; + if (status != errSecItemNotFound) { + if (keyError) { + [underlyingErrors addObject:CFBridgingRelease(keyError)]; + } + } + + CFTypeRef certificates = NULL; + NSDictionary* certificateQuery = @{ (id)kSecClass : (id)kSecClassCertificate, + (id)kSecReturnPersistentRef : @(YES), + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecMatchLimit : (id)kSecMatchLimitAll }; + status = SecItemCopyMatching((__bridge CFDictionaryRef)certificateQuery, &certificates); + CFErrorRef certificateError = NULL; + if (status != errSecItemNotFound) { + SecError(status, &certificateError, CFSTR("certificate query failed")); + if (certificateError) { + [underlyingErrors addObject:CFBridgingRelease(certificateError)]; + } + } + + void (^scanArrayForCorruptedItem)(CFTypeRef, NSString*) = ^(CFTypeRef items, NSString* class) { + if ([(__bridge NSArray*)items isKindOfClass:[NSArray class]]) { + NSLog(@"scanning %d %@", (int)CFArrayGetCount(items), class); + for (NSData* persistentRef in (__bridge NSArray*)items) { + NSDictionary* itemQuery = @{ (id)kSecClass : class, + (id)kSecValuePersistentRef : persistentRef, + (id)kSecReturnAttributes : @(YES), + (id)kSecUseDataProtectionKeychain : @(YES) }; + CFTypeRef itemAttributes = NULL; + OSStatus copyStatus = SecItemCopyMatching((__bridge CFDictionaryRef)itemQuery, &itemAttributes); + if (copyStatus != errSecSuccess && status != errSecInteractionNotAllowed) { + [corruptedItems addObject:itemQuery]; + } + } + } + }; + + scanArrayForCorruptedItem(genericPasswords, (id)kSecClassGenericPassword); + scanArrayForCorruptedItem(internetPasswords, (id)kSecClassInternetPassword); + scanArrayForCorruptedItem(keys, (id)kSecClassKey); + scanArrayForCorruptedItem(certificates, (id)kSecClassCertificate); + + if (underlyingErrors.count > 0 && error) { + *error = [NSError errorWithDomain:@"com.apple.security.keychainhealth" code:1 userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"encountered %d errors searching for corrupted items", (int)underlyingErrors.count], NSUnderlyingErrorKey : underlyingErrors.firstObject, @"searchingErrorCount" : @(underlyingErrors.count) }]; + } + + return corruptedItems; +} + +- (bool)deleteCorruptedItemsWithError:(NSError**)error +{ + NSError* findError = nil; + NSArray* corruptedItems = [self findCorruptedItemsWithError:&findError]; + bool success = findError == nil; + + NSMutableArray* deleteErrors = [[NSMutableArray alloc] init]; + for (NSDictionary* corruptedItem in corruptedItems) { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)corruptedItem); + if (status != errSecSuccess) { + success = false; + CFErrorRef deleteError = NULL; + SecError(status, &deleteError, CFSTR("failed to delete corrupted item")); + [deleteErrors addObject:CFBridgingRelease(deleteError)]; + } + } + + if (error && (findError || deleteErrors.count > 0)) { + *error = [NSError errorWithDomain:@"com.apple.security.keychainhealth" code:2 userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"encountered %@ errors searching for corrupted items and %d errors attempting to delete corrupted items", findError.userInfo[@"searchingErrorCount"], (int)deleteErrors.count]}]; + } + + return success; +} + +- (void)rpcFindCorruptedItemsWithReply:(void (^)(NSArray* corruptedItems, NSError* error))reply +{ + NSError* error = nil; + NSArray* corruptedItems = [self findCorruptedItemsWithError:&error]; + reply(corruptedItems, error); +} + +- (void)rpcDeleteCorruptedItemsWithReply:(void (^)(bool success, NSError* error))reply +{ + NSError* error = nil; + bool success = [self deleteCorruptedItemsWithError:&error]; + reply(success, error); +} + +@end diff --git a/keychain/securityd/SFKeychainServer.h b/keychain/securityd/SFKeychainServer.h new file mode 100644 index 00000000..771384cb --- /dev/null +++ b/keychain/securityd/SFKeychainServer.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import + +#define kSFKeychainServerServiceName "com.apple.security.sfkeychainserver" + +#if !TARGET_OS_BRIDGE && __OBJC2__ + +#import +#import +#import "SecCDKeychain.h" + +@interface SFKeychainServer : NSObject + +- (instancetype)initWithStorageURL:(NSURL*)persistentStoreURL modelURL:(NSURL*)managedObjectURL encryptDatabase:(bool)encryptDatabase; + +@end + +@interface SecCDKeychainItemTypeCredential : SecCDKeychainItemType +@end + +@interface SFKeychainServerConnection : NSObject + +@property (readonly) NSArray* clientAccessGroups; + +@end + +#endif // !TARGET_OS_BRIDGE && __OBJC2__ + +void SFKeychainServerInitialize(void); diff --git a/keychain/securityd/SFKeychainServer.m b/keychain/securityd/SFKeychainServer.m new file mode 100644 index 00000000..fb9c07b2 --- /dev/null +++ b/keychain/securityd/SFKeychainServer.m @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SFKeychainServer.h" +#import + +#if !TARGET_OS_BRIDGE +#if __OBJC2__ + +#import "SecCDKeychain.h" +#import "SecFileLocations.h" +#import "debugging.h" +#import "CloudKitCategories.h" +#import "SecAKSWrappers.h" +#include "securityd_client.h" +#import "server_entitlement_helpers.h" +#import "SecTask.h" +#import "keychain/categories/NSError+UsefulConstructors.h" +#import "SecEntitlements.h" +#import +#import +#import +#import +#import + +static NSString* const SFKeychainItemAttributeLocalizedLabel = @"label"; +static NSString* const SFKeychainItemAttributeLocalizedDescription = @"description"; + +static NSString* const SFCredentialAttributeUsername = @"username"; +static NSString* const SFCredentialAttributePrimaryServiceIdentifier = @"primaryServiceID"; +static NSString* const SFCredentialAttributeSupplementaryServiceIdentifiers = @"supplementaryServiceIDs"; +static NSString* const SFCredentialAttributeCreationDate = @"creationDate"; +static NSString* const SFCredentialAttributeModificationDate = @"modificationDate"; +static NSString* const SFCredentialAttributeCustom = @"customAttributes"; +static NSString* const SFCredentialSecretPassword = @"password"; + +@interface SFCredential (securityd_only) + +- (instancetype)_initWithUsername:(NSString*)username primaryServiceIdentifier:(SFServiceIdentifier*)primaryServiceIdentifier supplementaryServiceIdentifiers:(nullable NSArray*)supplementaryServiceIdentifiers; + +@end + +@interface SFKeychainServerConnection () + +- (instancetype)initWithKeychain:(SecCDKeychain*)keychain xpcConnection:(NSXPCConnection*)connection; + +@end + +@implementation SecCDKeychainItemTypeCredential + ++ (instancetype)itemType +{ + static SecCDKeychainItemTypeCredential* itemType = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + itemType = [[self alloc] _initWithName:@"Credential" version:1 primaryKeys:@[SFCredentialAttributeUsername, SFCredentialAttributePrimaryServiceIdentifier] syncableKeys:nil]; + }); + + return itemType; +} + +@end + +@implementation SFKeychainServer { + SecCDKeychain* _keychain; +} + +- (instancetype)initWithStorageURL:(NSURL*)persistentStoreURL modelURL:(NSURL*)managedObjectURL encryptDatabase:(bool)encryptDatabase +{ + if (self = [super init]) { + _keychain = [[SecCDKeychain alloc] initWithStorageURL:persistentStoreURL modelURL:managedObjectURL encryptDatabase:encryptDatabase]; + } + + return self; +} + +- (BOOL)listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection +{ + NSNumber* keychainDenyEntitlement = [newConnection valueForEntitlement:(__bridge NSString*)kSecEntitlementKeychainDeny]; + if ([keychainDenyEntitlement isKindOfClass:[NSNumber class]] && keychainDenyEntitlement.boolValue == YES) { + secerror("SFKeychainServer: connection denied due to entitlement %@", kSecEntitlementKeychainDeny); + return NO; + } + + // wait a bit for shared function from SecurityFoundation to get to SDK, then addopt that + NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainServerProtocol)]; + [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFServiceIdentifier class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:NO]; + [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFPasswordCredential class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:YES]; + newConnection.exportedInterface = interface; + newConnection.exportedObject = [[SFKeychainServerConnection alloc] initWithKeychain:_keychain xpcConnection:newConnection]; + [newConnection resume]; + return YES; +} + +- (SecCDKeychain*)_keychain +{ + return _keychain; +} + +@end + +@implementation SFKeychainServerConnection { + SecCDKeychain* _keychain; + NSArray* _clientAccessGroups; +} + +@synthesize clientAccessGroups = _clientAccessGroups; + +- (instancetype)initWithKeychain:(SecCDKeychain*)keychain xpcConnection:(NSXPCConnection*)connection +{ + if (self = [super init]) { + _keychain = keychain; + + SecTaskRef task = SecTaskCreateWithAuditToken(NULL, connection.auditToken); + if (task) { + _clientAccessGroups = (__bridge_transfer NSArray*)SecTaskCopyAccessGroups(task); + } + CFReleaseNull(task); + } + + return self; +} + +- (keyclass_t)keyclassForAccessPolicy:(SFAccessPolicy*)accessPolicy +{ + if (accessPolicy.accessibility.mode == SFAccessibleAfterFirstUnlock) { + if (accessPolicy.sharingPolicy == SFSharingPolicyThisDeviceOnly) { + return key_class_cku; + } + else { + return key_class_ck; + } + } + else { + if (accessPolicy.sharingPolicy == SFSharingPolicyThisDeviceOnly) { + return key_class_aku; + } + else { + return key_class_ak; + } + } +} + +- (void)rpcAddCredential:(SFCredential*)credential withAccessPolicy:(SFAccessPolicy*)accessPolicy reply:(void (^)(NSString* persistentIdentifier, NSError* error))reply +{ + if (![credential isKindOfClass:[SFPasswordCredential class]]) { + reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidParameter userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"attempt to add credential to SFCredentialStore that is not a password credential: %@", credential]}]); + return; + } + + NSString* accessGroup = accessPolicy.accessGroup; + if (!accessGroup) { + NSError* error = nil; + accessGroup = self.clientAccessGroups.firstObject; + if (!accessGroup) { + error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorMissingAccessGroup userInfo:@{NSLocalizedDescriptionKey : @"no keychain access group found; ensure that your process has the keychain-access-groups entitlement"}]; + reply(nil, error); + return; + } + } + + SFPasswordCredential* passwordCredential = (SFPasswordCredential*)credential; + + NSError* error = nil; + NSData* primaryServiceIdentifierData = [NSKeyedArchiver archivedDataWithRootObject:passwordCredential.primaryServiceIdentifier requiringSecureCoding:YES error:&error]; + if (!primaryServiceIdentifierData) { + dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSaveFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to serialize primary service identifier", NSUnderlyingErrorKey : error }]); + }); + return; + } + + NSMutableArray* serializedSupplementaryServiceIdentifiers = [[NSMutableArray alloc] initWithCapacity:passwordCredential.supplementaryServiceIdentifiers.count]; + for (SFServiceIdentifier* serviceIdentifier in passwordCredential.supplementaryServiceIdentifiers) { + NSData* serviceIdentifierData = [NSKeyedArchiver archivedDataWithRootObject:serviceIdentifier requiringSecureCoding:YES error:&error]; + if (serviceIdentifierData) { + [serializedSupplementaryServiceIdentifiers addObject:serviceIdentifierData]; + } + else { + dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + reply(nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSaveFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to serialize supplementary service identifier", NSUnderlyingErrorKey : error }]); + }); + return; + } + } + + NSDictionary* attributes = @{ SFCredentialAttributeUsername : passwordCredential.username, + SFCredentialAttributePrimaryServiceIdentifier : primaryServiceIdentifierData, + SFCredentialAttributeSupplementaryServiceIdentifiers : serializedSupplementaryServiceIdentifiers, + SFCredentialAttributeCreationDate : [NSDate date], + SFCredentialAttributeModificationDate : [NSDate date], + SFKeychainItemAttributeLocalizedLabel : passwordCredential.localizedLabel, + SFKeychainItemAttributeLocalizedDescription : passwordCredential.localizedDescription, + SFCredentialAttributeCustom : passwordCredential.customAttributes ?: [NSDictionary dictionary] }; + + NSDictionary* secrets = @{ SFCredentialSecretPassword : passwordCredential.password }; + NSUUID* persistentID = [NSUUID UUID]; + + // lookup attributes: + // 1. primaryServiceIdentifier (always) + // 2. username (always) + // 3. label (if present) + // 4. description (if present) + // 5. each of the service identifiers by type, e.g. "domain" + // 6. any custom attributes that fit the requirements (key is string, and value is plist type) + + SecCDKeychainLookupTuple* primaryServiceIdentifierLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFCredentialAttributePrimaryServiceIdentifier value:primaryServiceIdentifierData]; + SecCDKeychainLookupTuple* usernameLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFCredentialAttributeUsername value:passwordCredential.username]; + SecCDKeychainLookupTuple* labelLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFKeychainItemAttributeLocalizedLabel value:passwordCredential.localizedLabel]; + SecCDKeychainLookupTuple* descriptionLookup = [SecCDKeychainLookupTuple lookupTupleWithKey:SFKeychainItemAttributeLocalizedDescription value:passwordCredential.localizedDescription]; + NSMutableArray* lookupAttributes = [[NSMutableArray alloc] initWithObjects:primaryServiceIdentifierLookup, usernameLookup, nil]; + if (labelLookup) { + [lookupAttributes addObject:labelLookup]; + } + if (descriptionLookup) { + [lookupAttributes addObject:descriptionLookup]; + } + + SFServiceIdentifier* primaryServiceIdentifier = credential.primaryServiceIdentifier; + [lookupAttributes addObject:[SecCDKeychainLookupTuple lookupTupleWithKey:primaryServiceIdentifier.lookupKey value:primaryServiceIdentifier.serviceID]]; + for (SFServiceIdentifier* serviceIdentifier in credential.supplementaryServiceIdentifiers) { + [lookupAttributes addObject:[SecCDKeychainLookupTuple lookupTupleWithKey:serviceIdentifier.lookupKey value:serviceIdentifier.serviceID]]; + } + + [passwordCredential.customAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* customKey, id value, BOOL* stop) { + if ([customKey isKindOfClass:[NSString class]]) { + SecCDKeychainLookupTuple* lookupTuple = [SecCDKeychainLookupTuple lookupTupleWithKey:customKey value:value]; + if (lookupTuple) { + [lookupAttributes addObject:lookupTuple]; + } + else { + // TODO: an error here? + } + } + }]; + + SecCDKeychainAccessControlEntity* owner = [SecCDKeychainAccessControlEntity accessControlEntityWithType:SecCDKeychainAccessControlEntityTypeAccessGroup stringRepresentation:accessGroup]; + keyclass_t keyclass = [self keyclassForAccessPolicy:accessPolicy]; + SecCDKeychainItem* item = [[SecCDKeychainItem alloc] initItemType:[SecCDKeychainItemTypeCredential itemType] withPersistentID:persistentID attributes:attributes lookupAttributes:lookupAttributes secrets:secrets owner:owner keyclass:keyclass]; + [_keychain insertItems:@[item] withConnection:self completionHandler:^(bool success, NSError* insertError) { + if (success && !insertError) { + reply(persistentID.UUIDString, nil); + } + else { + reply(nil, insertError); + } + }]; +} + +- (void)rpcFetchPasswordCredentialForPersistentIdentifier:(NSString*)persistentIdentifier reply:(void (^)(SFPasswordCredential* credential, NSString* password, NSError* error))reply +{ + // TODO: negative testing + NSUUID* persistentID = [[NSUUID alloc] initWithUUIDString:persistentIdentifier]; + if (!persistentID) { + secerror("SFKeychainServer: attempt to fetch credential with invalid persistent identifier; %@", persistentIdentifier); + reply(nil, nil, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidPersistentIdentifier userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"invalid persistent identifier: %@", persistentIdentifier]}]); + return; + } + + [_keychain fetchItemForPersistentID:persistentID withConnection:self completionHandler:^(SecCDKeychainItem* item, NSError* error) { + NSError* localError = error; + SFPasswordCredential* credential = nil; + if (item && !error) { + credential = [self passwordCredentialForItem:item error:&localError]; + } + + if (credential) { + reply(credential, credential.password, nil); + } + else { + reply(nil, nil, localError); + } + }]; +} + +- (void)rpcLookupCredentialsForServiceIdentifiers:(nullable NSArray*)serviceIdentifiers reply:(void (^)(NSArray* _Nullable results, NSError* _Nullable error))reply +{ + __block NSMutableDictionary* resultsDict = [[NSMutableDictionary alloc] init]; + __block NSError* resultError = nil; + + void (^processFetchedItems)(NSArray*) = ^(NSArray* fetchedItems) { + for (SecCDKeychainItemMetadata* item in fetchedItems) { + if ([item.itemType isKindOfClass:[SecCDKeychainItemTypeCredential class]]) { + SFPasswordCredential* credential = [self passwordCredentialForItemMetadata:item error:&resultError]; + if (credential) { + resultsDict[item.persistentID] = credential; + } + else { + resultsDict = nil; // got an error + } + } + } + }; + + if (!serviceIdentifiers) { + // TODO: lookup everything + } + else { + for (SFServiceIdentifier* serviceIdentifier in serviceIdentifiers) { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + // TODO: this is lamé; make fetchItemsWithValue take an array and get rid of the semaphore crap + [_keychain fetchItemsWithValue:serviceIdentifier.serviceID forLookupKey:serviceIdentifier.lookupKey ofType:SecCDKeychainLookupValueTypeString withConnection:self completionHandler:^(NSArray* items, NSError* error) { + if (items && !error) { + processFetchedItems(items); + } + else { + resultsDict = nil; + resultError = error; + } + + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + } + } + + reply(resultsDict.allValues, resultError); +} + +- (void)rpcRemoveCredentialWithPersistentIdentifier:(NSString*)persistentIdentifier reply:(void (^)(BOOL success, NSError* _Nullable error))reply +{ + NSUUID* persistentID = [[NSUUID alloc] initWithUUIDString:persistentIdentifier]; + if (!persistentID) { + secerror("SFKeychainServer: attempt to remove credential with invalid persistent identifier; %@", persistentIdentifier); + reply(false, [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorInvalidPersistentIdentifier userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"invalid persistent identifier: %@", persistentIdentifier]}]); + return; + } + + [_keychain deleteItemWithPersistentID:persistentID withConnection:self completionHandler:^(bool success, NSError* error) { + reply(success, error); + }]; +} + +- (void)rpcReplaceOldCredential:(SFCredential*)oldCredential withNewCredential:(SFCredential*)newCredential reply:(void (^)(NSString* newPersistentIdentifier, NSError* _Nullable error))reply +{ + // TODO: implement + reply(nil, nil); +} + +- (SFPasswordCredential*)passwordCredentialForItem:(SecCDKeychainItem*)item error:(NSError**)error +{ + SFPasswordCredential* credential = [self passwordCredentialForItemMetadata:item.metadata error:error]; + if (credential) { + credential.password = item.secrets[SFCredentialSecretPassword]; + if (!credential.password) { + if (error) { + *error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{NSLocalizedDescriptionKey : @"failed to get password for SFCredential"}]; + } + return nil; + } + } + + return credential; +} + +- (SFPasswordCredential*)passwordCredentialForItemMetadata:(SecCDKeychainItemMetadata*)metadata error:(NSError**)error +{ + NSDictionary* attributes = metadata.attributes; + NSString* username = attributes[SFCredentialAttributeUsername]; + + NSError* localError = nil; + SFServiceIdentifier* primaryServiceIdentifier = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFServiceIdentifier class] fromData:attributes[SFCredentialAttributePrimaryServiceIdentifier] error:&localError]; + + NSArray* serializedSupplementaryServiceIdentifiers = attributes[SFCredentialAttributeSupplementaryServiceIdentifiers]; + NSMutableArray* supplementaryServiceIdentifiers = [[NSMutableArray alloc] initWithCapacity:serializedSupplementaryServiceIdentifiers.count]; + for (NSData* serializedServiceIdentifier in serializedSupplementaryServiceIdentifiers) { + if ([serializedServiceIdentifier isKindOfClass:[NSData class]]) { + SFServiceIdentifier* serviceIdentifier = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFServiceIdentifier class] fromData:serializedServiceIdentifier error:&localError]; + if (serviceIdentifier) { + [supplementaryServiceIdentifiers addObject:serviceIdentifier]; + } + else { + supplementaryServiceIdentifiers = nil; + break; + } + } + else { + supplementaryServiceIdentifiers = nil; + localError = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{NSLocalizedDescriptionKey : @"malformed supplementary service identifiers array in SecCDKeychainItem"}]; + break; + } + } + + if (username && primaryServiceIdentifier && supplementaryServiceIdentifiers) { + SFPasswordCredential* credential = [[SFPasswordCredential alloc] _initWithUsername:username primaryServiceIdentifier:primaryServiceIdentifier supplementaryServiceIdentifiers:supplementaryServiceIdentifiers]; + credential.creationDate = attributes[SFCredentialAttributeCreationDate]; + credential.modificationDate = attributes[SFCredentialAttributeModificationDate]; + credential.localizedLabel = attributes[SFKeychainItemAttributeLocalizedLabel]; + credential.localizedDescription = attributes[SFKeychainItemAttributeLocalizedDescription]; + credential.persistentIdentifier = metadata.persistentID.UUIDString; + credential.customAttributes = attributes[SFCredentialAttributeCustom]; + return credential; + } + else { + if (error) { + *error = [NSError errorWithDomain:SFKeychainErrorDomain code:SFKeychainErrorSecureDecodeFailed userInfo:@{ NSLocalizedDescriptionKey : @"failed to deserialize SFCredential", NSUnderlyingErrorKey : localError }]; + } + return nil; + } +} + +@end + +#endif // ___OBJC2__ + +void SFKeychainServerInitialize(void) +{ + static dispatch_once_t once; + static SFKeychainServer* server; + static NSXPCListener* listener; + + dispatch_once(&once, ^{ + @autoreleasepool { + NSURL* persistentStoreURL = (__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"CDKeychain"); + NSBundle* resourcesBundle = [NSBundle bundleWithPath:@"/System/Library/Keychain/KeychainResources.bundle"]; + NSURL* managedObjectModelURL = [resourcesBundle URLForResource:@"KeychainModel" withExtension:@"momd"]; + server = [[SFKeychainServer alloc] initWithStorageURL:persistentStoreURL modelURL:managedObjectModelURL encryptDatabase:true]; + listener = [[NSXPCListener alloc] initWithMachServiceName:@(kSFKeychainServerServiceName)]; + listener.delegate = server; + [listener resume]; + } + }); +} + +#else // !TARGET_OS_BRIDGE + +void SFKeychainServerInitialize(void) {} + +#endif + diff --git a/keychain/securityd/SOSCloudCircleServer.h b/keychain/securityd/SOSCloudCircleServer.h new file mode 100644 index 00000000..6c363684 --- /dev/null +++ b/keychain/securityd/SOSCloudCircleServer.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef _SECURITY_SOSCLOUDCIRCLESERVER_H_ +#define _SECURITY_SOSCLOUDCIRCLESERVER_H_ + +#import +#include "keychain/SecureObjectSync/SOSRing.h" +#import +#import + +__BEGIN_DECLS + +// +// MARK: Server versions of our SPI +// +bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error); +bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error); +bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error); +bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error); + +bool SOSCCCanAuthenticate_Server(CFErrorRef *error); +bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error); + +SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error); +bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error); +bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); +bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error); +bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); + +bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error); +bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); +bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error); +bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error); +bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error); +bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error); +bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error); + + +bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error); +bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error); +SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error); +CF_RETURNS_RETAINED CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error); +bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error); + + +CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error); +bool SOSCCValidateUserPublic_Server(CFErrorRef* error); + +CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error); +bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error); +bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error); + +SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error); + +CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error); +CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error); +bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error); +bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error); +bool SOSCCAccountSetToNew_Server(CFErrorRef *error); +bool SOSCCResetToOffering_Server(CFErrorRef* error); +bool SOSCCResetToEmpty_Server(CFErrorRef* error); +bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); + +CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error); + +SOSViewResultCode SOSCCView_Server(CFStringRef view, SOSViewActionCode action, CFErrorRef *error); +bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent); +bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews); + +CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error); +enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error); +bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error); + +bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error); + +CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error); +SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error); + +SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error); +bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef backupSlice, bool setupV0Only, CFErrorRef *error); + +bool SOSCCWaitForInitialSync_Server(CFErrorRef*); +bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error); +CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef*); + +bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error); + +SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error); +CF_RETURNS_RETAINED CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error); + +// +// MARK: Internal kicks. +// +CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates); + + +// Expected to be called when the data source changes. +void SOSCCRequestSyncWithPeer(CFStringRef peerID); +void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs); +void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs); +void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId); +bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error); + +void SOSCCEnsurePeerRegistration(void); +typedef void (^SOSAccountSyncablePeersBlock)(CFArrayRef trustedPeers, CFArrayRef addedPeers, CFArrayRef removedPeers); + +dispatch_queue_t SOSCCGetAccountQueue(void); + +CFTypeRef GetSharedAccountRef(void); // returns SOSAccount* but this header is imported by C files, so we cast through CFTypeRef + +// +// MARK: Internal access to local account for tests. +// +CFTypeRef SOSKeychainAccountGetSharedAccount(void); +// +// MARK: Internal SPIs for testing +// + +void SOSCCSetGestalt_Server(CFStringRef name, CFStringRef version, CFStringRef model, CFStringRef serial); +CFStringRef SOSCCCopyOSVersion(void); +CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error); +CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error); +bool SOSCCDeleteEngineState_Server(CFErrorRef* error); +bool SOSCCDeleteAccountState_Server(CFErrorRef* error); + + +// +// MARK: Testing operations, dangerous to call in normal operation. +// +bool SOSKeychainSaveAccountDataAndPurge(CFErrorRef *error); + +// +// MARK: Constants for where we store persistent information in the keychain +// + +extern CFStringRef kSOSAccountLabel; +extern CFStringRef kSOSPeerDataLabel; + +CFDataRef SOSItemCopy(CFStringRef label, CFErrorRef* error); +bool SOSItemUpdateOrAdd(CFStringRef label, CFStringRef accessibility, CFDataRef data, CFErrorRef *error); + +bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error); +CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error); +bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error); +CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error); + +CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error); + +SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error); +CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error); +bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData_Server(uint32_t flags, CFErrorRef *error); +bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error); + +bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error); +bool SOSCCAccountIsNew_Server(CFErrorRef *error); +bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error); + +void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization); + +bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); +bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); + +void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivKey, CFErrorRef error)); +void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error)); +void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error)); +void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error)); +void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error)); +void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error)); +void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error)); +void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey, + CFDataRef signingPublicKey, CFDataRef encryptionPublicKey, + SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef, + void (^action)(CFErrorRef error)); + +void SOSCCResetOTRNegotiation_Server(CFStringRef peerid); +void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup); + +__END_DECLS + +#endif diff --git a/keychain/securityd/SOSCloudCircleServer.m b/keychain/securityd/SOSCloudCircleServer.m new file mode 100644 index 00000000..ef07ff98 --- /dev/null +++ b/keychain/securityd/SOSCloudCircleServer.m @@ -0,0 +1,2571 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include + +#import "keychain/SecureObjectSync/SOSAccountTransaction.h" + +#include "keychain/securityd/SOSCloudCircleServer.h" +#include +#include + +#include "keychain/SecureObjectSync/SOSCircle.h" +#include "keychain/SecureObjectSync/SOSAccount.h" +#include "keychain/SecureObjectSync/SOSAccountPriv.h" +#include "keychain/SecureObjectSync/SOSAccountGhost.h" + +#include "keychain/SecureObjectSync/SOSTransport.h" +#include "keychain/SecureObjectSync/SOSFullPeerInfo.h" +#include "keychain/SecureObjectSync/SOSPeerInfoV2.h" +#include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" +#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" +#include "keychain/SecureObjectSync/SOSInternal.h" +#include "keychain/SecureObjectSync/SOSUserKeygen.h" +#include "keychain/SecureObjectSync/SOSMessage.h" +#include "keychain/SecureObjectSync/SOSBackupInformation.h" +#include "keychain/SecureObjectSync/SOSDataSource.h" +#include "keychain/SecureObjectSync/SOSKVSKeys.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "keychain/SecureObjectSync/SOSAuthKitHelpers.h" +#import "keychain/ot/OTManager.h" +#import "NSError+UsefulConstructors.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include + +#include + +#include +#include +#include "keychain/securityd/SecDbKeychainItem.h" + +#include +#include + +#include + +#if TARGET_OS_IPHONE +#include +#else +#include +#endif + +#define SOSCKCSCOPE "sync" +#define RUN_AS_ROOT_ERROR 550 + +#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS +#import + +#include + +static int64_t getTimeDifference(time_t start); +CFStringRef const SOSAggdSyncCompletionKey = CFSTR("com.apple.security.sos.synccompletion"); +CFStringRef const SOSAggdSyncTimeoutKey = CFSTR("com.apple.security.sos.timeout"); + +typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(void); + +static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL; + + + +// +// Forward declared +// + +static void do_with_account(void (^action)(SOSAccountTransaction* txn)); + +// +// Constants +// + +CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data"); + +CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count"); + +CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date"); + +static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData) +{ + return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrService, service, + kSecAttrAccessGroup, kSOSInternalAccessGroup, + kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse, + NULL); +} + +CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error) +{ + CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true); + + CFDataRef result = NULL; + + OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result); + + CFReleaseNull(query); + + if (copyResult != noErr) { + SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service); + CFReleaseNull(result); + return NULL; + } + + if (!isData(result)) { + SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service); + CFReleaseNull(result); + return NULL; + } + + return result; +} + +static CFDataRef SOSKeychainCopySavedAccountData() +{ + CFErrorRef error = NULL; + CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error); + if (!accountData) { + secnotice("account", "Failed to load account: %@", error); + secerror("Failed to load account: %@", error); + } + CFReleaseNull(error); + + return accountData; +} + +bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error) +{ + CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false); + + CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecValueData, data, + kSecAttrAccessible, accessibility, + NULL); + OSStatus saveStatus = SecItemUpdate(query, update); + + if (errSecItemNotFound == saveStatus) { + CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query); + CFDictionaryForEach(update, ^(const void *key, const void *value) { + CFDictionaryAddValue(add, key, value); + }); + saveStatus = SecItemAdd(add, NULL); + CFReleaseNull(add); + } + + CFReleaseNull(query); + CFReleaseNull(update); + + return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service); +} + +static void SOSKeychainAccountEnsureSaved(CFDataRef accountAsData) +{ + static CFDataRef sLastSavedAccountData = NULL; + + CFErrorRef saveError = NULL; + require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit); + + if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, accountAsData, &saveError)) { + secerror("Can't save account: %@", saveError); + goto exit; + } + + CFAssignRetained(sLastSavedAccountData, CFRetainSafe(accountAsData)); + +exit: + CFReleaseNull(saveError); +} + +static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt) +{ + secdebug("account", "Created account"); + + CFDataRef savedAccount = SOSKeychainCopySavedAccountData(); + SOSAccount* account = NULL; + + SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride() + : SecItemDataSourceFactoryGetDefault(); + + require_quiet(factory, done); + + if (savedAccount) { + NSError* inflationError = NULL; + + account = [SOSAccount accountFromData:(__bridge NSData*) savedAccount + factory:factory + error:&inflationError]; + + if (account){ + [account.trust updateGestalt:account newGestalt:our_gestalt]; + } else { + secerror("Got error inflating account: %@", inflationError); + } + + } + CFReleaseNull(savedAccount); + + if (!account) { + account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory); + + if (!account) + secerror("Got NULL creating account"); + } + +done: + CFReleaseNull(savedAccount); + return account; +} + +// +// Mark: Gestalt Handling +// + +CFStringRef SOSGestaltVersion = NULL; +CFStringRef SOSGestaltModel = NULL; +CFStringRef SOSGestaltDeviceName = NULL; + +void +SOSCCSetGestalt_Server(CFStringRef deviceName, + CFStringRef version, + CFStringRef model, + CFStringRef serial) +{ + SOSGestaltDeviceName = CFRetainSafe(deviceName); + SOSGestaltVersion = CFRetainSafe(version); + SOSGestaltModel = CFRetainSafe(model); + SOSGestaltSerial = CFRetainSafe(serial); +} + +CFStringRef SOSCCCopyOSVersion(void) +{ + static dispatch_once_t once; + dispatch_once(&once, ^{ + if (SOSGestaltVersion == NULL) { + CFDictionaryRef versions = _CFCopySystemVersionDictionary(); + if (versions) { + CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey); + if (isString(versionValue)) + SOSGestaltVersion = CFRetainSafe((CFStringRef) versionValue); + } + + CFReleaseNull(versions); + if (SOSGestaltVersion == NULL) { + SOSGestaltVersion = CFSTR("Unknown model"); + } + } + }); + return CFRetainSafe(SOSGestaltVersion); +} + + +static CFStringRef CopyModelName(void) +{ + static dispatch_once_t once; + dispatch_once(&once, ^{ + if (SOSGestaltModel == NULL) { +#if TARGET_OS_IPHONE + SOSGestaltModel = MGCopyAnswer(kMGQDeviceName, NULL); +#else + SOSGestaltModel = ASI_CopyComputerModelName(FALSE); +#endif + if (SOSGestaltModel == NULL) + SOSGestaltModel = CFSTR("Unknown model"); + } + }); + return CFStringCreateCopy(kCFAllocatorDefault, SOSGestaltModel); +} + +static CFStringRef CopyComputerName(SCDynamicStoreRef store) +{ + if (SOSGestaltDeviceName == NULL) { + CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL); + if (deviceName == NULL) { + deviceName = CFSTR("Unknown name"); + } + return deviceName; + } + return SOSGestaltDeviceName; +} + +static bool _EngineMessageProtocolV2Enabled(void) +{ +#if DEBUG + //sudo rhr + static dispatch_once_t onceToken; + static bool v2_enabled = false; + dispatch_once(&onceToken, ^{ + CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + + if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) { + v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref); + secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled"); + } + CFReleaseSafe(v2Pref); + }); + + return v2_enabled; +#else + return false; +#endif +} + + +static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context) +{ + CFStringRef modelName = CopyModelName(); + CFStringRef computerName = CopyComputerName(store); + CFStringRef osVersion = SOSCCCopyOSVersion(); + + SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0; + CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version); + + CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kPIUserDefinedDeviceNameKey, computerName, + kPIDeviceModelNameKey, modelName, + kPIMessageProtocolVersionKey, protocolVersion, + kPIOSVersionKey, osVersion, + NULL); + CFReleaseSafe(osVersion); + CFReleaseSafe(modelName); + CFReleaseSafe(computerName); + CFReleaseSafe(protocolVersion); + + return gestalt; +} + +static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context) +{ + do_with_account(^(SOSAccountTransaction* txn) { + if(txn.account){ + CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context); + if ([txn.account.trust updateGestalt:txn.account newGestalt:gestalt]) { + secnotice("circleOps", "Changed our peer's gestalt information. This is not a circle change."); + } + CFReleaseSafe(gestalt); + } + }); +} + + +static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info) +{ + SCDynamicStoreContext context = { .info = info }; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context); + CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL); + CFArrayRef keys = NULL; + CFDictionaryRef gestalt = NULL; + + if (store == NULL || computerKey == NULL) { + goto done; + } + keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks); + if (keys == NULL) { + goto done; + } + gestalt = CreateDeviceGestaltDictionary(store, keys, info); + SCDynamicStoreSetNotificationKeys(store, keys, NULL); + SCDynamicStoreSetDispatchQueue(store, queue); + +done: + if (store) CFRelease(store); + if (computerKey) CFRelease(computerKey); + if (keys) CFRelease(keys); + return gestalt; +} + +os_state_block_t accountStateBlock = ^os_state_data_t(os_state_hints_t hints) { + os_state_data_t retval = NULL; + CFDataRef savedAccount = NULL; + if(hints->osh_api != OS_STATE_API_REQUEST) return NULL; + + /* Get account DER */ + savedAccount = SOSKeychainCopySavedAccountData(); + require_quiet(savedAccount, errOut); + + /* make a os_state_data_t object to return. */ + size_t statelen = CFDataGetLength(savedAccount); + retval = (os_state_data_t)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen)); + require_quiet(retval, errOut); + + retval->osd_type = OS_STATE_DATA_PROTOCOL_BUFFER; + memcpy(retval->osd_data, CFDataGetBytePtr(savedAccount), statelen); + retval->osd_size = statelen; + strlcpy(retval->osd_title, "CloudCircle Account Object", sizeof(retval->osd_title)); + +errOut: + CFReleaseNull(savedAccount); + return retval; +}; + +#define FOR_EXISTING_ACCOUNT 1 +#define CREATE_ACCOUNT_IF_NONE 0 + +static SOSAccount* GetSharedAccount(bool onlyIfItExists) { + static SOSAccount* sSharedAccount = NULL; + static dispatch_once_t onceToken; + +#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + if(geteuid() == 0){ + secerror("Cannot inflate account object as root"); + return NULL; + } +#endif + + if(onlyIfItExists) { + return sSharedAccount; + } + + dispatch_once(&onceToken, ^{ + secdebug("account", "Account Creation start"); + + CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + + if (!gestalt) { +#if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR + gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); +#else + secerror("Didn't get machine gestalt! This is going to be ugly."); +#endif + } + + sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt); + + SOSAccountAddChangeBlock(sSharedAccount, ^(SOSAccount *account, SOSCircleRef circle, + CFSetRef peer_additions, CFSetRef peer_removals, + CFSetRef applicant_additions, CFSetRef applicant_removals) { + CFErrorRef pi_error = NULL; + SOSPeerInfoRef me = account.peerInfo; + if(!me) { + secinfo("circleOps", "Change block called with no peerInfo"); + return; + } + + if(!SOSCircleHasPeer(circle, me, NULL)) { + secinfo("circleOps", "Change block called while not in circle"); + return; + } + + // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer. + if (CFSetGetCount(peer_additions) != 0) { + secnotice("updates", "Requesting Ensure Peer Registration."); + SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + } else { + secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed"); + } + + if (CFSetContainsValue(peer_additions, me)) { + // TODO: Potentially remove from here and move this to the engine + // TODO: We also need to do this when our views change. + CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault); + CFSetRemoveValue(peers, me); + if (!CFSetIsEmpty(peers)) { + SOSCCRequestSyncWithPeers(peers); + } + CFReleaseNull(peers); + } + + CFReleaseNull(pi_error); + + if (CFSetGetCount(peer_additions) != 0 || + CFSetGetCount(peer_removals) != 0 || + CFSetGetCount(applicant_additions) != 0 || + CFSetGetCount(applicant_removals) != 0) { + + if(CFSetGetCount(peer_removals) != 0) + { + CFErrorRef localError = NULL; + CFMutableArrayRef removed = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetForEach(peer_removals, ^(const void *value) { + CFArrayAppendValue(removed, value); + }); + SOSAccountRemoveBackupPeers(account, removed, &localError); + if(localError) + secerror("Had trouble removing: %@, error: %@", removed, localError); + CFReleaseNull(localError); + CFReleaseNull(removed); + } + secnotice("circleOps", "peer counts changed, posting kSOSCCCircleChangedNotification"); + account.notifyCircleChangeOnExit = true; + } + }); + + SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) { + CFRetainSafe(changes); + __block CFMutableArrayRef handledKeys = NULL; + do_with_account(^(SOSAccountTransaction* txn) { + CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false); + secdebug(SOSCKCSCOPE, "Received: %@", changeDescription); + CFReleaseSafe(changeDescription); + + CFErrorRef error = NULL; + handledKeys = SOSTransportDispatchMessages(txn, changes, &error); + if (!handledKeys || error) { + secerror("Error handling updates: %@", error); + } + CFReleaseNull(error); + }); + CFReleaseSafe(changes); + return handledKeys; + }); + CFReleaseSafe(gestalt); + + sSharedAccount.saveBlock = ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) { + if (flattenedAccount) { + SOSKeychainAccountEnsureSaved(flattenedAccount); + } else { + secerror("Failed to transform account into data, error: %@", flattenFailError); + } + }; + // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call + SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + + // provide state handler to sysdiagnose and logging + os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock); + + [sSharedAccount ghostBustSchedule]; + + }); + + return sSharedAccount; +} + +CFTypeRef GetSharedAccountRef(void) +{ + return (__bridge CFTypeRef)GetSharedAccount(FOR_EXISTING_ACCOUNT); +} + +static void do_with_account(void (^action)(SOSAccountTransaction* txn)) { + @autoreleasepool { + SOSAccount* account = GetSharedAccount(CREATE_ACCOUNT_IF_NONE); + + if(account){ + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + action(txn); + }]; + } + } +} + +static bool isValidUser(CFErrorRef* error) { +#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + if(geteuid() == 0){ + secerror("Cannot inflate account object as root"); + SOSErrorCreate(kSOSErrorUnsupported, error, NULL, CFSTR("Cannot inflate account object as root")); + return false; + } +#endif + + return true; +} + +static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action) +{ +#if TARGET_OS_SIMULATOR + action(); + return true; +#else + bool beenUnlocked = false; + require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail); + + require_action_quiet(beenUnlocked, fail, + SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL, + CFSTR("Keybag never unlocked, ask after first unlock"))); + + action(); + + return true; + +fail: + return false; +#endif +} + +static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) +{ + __block bool action_result = false; + + return isValidUser(error) && do_if_after_first_unlock(error, ^{ + do_with_account(^(SOSAccountTransaction* txn) { + action_result = action(txn, error); + }); + + }) && action_result; +} + +static bool isAssertionLockAcquireError(CFErrorRef error) { + return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain)); +} + +static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) +{ + bool result = false; + + CFErrorRef statusError = NULL; + + __block bool action_result = false; + __block bool attempted_action = false; + __block CFErrorRef localError = NULL; + + + if(!isValidUser(error)){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result; + } + + result = SecAKSDoWithUserBagLockAssertion(&localError, ^{ + // SOSAccountGhostBustingOptions need to be retrieved from RAMP while not holding the account queue + // yet we only want to request RAMP info if it's "time" to ghostbust. + +#if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX) + __block bool ghostbustnow = false; + __block SOSAccountGhostBustingOptions gbOptions = 0; + + // Avoid mutual deadlock for just checking date. + // Check to see if we're InCircle using the client API - will read cached value if available; otherwise it'll do the round trip and lock appropriately + SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(NULL); + if(circleStatus == kSOSCCInCircle) { + // Only need the account object to check settings + SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT); + if(tmpAccount.settings) { + ghostbustnow = [tmpAccount ghostBustCheckDate]; + } + + // Get ramp settings from the Cloud + if(ghostbustnow) { + gbOptions = [SOSAccount ghostBustGetRampSettings]; + } + } +#endif + + do_with_account(^(SOSAccountTransaction* txn) { + SOSAccount *account = txn.account; + if ([account isInCircle:(NULL)] && [SOSAuthKitHelpers accountIsHSA2]) { + if(![SOSAuthKitHelpers peerinfoHasMID: account]) { + // This is the first good opportunity to update our FullPeerInfo and + // push the resulting circle. + [SOSAuthKitHelpers updateMIDInPeerInfo: account]; + } + } +#if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX) + if(ghostbustnow) { + [account ghostBustPeriodic:gbOptions complete:^(bool ghostBusted, NSError *error) { + secnotice("ghostbust", "GhostBusting: %@", ghostBusted ? CFSTR("true"): CFSTR("false")); + }]; + } +#endif + attempted_action = true; + action_result = action(txn, error); + }); + }); + + + + // For 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked + // If we fail with an error attempting to get an assertion while someone else has one and the system is unlocked, it must be trying to lock. + // we assume our caller will hold the lock assertion for us to finsh our job. + // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again. + + if(result || !isAssertionLockAcquireError(localError)){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return (result && action_result); + } + if(attempted_action){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return (result && action_result); + } + + bool isUnlocked = false; + (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError); + if(!isUnlocked){ + secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError); + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result && action_result; + } + + CFReleaseNull(localError); + + secnotice("while-unlocked-hack", "Trying action while unlocked without assertion"); + + result = true; + do_with_account(^(SOSAccountTransaction* txn) { + action_result = action(txn, &localError); + }); + + secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError); + + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result && action_result; +} + + + +CFTypeRef SOSKeychainAccountGetSharedAccount() +{ + __block SOSAccount* result = NULL; + result = GetSharedAccount(FOR_EXISTING_ACCOUNT); + + if(!result) { + secnotice("secAccount", "Failed request for account object"); + } + return (__bridge CFTypeRef)result; +} + +// +// Mark: Credential processing +// + + +SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) { + __block SOSViewResultCode status = kSOSCCGeneralViewError; + + do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool retval = false; + + switch(action) { + case kSOSCCViewQuery: + status = [txn.account.trust viewStatus:txn.account name:viewname err:error]; + retval = true; + break; + case kSOSCCViewEnable: + status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; + retval = true; + break; + + case kSOSCCViewDisable: + status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; + retval = true; + break; + default: + secnotice("views", "Bad SOSViewActionCode - %d", (int) action); + retval = false; + break; + } + return retval; + }); + return status; +} + +bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) { + __block bool status = false; + + do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent]; + return true; + }); + return status; +} + + +bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) { + return SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, NULL); +} + + +void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){ + + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); + + secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait"); + + SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { + if (sync_error) { + secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error); + } else { + secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues); + } + + dispatch_semaphore_signal(wait_for); + }); + + if(waitForeverForSynchronization) + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + else + dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC)); + + wait_for = nil; +} + +#define kWAIT2MINID "EFRESH" + +static bool SyncKVSAndWait(CFErrorRef *error) { + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); + + __block bool success = false; + + secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait"); + + os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) { + secnotice("fresh", "EFP returned, callback error: %@", sync_error); + + success = (sync_error == NULL); + if (error) { + CFRetainAssign(*error, sync_error); + } + + dispatch_semaphore_signal(wait_for); + }); + + + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL); + }); + + return success; +} + +static bool Flush(CFErrorRef *error) { + __block bool success = false; + + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); + secnotice("flush", "Starting"); + + SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { + success = (sync_error == NULL); + if (error) { + CFRetainAssign(*error, sync_error); + } + + dispatch_semaphore_signal(wait_for); + }); + + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + + secnotice("flush", "Returned %s", success? "Success": "Failure"); + + return success; +} + +bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { + secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label); + + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { + SOSAccountAssertDSID(txn.account, dsid); + } + return true; + }); + + require_quiet(result, done); + + require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has + require_quiet(Flush(error), done); // And processed it already...before asserting + + result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { + return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error); + }); + + require_quiet(result, done); + require_quiet(Flush(error), done); + +done: + return result; +} + +static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { + secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); + + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { + SOSAccountAssertDSID(txn.account, dsid); + } + return true; + }); + + require_quiet(result, done); + + require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has + require_quiet(Flush(error), done); // And processed it already...before asserting + + result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { + return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); + }); + + require_quiet(result, done); + require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature + + result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountGenerationSignatureUpdate(txn.account, error); + }); + + secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", + dsid, user_label, result, error ? *error : NULL); +done: + return result; +} + +static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) { + secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); + + NSError* localError = nil; + SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; + + SFSignInAnalytics *syncAndWaitEvent = nil; + SFSignInAnalytics *flushEvent = nil; + SFSignInAnalytics *secondFlushEvent = nil; + SFSignInAnalytics *generationSignatureUpdateEvent = nil; + + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { + SOSAccountAssertDSID(txn.account, dsid); + } + return true; + }); + + require_quiet(result, done); + syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"]; + require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has + [syncAndWaitEvent stopWithAttributes:nil]; + + flushEvent = [parent newSubTaskForEvent:@"flushEvent"]; + require_quiet(Flush(error), done); // And processed it already...before asserting + [flushEvent stopWithAttributes:nil]; + + result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { + return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); + }); + + require_quiet(result, done); + secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"]; + require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature + [secondFlushEvent stopWithAttributes:nil]; + + generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; + result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountGenerationSignatureUpdate(txn.account, error); + }); + [generationSignatureUpdateEvent stopWithAttributes:nil]; + + +done: + if(syncAndWaitEvent){ + [syncAndWaitEvent stopWithAttributes:nil]; + } + if(flushEvent){ + [flushEvent stopWithAttributes:nil]; + } + if(secondFlushEvent){ + [secondFlushEvent stopWithAttributes:nil]; + } + if(generationSignatureUpdateEvent){ + [generationSignatureUpdateEvent stopWithAttributes:nil]; + } + secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", + dsid, user_label, result, error ? *error : NULL); + + return result; +} + +bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) +{ + // TODO: Return error if DSID is NULL to insist our callers provide one? + return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error); +} + +bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error) +{ + return SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error); +} +bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error) +{ + return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error); +} + +bool SOSCCCanAuthenticate_Server(CFErrorRef *error) +{ + bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet. + // + SOSAccountRestartPrivateCredentialTimer(txn.account); + return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL; + }); + + if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) { + CFIndex code = CFErrorGetCode(*error); + if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) { + CFReleaseNull(*error); + } + } + + return result; +} + +bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error) +{ + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountPurgePrivateCredential(txn.account); + return true; + }); +} + +SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error) +{ + __block SOSCCStatus status; + + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + status = [txn.account getCircleStatus:block_error]; + + return true; + }) ? status : kSOSCCError; +} + +bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) +{ + __block bool result = true; + + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountJoinCircles(txn, block_error); + return result; + }); +} + +bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) +{ + __block bool result = true; + + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); + return result; + }); +} + +bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) +{ + __block bool result = true; + __block CFErrorRef localError = NULL; + + bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountHasPublicKey(txn.account, &localError); + return result; + }); + + if(error != NULL && localError != NULL) + *error = localError; + + return hasPublicKey; +} + +bool SOSCCAccountIsNew_Server(CFErrorRef *error) +{ + __block bool result = true; + __block CFErrorRef localError = NULL; + + (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountIsNew(txn.account, &localError); + return result; + }); + + if(error != NULL && localError != NULL) + *error = localError; + + return result; +} +bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) +{ + __block bool result = true; + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountEnsurePeerRegistration(txn.account, block_error); + result = SOSAccountJoinCirclesAfterRestore(txn, block_error); + return result; + }); + return returned; + +} + +bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) +{ + __block bool result = true; + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + NSError* localError = nil; + SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; + + SFSignInAnalytics *ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"]; + SOSAccountEnsurePeerRegistration(txn.account, block_error); + if(block_error && *block_error){ + NSError* blockError = (__bridge NSError*)*block_error; + if(blockError){ + [ensurePeerRegistrationEvent logRecoverableError:blockError]; + secerror("ensure peer registration error: %@", blockError); + } + } + [ensurePeerRegistrationEvent stopWithAttributes:nil]; + result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); + return result; + }); + return returned; + +} + +bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error) +{ + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SyncKVSAndWait(block_error); + }); + if (returned) { + returned = Flush(error); + } + return returned; +} + +bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){ + __block bool result = true; + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; + + if(fpi && ring) { + result = SOSRingApply(ring, txn.account.accountKey, fpi , error); + } + CFReleaseNull(ring); + return result; + }); + return returned; +} + +bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){ + __block bool result = true; + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; + if(fpi && ring) { + result = SOSRingWithdraw(ring, txn.account.accountKey, fpi , error); + } + CFReleaseNull(ring); + return result; + }); + return returned; +} + +bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){ + __block bool result = true; + bool returned = false; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; + if(fpi && ring) { + result = SOSRingResetToOffering(ring, NULL, fpi, error); + } + CFReleaseNull(ring); + return result; + }); + return returned; +} + +CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){ + __block CFMutableDictionaryRef result = NULL; + __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); + + (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountForEachRing(txn.account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { + CFStringAppendFormat(description, NULL, CFSTR("%@\n"), ring); + return NULL; + }); + if(result) + return true; + return false; + }); + + return description; +} + +SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){ + __block bool result = true; + SOSRingStatus returned; + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); + + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; + if(myPeer && ring) { + result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer)); + } + CFReleaseNull(ring); + + return result; + }); + return returned; +} + +bool SOSCCAccountSetToNew_Server(CFErrorRef *error) +{ + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountSetToNew(txn.account); + return true; + }); +} + +bool SOSCCResetToOffering_Server(CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); + if (!user_key) + return false; + return [txn.account.trust resetToOffering:txn key:user_key err:block_error]; + }); + +} + +bool SOSCCResetToEmpty_Server(CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (!SOSAccountHasPublicKey(txn.account, error)) + return false; + return [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error]; + }); + +} + +bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (!SOSAccountHasPublicKey(txn.account, error)) + return false; + return [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error]; + }); + +} + +bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error]; + }); +} + +bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return [txn.account.trust leaveCircle:txn.account err:block_error]; + }); +} + +bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); + }); +} + +bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error); + }); +} + +bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + secnotice("circleOps", "Signed out of account!"); + + bool waitForeverForSynchronization = true; + + bool result = [txn.account.trust leaveCircle:txn.account err:block_error]; + + [txn restart]; // Make sure this gets finished before we set to new. + + sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); + + SOSAccountSetToNew(txn.account); + + return result; + }); +} + +bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool waitForeverForSynchronization = false; + + bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error); + + [txn restart]; // Make sure this gets finished before we set to new. + + sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); + + return result; + }); + +} + +CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyApplicants(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyGeneration(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + @autoreleasepool { + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + @autoreleasepool { + result = SOSAccountCopyValidPeers(txn.account, block_error); + } + return result != NULL; + }); + } + + return result; +} + +bool SOSCCValidateUserPublic_Server(CFErrorRef* error) +{ + __block bool result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSValidateUserPublic(txn.account, block_error); + return result; + }); + + return result; +} + +CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyNotValidPeers(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyRetired(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyViewUnaware(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error) +{ + CFArrayRef result = NULL; + SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); + if (ds) { + SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); + result = SOSEngineCopyPeerConfirmedDigests(engine, error); + SOSDataSourceRelease(ds, error); + } + + return result; +} + +static int64_t getTimeDifference(time_t start) +{ + time_t stop; + int64_t duration; + + stop = time(NULL); + + duration = stop - start; + + return SecBucket1Significant(duration); +} + +static uint64_t initialSyncTimeoutFromDefaultsWrite(void) +{ + uint64_t timeout = 10; + + //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true + CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + + if (isNumber(initialSyncTimeout)) { + CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout); + } + CFReleaseNull(initialSyncTimeout); + return timeout; +} + +bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { + __block dispatch_semaphore_t inSyncSema = NULL; + __block bool result = false; + __block bool synced = false; + bool timed_out = false; + __block CFStringRef inSyncCallID = NULL; + __block time_t start; + __block CFBooleanRef shouldUseInitialSyncV0 = false; + SFSignInAnalytics* syncingEvent = nil; + + NSError* localError = nil; + SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; + + secnotice("initial sync", "Wait for initial sync start!"); + + result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error); + bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account)); + + if (!alreadyInSync) { + start = time(NULL); + inSyncSema = dispatch_semaphore_create(0); + + SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"]; + inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) { + synced = true; + + if(inSyncSema){ + dispatch_semaphore_signal(inSyncSema); + NSDictionary* attributes = @{@"finishedSyncing" : @YES}; + [syncingEvent stopWithAttributes:attributes]; + } + return true; + }); + NSDictionary* attributes = @{}; + [callWhenInSyncEvent stopWithAttributes:attributes]; + } + else{ + synced = true; + } + return true; + }); + + require_quiet(result, fail); + + + if(inSyncSema){ + syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"]; + if(shouldUseInitialSyncV0){ + secnotice("piggy","setting initial sync timeout to 5 minutes"); + timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC)); + } + else{ + uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite(); + secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite); + timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC)); + } + } + if (timed_out && shouldUseInitialSyncV0) { + do_with_account(^(SOSAccountTransaction* txn) { + if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) { + if(inSyncSema){ + inSyncSema = NULL; // We've canceled the timeout so we must be the last. + } + } + }); + NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}]; + [syncingEvent logUnrecoverableError:error]; + NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES}; + [syncingEvent stopWithAttributes:attributes]; + } + + require_quiet(result, fail); + + if(result) + { + SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start)); + } + else if(!result) + { + SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1); + } + + secnotice("initial sync", "Finished!: %d", result); + +fail: + CFReleaseNull(inSyncCallID); + return result; +} + +bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { + + __block dispatch_semaphore_t inSyncSema = NULL; + __block bool result = false; + __block bool synced = false; + bool timed_out = false; + __block CFStringRef inSyncCallID = NULL; + __block time_t start; + __block CFBooleanRef shouldUseInitialSyncV0 = false; + + secnotice("initial sync", "Wait for initial sync start!"); + + result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error); + bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account)); + + if (!alreadyInSync) { + start = time(NULL); + inSyncSema = dispatch_semaphore_create(0); + + inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) { + synced = true; + + if(inSyncSema){ + dispatch_semaphore_signal(inSyncSema); + + } + return true; + }); + } + else{ + synced = true; + } + return true; + }); + + require_quiet(result, fail); + + if(inSyncSema){ + if(shouldUseInitialSyncV0){ + secnotice("piggy","setting initial sync timeout to 5 minutes"); + timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC)); + } + else{ + uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite(); + secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite); + timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC)); + } + } + if (timed_out && shouldUseInitialSyncV0) { + do_with_account(^(SOSAccountTransaction* txn) { + if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) { + if(inSyncSema){ + inSyncSema = NULL; // We've canceled the timeout so we must be the last. + } + } + }); + } + + require_quiet(result, fail); + + if(result) + { + SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start)); + } + else if(!result) + { + SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1); + } + + secnotice("initial sync", "Finished!: %d", result); + +fail: + CFReleaseNull(inSyncCallID); + return result; +} + + +static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccount* account, CFErrorRef *error) { + __block CFArrayRef result = NULL; + + CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error); + if (valueFetched == kCFBooleanTrue) { + SOSPeerInfoRef myPI = account.peerInfo; + if (myPI) { + SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) { + result = CFSetCopyValues(enabled); + }); + } + } else if (isSet(valueFetched)) { + result = CFSetCopyValues((CFSetRef)valueFetched); + } + + if (result == NULL) { + result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); + } + + return result; +} + +CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) { + + __block CFArrayRef views = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + views = SOSAccountCopyYetToSyncViews(txn.account, error); + + return true; + }); + + return views; +} + +bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error) { + CFErrorRef localerror = NULL; + SOSBackupSliceKeyBagRef bskb = SOSBackupSliceKeyBagForView(viewName, &localerror); + + if(bskbEncoded && bskb) { + *bskbEncoded = SOSBSKBCopyEncoded(bskb, &localerror); + } + + if(output) { + *output = SOSWrapToBackupSliceKeyBag(bskb, input, &localerror); + } + + if(error) { + *error = localerror; + } + return localerror == NULL; +} + +SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){ + __block SOSBackupSliceKeyBagRef bskb = NULL; + (void) do_with_account(^ (SOSAccountTransaction* txn) { + bskb = SOSAccountBackupSliceKeyBagForView(txn.account, viewName, error); + }); + return bskb; +} + +CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error) { + CFDataRef encrypted = NULL; + bskb_keybag_handle_t bskb_handle = 0; + + require_quiet(bskb, exit); + + bskb_handle = SOSBSKBLoadLocked(bskb, error); + require_quiet(bskb_handle, exit); + + SecAccessControlRef access = NULL; + require_quiet(access = SecAccessControlCreate(kCFAllocatorDefault, error), exit); + require_quiet(SecAccessControlSetProtection(access, kSecAttrAccessibleWhenUnlocked, error), exit); + + // ks_encrypt_data takes a dictionary as its plaintext. + CFMutableDictionaryRef plaintext = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(plaintext, CFSTR("data"), input); + + require_quiet(ks_encrypt_data_legacy(bskb_handle, access, NULL, plaintext, NULL, &encrypted, false, error), exit); + +exit: + CFReleaseNull(bskb); + if(bskb_handle != 0) { + ks_close_keybag(bskb_handle, error); + } + if(error && *error) { + secnotice("backup", "Failed to wrap to a BKSB: %@", *error); + } + return encrypted; + +} + +CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){ + + __block CFDictionaryRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + CFErrorRef localError = NULL; + SOSCCStatus status = [txn.account getCircleStatus:&localError]; + + CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); + CFDictionaryRef escrowRecords = NULL; + CFDictionaryRef record = NULL; + switch(status) { + case kSOSCCInCircle: + //get the escrow record in the peer info! + escrowRecords = SOSPeerInfoCopyEscrowRecord(txn.account.peerInfo); + if(escrowRecords){ + record = CFDictionaryGetValue(escrowRecords, dsid); + if(record) + result = CFRetainSafe(record); + } + CFReleaseNull(escrowRecords); + break; + case kSOSCCRequestPending: + //set the escrow record in the peer info/application? + break; + case kSOSCCNotInCircle: + case kSOSCCCircleAbsent: + //set the escrow record in the account expansion! + escrowRecords = SOSAccountGetValue(txn.account, kSOSEscrowRecord, error); + if(escrowRecords){ + record = CFDictionaryGetValue(escrowRecords, dsid); + if(record) + result = CFRetainSafe(record); + } + break; + default: + secdebug("account", "no circle status!"); + break; + } + return true; + }); + + return result; +} + +CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error) { + __block CFDictionaryRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSBackupInformation(txn, error); + return true; + }); + return result; +} + +bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){ + + if (escrow_label == NULL) { + return false; + } + + __block bool result = true; + __block CFErrorRef block_error = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSCCStatus status = [txn.account getCircleStatus:&block_error]; + + CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); + + CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); + + withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { + CFStringAppend(timeDescription, decription); + }); + CFStringAppend(timeDescription, CFSTR("]")); + + CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries); + + CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts); + CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription); + + CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries); + + switch(status) { + case kSOSCCInCircle: + //set the escrow record in the peer info! + if(!SOSFullPeerInfoAddEscrowRecord(txn.account.fullPeerInfo, dsid, escrowRecord, error)){ + secdebug("accout", "Could not set escrow record in the full peer info"); + result = false; + } + break; + case kSOSCCRequestPending: + //set the escrow record in the peer info/application? + break; + case kSOSCCNotInCircle: + case kSOSCCCircleAbsent: + //set the escrow record in the account expansion! + + if(!SOSAccountAddEscrowRecords(txn.account, dsid, escrowRecord, error)) { + secdebug("account", "Could not set escrow record in expansion data"); + result = false; + } + break; + default: + secdebug("account", "no circle status!"); + break; + } + CFReleaseNull(attempts); + CFReleaseNull(timeDescription); + CFReleaseNull(escrowTimeAndTries); + CFReleaseNull(escrowRecord); + + return true; + }); + + return result; +} + +bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountAcceptApplicants(txn.account, applicants, block_error); + }); + +} + +bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error) +{ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRejectApplicants(txn.account, applicants, block_error); + }); +} + +CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyPeers(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error) +{ + __block CFArrayRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyConcurringPeers(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error) +{ + __block SOSPeerInfoRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // Create a copy to be DERed/sent back to client + result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); + return result != NULL; + }); + + return result; +} + +CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error) +{ + __block CFDataRef accountState = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // Copy account state from the keychain + accountState = SOSAccountCopyAccountStateFromKeychain(block_error); + return accountState != NULL; + }); + + return accountState; +} + +bool SOSCCDeleteAccountState_Server(CFErrorRef* error) +{ + __block bool result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // Delete account state from the keychain + result = SOSAccountDeleteAccountStateFromKeychain(block_error); + return result; + }); + + return result; +} + +CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error) +{ + __block CFDataRef engineState = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // Copy engine state from the keychain + engineState = SOSAccountCopyEngineStateFromKeychain(block_error); + return engineState != NULL; + }); + + return engineState; +} + +bool SOSCCDeleteEngineState_Server(CFErrorRef* error) +{ + __block bool result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // Delete engine state from the keychain + result = SOSAccountDeleteEngineStateFromKeychain(block_error); + return result; + }); + + return result; +} + + + +SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){ + __block SOSPeerInfoRef result = NULL; + + secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock"); + (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquired account lock"); + if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){ + secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set in account"); + [txn restart]; // Finish the transaction to update any changes to the peer info. + + // Create a copy to be DERed/sent back to client + result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); + secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set and pushed"); + } + else + { + secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, could not set new public backup"); + } + return result != NULL; + }); + + return result; +} + +bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error); + }); +} + +CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error) +{ + __block CFStringRef result = NULL; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyIncompatibilityInfo(txn.account, block_error); + return result != NULL; + }); + + return result; +} + +bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error) { + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountIsLastBackupPeer(txn.account, block_error); + }); + return result; +} + +enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error) +{ + __block enum DepartureReason result = kSOSDepartureReasonError; + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountGetLastDepartureReason(txn.account, block_error); + return result != kSOSDepartureReasonError; + }); + + return result; +} + +bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){ + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountSetLastDepartureReason(txn.account, reason); + return true; + }); +} + +bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error) +{ + secnotice("updates", "Request for registering peers"); + return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountEnsurePeerRegistration(txn.account, error); + }); +} + +CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) { + __block CFSetRef result = NULL; + if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error); + return result != NULL; + })) { + // Be sure we don't return a result if we got an error + CFReleaseNull(result); + } + + return result; +} + +SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error) +{ + /* + #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked + #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked + */ + __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess; + + CFErrorRef action_error = NULL; + + if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRequestSyncWithAllPeers(txn, block_error); + })) { + if (action_error) { + if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) { + secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know"); + result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks + CFReleaseNull(action_error); + } else { + secerror("Unexpected error: %@", action_error); + } + } + + SecErrorPropagate(action_error, error); + } + + return result; +} + +// +// Sync requesting +// + +void SOSCCRequestSyncWithPeer(CFStringRef peerID) { + CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL); + + SOSCCRequestSyncWithPeersList(peers); + + CFReleaseNull(peers); +} + +void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) { + CFMutableArrayRef peerIDArray = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + CFSetForEach(peerIDs, ^(const void *value) { + if (isString(value)) { + CFArrayAppendValue(peerIDArray, value); + } else if (isSOSPeerInfo(value)) { + SOSPeerInfoRef peer = asSOSPeerInfo(value); + CFArrayAppendValue(peerIDArray, SOSPeerInfoGetPeerID(peer)); + } else { + secerror("Bad element, skipping: %@", value); + } + }); + + SOSCCRequestSyncWithPeersList(peerIDArray); + + CFReleaseNull(peerIDArray); +} + +void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) { + os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); + + CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) { + secnotice("syncwith", "Request Sync With: %@", description); + }); + + SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + CFReleaseNull(empty); + }); +} + +void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId) { + os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeer", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); + CFArrayRef backupPeerList = CFArrayCreateForCFTypes(kCFAllocatorDefault, backupPeerId, NULL); + + CFStringArrayPerformWithDescription(backupPeerList, ^(CFStringRef description) { + secnotice("syncwith", "Request backup sync With: %@", description); + }); + + SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerList, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + + CFReleaseNull(empty); + CFReleaseNull(backupPeerList); + }); +} + +bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) { + return false; +} + +void SOSCCEnsurePeerRegistration(void) +{ + os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + + SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + + }); +} + +CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) +{ + CFArrayRef result = NULL; + SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set + + (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault)); + return result; +} + +SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) { + __block SOSPeerInfoRef application = NULL; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + application = SOSAccountCopyApplication(txn.account, error); + return application != NULL; + }); + return application; +} + +bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) { + bool result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountCleanupAllKVSKeys(txn.account, error); + }); + if(result && error && *error) { + CFReleaseNull(*error); + } + return result; +} + +bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error) +{ + __block bool result = false; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountPopulateKVSWithBadKeys(txn.account, error); + }); + return result; +} +CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) { + __block CFDataRef pbblob = NULL; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error); + return pbblob != NULL; + }); + return pbblob; +} + +CFDataRef SOSCCCopyInitialSyncData_Server(SOSInitialSyncFlags flags, CFErrorRef *error) { + __block CFDataRef pbblob = NULL; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + pbblob = SOSAccountCopyInitialSyncData(txn.account, flags, error); + return pbblob != NULL; + }); + return pbblob; +} + +bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { + return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error); + }); + +} + +CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) { + __block CFBooleanRef result = NULL; + do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error); + return result != NULL; + }); + + return result; +} + +bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){ + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) + return SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); + else + return SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); + }); +} + +CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){ + + __block CFDataRef result = NULL; + do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSAccountCopyRecoveryPublicKey(txn, error); + return result != NULL; + }); + + return result; +} + +bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountMessageFromPeerIsPending(txn, peer, error); + }); +} + +bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountSendToPeerIsPending(txn, peer, error); + }); +} + +void SOSCCResetOTRNegotiation_Server(CFStringRef peerid) +{ + CFErrorRef localError = NULL; + do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountResetOTRNegotiationCoder(txn.account, peerid); + return true; + }); + if(localError) + { + secerror("error resetting otr negotation: %@", localError); + } +} + +void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup) +{ + CFErrorRef localError = NULL; + do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup); + return true; + }); + if(localError) + { + secerror("error sending next message: %@", localError); + } +} + +void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivSigningKey, CFErrorRef error)) +{ + CFErrorRef error = NULL; + do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err); + CFErrorRef errorArg = err ? *err : NULL; + action(signingKey, errorArg); + CFReleaseNull(signingKey); + return true; + }); + CFReleaseNull(error); +} + +void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error)) +{ + CFErrorRef error = NULL; + do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, err); + CFErrorRef errorArg = err ? *err : NULL; + action(signingKey, errorArg); + CFReleaseNull(signingKey); + return true; + }); + CFReleaseNull(error); +} + +void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error)) +{ + CFErrorRef error = NULL; + do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, err); + CFErrorRef errorArg = err ? *err : NULL; + action(signingKey, errorArg); + CFReleaseNull(signingKey); + return true; + }); + CFReleaseNull(error); +} + +void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error)) +{ + CFErrorRef error = NULL; + do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, err); + CFErrorRef errorArg = err ? *err : NULL; + action(signingKey, errorArg); + CFReleaseNull(signingKey); + return true; + }); + CFReleaseNull(error); +} + +void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error)) +{ + CFErrorRef localError = NULL; + do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SecKeyRef encryptionKey = NULL; + SecKeyRef signingKey = NULL; + CFErrorRef errorArg = err ? *err : NULL; + + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + require_action_quiet(fpi, fail, secerror("device does not have a peer"); SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, &errorArg)); + + signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, &errorArg); + require_action_quiet(signingKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys signing key error: %@", errorArg)); + CFReleaseNull(errorArg); + + encryptionKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, &errorArg); + require_action_quiet(encryptionKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys encryption key error: %@", errorArg)); + + action(encryptionKey, signingKey, errorArg); + CFReleaseNull(signingKey); + CFReleaseNull(encryptionKey); + CFReleaseNull(errorArg); + return true; + fail: + action(NULL, NULL, errorArg); + CFReleaseNull(errorArg); + CFReleaseNull(signingKey); + CFReleaseNull(encryptionKey); + return true; + }); + CFReleaseNull(localError); +} + +static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, int keySize, SecKeyRef octagonPublicKey, NSError** error) { + NSError* localerror = nil; + + CFDataRef publicKeyHash = SecKeyCopyPublicKeyHash(octagonPublicKey); + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC, + (id)kSecAttrKeyClass : (id)kSecAttrKeyClassPrivate, + (id)kSecAttrAccessGroup : (id)kSOSInternalAccessGroup, + (id)kSecAttrLabel : keyLabel, + (id)kSecAttrApplicationLabel : (__bridge NSData*)(publicKeyHash), + (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, + (id)kSecUseDataProtectionKeychain : @YES, + (id)kSecValueData : keyDataToSave, + } mutableCopy]; + + CFTypeRef result = NULL; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &result); + + if(status == errSecSuccess) { + CFReleaseNull(publicKeyHash); + return true; + } + if(status == errSecDuplicateItem) { + // Add every primary key attribute to this find dictionary + NSMutableDictionary* findQuery = [[NSMutableDictionary alloc] init]; + findQuery[(id)kSecClass] = query[(id)kSecClass]; + findQuery[(id)kSecAttrKeyType] = query[(id)kSecAttrKeyTypeEC]; + findQuery[(id)kSecAttrKeyClass] = query[(id)kSecAttrKeyClassPrivate]; + findQuery[(id)kSecAttrAccessGroup] = query[(id)kSecAttrAccessGroup]; + findQuery[(id)kSecAttrLabel] = query[(id)kSecAttrLabel]; + findQuery[(id)kSecAttrApplicationLabel] = query[(id)kSecAttrApplicationLabel]; + findQuery[(id)kSecUseDataProtectionKeychain] = query[(id)kSecUseDataProtectionKeychain]; + + NSMutableDictionary* updateQuery = [query mutableCopy]; + updateQuery[(id)kSecClass] = nil; + + status = SecItemUpdate((__bridge CFDictionaryRef)findQuery, (__bridge CFDictionaryRef)updateQuery); + + if(status) { + localerror = [NSError + errorWithDomain:NSOSStatusErrorDomain + code:status + description:[NSString stringWithFormat:@"SecItemUpdate: %d", (int)status]]; + } + } else { + localerror = [NSError + errorWithDomain:NSOSStatusErrorDomain + code:status + description:[NSString stringWithFormat:@"SecItemAdd: %d", (int)status]]; + } + if(localerror && error) { + *error = localerror; + } + + CFReleaseNull(publicKeyHash); + + return (status == errSecSuccess); +} + +static NSString* createKeyLabel(NSDictionary *gestalt, NSString* circleName, NSString* prefix) +{ + NSString *keyName = [NSString stringWithFormat:@"ID for %@-%@",SOSPeerGestaltGetName((__bridge CFDictionaryRef)(gestalt)), circleName]; + + NSString* octagonSigningKeyName = [prefix stringByAppendingString: keyName]; + + return octagonSigningKeyName; +} + +static NSError* saveKeysToKeychain(SOSAccount* account, NSData* octagonSigningFullKey, NSData* octagonEncryptionFullKey, SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef) +{ + NSError* saveToKeychainError = nil; + + NSString* circleName = (__bridge NSString*)(SOSCircleGetName(account.trust.trustedCircle)); + NSString* signingPrefix = @"Octagon Peer Signing "; + NSString* encryptionPrefix = @"Octagon Peer Encryption "; + NSString* octagonSigningKeyName = createKeyLabel(account.gestalt, circleName, signingPrefix); + NSString* octagonEncryptionKeyName = createKeyLabel(account.gestalt, circleName, encryptionPrefix); + + /* behavior mimics GeneratePermanentFullECKey_internal */ + saveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError); + if(saveToKeychainError) { + secerror("octagon: could not save signing key: %@", saveToKeychainError); + return saveToKeychainError; + } + saveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError); + if(saveToKeychainError) { + secerror("octagon: could not save encryption key: %@", saveToKeychainError); + return saveToKeychainError; + } + + return nil; +} + +void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey, + CFDataRef signingPublicKey, CFDataRef encryptionPublicKey, + SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef, + void (^action)(CFErrorRef error)) +{ + CFErrorRef localError = NULL; + do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + CFErrorRef updateOctagonKeysError = NULL; + bool updatedPeerInfo = SOSAccountUpdatePeerInfoAndPush(txn.account, CFSTR("Updating Octagon Keys in SOS"), &updateOctagonKeysError, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) { + + //save octagon key set to the keychain + NSError* saveError = nil; + saveError = saveKeysToKeychain(txn.account, (__bridge NSData*)octagonSigningFullKey, (__bridge NSData*)octagonEncryptionFullKey, + octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef); + + if(saveError) { + secerror("octagon: failed to save Octagon keys to the keychain: %@", saveError); + action((__bridge CFErrorRef)saveError); + return false; + } + + //now update the peer info to contain octagon keys + if(pi){ + CFErrorRef setError = NULL; + SOSPeerInfoSetOctagonKeysInDescription(pi, octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef, &setError); + if(setError) { + secerror("octagon: Failed to set Octagon Keys in peerInfo: %@", setError); + action(setError); + return false; + } + } else { + secnotice("octagon", "No peer info to update?"); + NSError *noPIError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorPeerNotFound userInfo:@{NSLocalizedDescriptionKey : @"Device has no full peer info"}]; + action((__bridge CFErrorRef)noPIError); + return false; + } + + secnotice("octagon", "Success! Upated Octagon keys in SOS!"); + + action(nil); + return true; + }); + return updatedPeerInfo; + }); + CFReleaseNull(localError); +} + +void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error)) +{ + CFErrorRef cfAccountError = NULL; + do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) { + CFSetRef sosPeerSet = [txn.account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) { + return true; + }]; + + CFErrorRef errorArg = cferror ? *cferror : NULL; + action(sosPeerSet, errorArg); + CFReleaseNull(sosPeerSet); + return true; + }); + CFReleaseNull(cfAccountError); +} + +void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error)) +{ + CFErrorRef cfAccountError = NULL; + do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) { + SOSAccount* account = txn.account; + NSString* peerID = nil; + CFErrorRef localError = nil; + + if([account getCircleStatus:nil] == kSOSCCInCircle){ + peerID = [txn.account peerID]; + } + else{ + SOSErrorCreate(kSOSErrorNoCircle, &localError, NULL, CFSTR("Not in circle")); + } + action((__bridge CFStringRef)peerID, localError); + CFReleaseNull(localError); + return true; + }); + CFReleaseNull(cfAccountError); +} diff --git a/keychain/securityd/SecAKSObjCWrappers.h b/keychain/securityd/SecAKSObjCWrappers.h new file mode 100644 index 00000000..d7bf4e94 --- /dev/null +++ b/keychain/securityd/SecAKSObjCWrappers.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import +#import "SecKeybagSupport.h" +#include + +#define BridgeCFErrorToNSErrorOut(nsErrorOut, CFErr) \ +{ \ + if (nsErrorOut) { \ + *nsErrorOut = CFBridgingRelease(CFErr); \ + CFErr = NULL; \ + } \ + else { \ + CFReleaseNull(CFErr); \ + } \ +} + +NS_ASSUME_NONNULL_BEGIN + +@interface SecAKSObjCWrappers : NSObject ++ (bool)aksEncryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass plaintext:(NSData*)plaintext + outKeyclass:(keyclass_t* _Nullable)outKeyclass ciphertext:(NSMutableData*)ciphertext error:(NSError**)error; + ++ (bool)aksDecryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass ciphertext:(NSData*)ciphertext + outKeyclass:(keyclass_t* _Nullable)outKeyclass plaintext:(NSMutableData*)plaintext error:(NSError**)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/securityd/SecAKSObjCWrappers.m b/keychain/securityd/SecAKSObjCWrappers.m new file mode 100644 index 00000000..68eb3d6a --- /dev/null +++ b/keychain/securityd/SecAKSObjCWrappers.m @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SecAKSObjCWrappers.h" + +@implementation SecAKSObjCWrappers + ++ (bool)aksEncryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass plaintext:(NSData*)plaintext + outKeyclass:(keyclass_t*)outKeyclass ciphertext:(NSMutableData*)ciphertext error:(NSError**)error +{ + CFErrorRef cfError = NULL; + bool result = ks_crypt(kAKSKeyOpEncrypt, keybag, keyclass, (uint32_t)plaintext.length, plaintext.bytes, outKeyclass, (__bridge CFMutableDataRef)ciphertext, &cfError); + BridgeCFErrorToNSErrorOut(error, cfError); + return result; +} + ++ (bool)aksDecryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass ciphertext:(NSData*)ciphertext + outKeyclass:(keyclass_t*)outKeyclass plaintext:(NSMutableData*)plaintext error:(NSError**)error +{ + CFErrorRef cfError = NULL; + bool result = ks_crypt(kAKSKeyOpDecrypt, keybag, keyclass, (uint32_t)ciphertext.length, ciphertext.bytes, outKeyclass, (__bridge CFMutableDataRef)plaintext, &cfError); + BridgeCFErrorToNSErrorOut(error, cfError); + return result; +} + +@end diff --git a/keychain/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto b/keychain/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto new file mode 100644 index 00000000..e2f4dbad --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto @@ -0,0 +1,40 @@ +syntax = "proto2"; + +option objc_class_naming = "extended"; + +// Maintain identity consistency by including this in key and bag messages +message SecDbBackupBagIdentity { + optional bytes baguuid = 1; + optional bytes baghash = 2; +} + +// Insert into backupkeyclasssigningkeys table, v12_keyClassSigningKey column +message SecDbBackupKeyClassSigningKey { + optional int32 keyClass = 1; + optional bytes publicKey = 3; + optional bytes aksRefKey = 4; // Contains bag identity as authenticated data + optional bytes aksWrappedKey = 5; // SFECIESKeyPair wrapped by AKS ref key + optional bytes backupWrappedKey = 6; // SFECIESKeyPair wrapped by KCSKSecret in RecoverySet. Also authenticates bag identity +} + +// Insert into metadatakeys table, v12_metadatakeydata column +message SecDbBackupMetadataClassKey { + optional int32 keyClass = 1; + optional bytes backupWrappedMetadataKey = 2; // wrapped by appropriate backup keyclass for recovery +// optional bytes aksWrappedMetadataKey = 3; // wrapped by device bag for daily use. Not in use right now. +} + +// Insert into backuprecoverysets table, v12_recoverySet column +message SecDbBackupRecoverySet { + optional int32 recoveryType = 1; + optional SecDbBackupBagIdentity bagIdentity = 2; + optional bytes wrappedBagSecret = 3; // 'passphrase' to unlock backup bag's private keys + optional bytes wrappedKCSKSecret = 4; // recovers KCSKs to verify authenticity of IKs and MCKs + optional bytes wrappedRecoveryKey = 5; // wraps the above two secrets +} + +// Insert into backupbags table, v12_backupBag column +message SecDbBackupBag { + optional SecDbBackupBagIdentity bagIdentity = 1; + optional bytes keybag = 2; +} diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h new file mode 100644 index 00000000..b4568c2c --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h @@ -0,0 +1,42 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import +#import + +@class SecDbBackupBagIdentity; + +#ifdef __cplusplus +#define SECDBBACKUPBAG_FUNCTION extern "C" +#else +#define SECDBBACKUPBAG_FUNCTION extern +#endif + +/** Insert into backupbags table, v12_backupBag column */ +@interface SecDbBackupBag : PBCodable +{ + SecDbBackupBagIdentity *_bagIdentity; + NSData *_keybag; +} + + +@property (nonatomic, readonly) BOOL hasBagIdentity; +@property (nonatomic, retain) SecDbBackupBagIdentity *bagIdentity; + +@property (nonatomic, readonly) BOOL hasKeybag; +@property (nonatomic, retain) NSData *keybag; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbBackupBag *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbBackupBag *)other; + +SECDBBACKUPBAG_FUNCTION BOOL SecDbBackupBagReadFrom(__unsafe_unretained SecDbBackupBag *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m new file mode 100644 index 00000000..01ab3770 --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m @@ -0,0 +1,177 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import "SecDbBackupBag.h" +#import +#import +#import + +#import "SecDbBackupBagIdentity.h" + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbBackupBag + +- (BOOL)hasBagIdentity +{ + return _bagIdentity != nil; +} +@synthesize bagIdentity = _bagIdentity; +- (BOOL)hasKeybag +{ + return _keybag != nil; +} +@synthesize keybag = _keybag; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_bagIdentity) + { + [dict setObject:[_bagIdentity dictionaryRepresentation] forKey:@"bagIdentity"]; + } + if (self->_keybag) + { + [dict setObject:self->_keybag forKey:@"keybag"]; + } + return dict; +} + +BOOL SecDbBackupBagReadFrom(__unsafe_unretained SecDbBackupBag *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* bagIdentity */: + { + SecDbBackupBagIdentity *new_bagIdentity = [[SecDbBackupBagIdentity alloc] init]; + self->_bagIdentity = new_bagIdentity; + PBDataReaderMark mark_bagIdentity; + BOOL markError = !PBReaderPlaceMark(reader, &mark_bagIdentity); + if (markError) + { + return NO; + } + BOOL inError = !SecDbBackupBagIdentityReadFrom(new_bagIdentity, reader); + if (inError) + { + return NO; + } + PBReaderRecallMark(reader, &mark_bagIdentity); + } + break; + case 2 /* keybag */: + { + NSData *new_keybag = PBReaderReadData(reader); + self->_keybag = new_keybag; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbBackupBagReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* bagIdentity */ + { + if (self->_bagIdentity != nil) + { + PBDataWriterWriteSubmessage(writer, self->_bagIdentity, 1); + } + } + /* keybag */ + { + if (self->_keybag) + { + PBDataWriterWriteDataField(writer, self->_keybag, 2); + } + } +} + +- (void)copyTo:(SecDbBackupBag *)other +{ + if (_bagIdentity) + { + other.bagIdentity = _bagIdentity; + } + if (_keybag) + { + other.keybag = _keybag; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbBackupBag *copy = [[[self class] allocWithZone:zone] init]; + copy->_bagIdentity = [_bagIdentity copyWithZone:zone]; + copy->_keybag = [_keybag copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbBackupBag *other = (SecDbBackupBag *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_bagIdentity && !other->_bagIdentity) || [self->_bagIdentity isEqual:other->_bagIdentity]) + && + ((!self->_keybag && !other->_keybag) || [self->_keybag isEqual:other->_keybag]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_bagIdentity hash] + ^ + [self->_keybag hash] + ; +} + +- (void)mergeFrom:(SecDbBackupBag *)other +{ + if (self->_bagIdentity && other->_bagIdentity) + { + [self->_bagIdentity mergeFrom:other->_bagIdentity]; + } + else if (!self->_bagIdentity && other->_bagIdentity) + { + [self setBagIdentity:other->_bagIdentity]; + } + if (other->_keybag) + { + [self setKeybag:other->_keybag]; + } +} + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h new file mode 100644 index 00000000..939066cb --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h @@ -0,0 +1,40 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBBACKUPBAGIDENTITY_FUNCTION extern "C" +#else +#define SECDBBACKUPBAGIDENTITY_FUNCTION extern +#endif + +/** Maintain identity consistency by including this in key and bag messages */ +@interface SecDbBackupBagIdentity : PBCodable +{ + NSData *_baghash; + NSData *_baguuid; +} + + +@property (nonatomic, readonly) BOOL hasBaguuid; +@property (nonatomic, retain) NSData *baguuid; + +@property (nonatomic, readonly) BOOL hasBaghash; +@property (nonatomic, retain) NSData *baghash; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbBackupBagIdentity *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbBackupBagIdentity *)other; + +SECDBBACKUPBAGIDENTITY_FUNCTION BOOL SecDbBackupBagIdentityReadFrom(__unsafe_unretained SecDbBackupBagIdentity *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m new file mode 100644 index 00000000..03bcbf45 --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m @@ -0,0 +1,159 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import "SecDbBackupBagIdentity.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbBackupBagIdentity + +- (BOOL)hasBaguuid +{ + return _baguuid != nil; +} +@synthesize baguuid = _baguuid; +- (BOOL)hasBaghash +{ + return _baghash != nil; +} +@synthesize baghash = _baghash; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_baguuid) + { + [dict setObject:self->_baguuid forKey:@"baguuid"]; + } + if (self->_baghash) + { + [dict setObject:self->_baghash forKey:@"baghash"]; + } + return dict; +} + +BOOL SecDbBackupBagIdentityReadFrom(__unsafe_unretained SecDbBackupBagIdentity *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* baguuid */: + { + NSData *new_baguuid = PBReaderReadData(reader); + self->_baguuid = new_baguuid; + } + break; + case 2 /* baghash */: + { + NSData *new_baghash = PBReaderReadData(reader); + self->_baghash = new_baghash; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbBackupBagIdentityReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* baguuid */ + { + if (self->_baguuid) + { + PBDataWriterWriteDataField(writer, self->_baguuid, 1); + } + } + /* baghash */ + { + if (self->_baghash) + { + PBDataWriterWriteDataField(writer, self->_baghash, 2); + } + } +} + +- (void)copyTo:(SecDbBackupBagIdentity *)other +{ + if (_baguuid) + { + other.baguuid = _baguuid; + } + if (_baghash) + { + other.baghash = _baghash; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbBackupBagIdentity *copy = [[[self class] allocWithZone:zone] init]; + copy->_baguuid = [_baguuid copyWithZone:zone]; + copy->_baghash = [_baghash copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbBackupBagIdentity *other = (SecDbBackupBagIdentity *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_baguuid && !other->_baguuid) || [self->_baguuid isEqual:other->_baguuid]) + && + ((!self->_baghash && !other->_baghash) || [self->_baghash isEqual:other->_baghash]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_baguuid hash] + ^ + [self->_baghash hash] + ; +} + +- (void)mergeFrom:(SecDbBackupBagIdentity *)other +{ + if (other->_baguuid) + { + [self setBaguuid:other->_baguuid]; + } + if (other->_baghash) + { + [self setBaghash:other->_baghash]; + } +} + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h new file mode 100644 index 00000000..e3b5c0bc --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h @@ -0,0 +1,58 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION extern "C" +#else +#define SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION extern +#endif + +/** Insert into backupkeyclasssigningkeys table, v12_keyClassSigningKey column */ +@interface SecDbBackupKeyClassSigningKey : PBCodable +{ + NSData *_aksRefKey; + NSData *_aksWrappedKey; + NSData *_backupWrappedKey; + int32_t _keyClass; + NSData *_publicKey; + struct { + int keyClass:1; + } _has; +} + + +@property (nonatomic) BOOL hasKeyClass; +@property (nonatomic) int32_t keyClass; + +@property (nonatomic, readonly) BOOL hasPublicKey; +@property (nonatomic, retain) NSData *publicKey; + +@property (nonatomic, readonly) BOOL hasAksRefKey; +/** Contains bag identity as authenticated data */ +@property (nonatomic, retain) NSData *aksRefKey; + +@property (nonatomic, readonly) BOOL hasAksWrappedKey; +/** SFECIESKeyPair wrapped by AKS ref key */ +@property (nonatomic, retain) NSData *aksWrappedKey; + +@property (nonatomic, readonly) BOOL hasBackupWrappedKey; +/** SFECIESKeyPair wrapped by KCSKSecret in RecoverySet. Also authenticates bag identity */ +@property (nonatomic, retain) NSData *backupWrappedKey; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbBackupKeyClassSigningKey *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbBackupKeyClassSigningKey *)other; + +SECDBBACKUPKEYCLASSSIGNINGKEY_FUNCTION BOOL SecDbBackupKeyClassSigningKeyReadFrom(__unsafe_unretained SecDbBackupKeyClassSigningKey *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m new file mode 100644 index 00000000..b86f63cb --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m @@ -0,0 +1,279 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import "SecDbBackupKeyClassSigningKey.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbBackupKeyClassSigningKey + +@synthesize keyClass = _keyClass; +- (void)setKeyClass:(int32_t)v +{ + _has.keyClass = YES; + _keyClass = v; +} +- (void)setHasKeyClass:(BOOL)f +{ + _has.keyClass = f; +} +- (BOOL)hasKeyClass +{ + return _has.keyClass; +} +- (BOOL)hasPublicKey +{ + return _publicKey != nil; +} +@synthesize publicKey = _publicKey; +- (BOOL)hasAksRefKey +{ + return _aksRefKey != nil; +} +@synthesize aksRefKey = _aksRefKey; +- (BOOL)hasAksWrappedKey +{ + return _aksWrappedKey != nil; +} +@synthesize aksWrappedKey = _aksWrappedKey; +- (BOOL)hasBackupWrappedKey +{ + return _backupWrappedKey != nil; +} +@synthesize backupWrappedKey = _backupWrappedKey; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.keyClass) + { + [dict setObject:[NSNumber numberWithInt:self->_keyClass] forKey:@"keyClass"]; + } + if (self->_publicKey) + { + [dict setObject:self->_publicKey forKey:@"publicKey"]; + } + if (self->_aksRefKey) + { + [dict setObject:self->_aksRefKey forKey:@"aksRefKey"]; + } + if (self->_aksWrappedKey) + { + [dict setObject:self->_aksWrappedKey forKey:@"aksWrappedKey"]; + } + if (self->_backupWrappedKey) + { + [dict setObject:self->_backupWrappedKey forKey:@"backupWrappedKey"]; + } + return dict; +} + +BOOL SecDbBackupKeyClassSigningKeyReadFrom(__unsafe_unretained SecDbBackupKeyClassSigningKey *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* keyClass */: + { + self->_has.keyClass = YES; + self->_keyClass = PBReaderReadInt32(reader); + } + break; + case 3 /* publicKey */: + { + NSData *new_publicKey = PBReaderReadData(reader); + self->_publicKey = new_publicKey; + } + break; + case 4 /* aksRefKey */: + { + NSData *new_aksRefKey = PBReaderReadData(reader); + self->_aksRefKey = new_aksRefKey; + } + break; + case 5 /* aksWrappedKey */: + { + NSData *new_aksWrappedKey = PBReaderReadData(reader); + self->_aksWrappedKey = new_aksWrappedKey; + } + break; + case 6 /* backupWrappedKey */: + { + NSData *new_backupWrappedKey = PBReaderReadData(reader); + self->_backupWrappedKey = new_backupWrappedKey; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbBackupKeyClassSigningKeyReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* keyClass */ + { + if (self->_has.keyClass) + { + PBDataWriterWriteInt32Field(writer, self->_keyClass, 1); + } + } + /* publicKey */ + { + if (self->_publicKey) + { + PBDataWriterWriteDataField(writer, self->_publicKey, 3); + } + } + /* aksRefKey */ + { + if (self->_aksRefKey) + { + PBDataWriterWriteDataField(writer, self->_aksRefKey, 4); + } + } + /* aksWrappedKey */ + { + if (self->_aksWrappedKey) + { + PBDataWriterWriteDataField(writer, self->_aksWrappedKey, 5); + } + } + /* backupWrappedKey */ + { + if (self->_backupWrappedKey) + { + PBDataWriterWriteDataField(writer, self->_backupWrappedKey, 6); + } + } +} + +- (void)copyTo:(SecDbBackupKeyClassSigningKey *)other +{ + if (self->_has.keyClass) + { + other->_keyClass = _keyClass; + other->_has.keyClass = YES; + } + if (_publicKey) + { + other.publicKey = _publicKey; + } + if (_aksRefKey) + { + other.aksRefKey = _aksRefKey; + } + if (_aksWrappedKey) + { + other.aksWrappedKey = _aksWrappedKey; + } + if (_backupWrappedKey) + { + other.backupWrappedKey = _backupWrappedKey; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbBackupKeyClassSigningKey *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.keyClass) + { + copy->_keyClass = _keyClass; + copy->_has.keyClass = YES; + } + copy->_publicKey = [_publicKey copyWithZone:zone]; + copy->_aksRefKey = [_aksRefKey copyWithZone:zone]; + copy->_aksWrappedKey = [_aksWrappedKey copyWithZone:zone]; + copy->_backupWrappedKey = [_backupWrappedKey copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbBackupKeyClassSigningKey *other = (SecDbBackupKeyClassSigningKey *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.keyClass && other->_has.keyClass && self->_keyClass == other->_keyClass) || (!self->_has.keyClass && !other->_has.keyClass)) + && + ((!self->_publicKey && !other->_publicKey) || [self->_publicKey isEqual:other->_publicKey]) + && + ((!self->_aksRefKey && !other->_aksRefKey) || [self->_aksRefKey isEqual:other->_aksRefKey]) + && + ((!self->_aksWrappedKey && !other->_aksWrappedKey) || [self->_aksWrappedKey isEqual:other->_aksWrappedKey]) + && + ((!self->_backupWrappedKey && !other->_backupWrappedKey) || [self->_backupWrappedKey isEqual:other->_backupWrappedKey]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.keyClass ? PBHashInt((NSUInteger)self->_keyClass) : 0) + ^ + [self->_publicKey hash] + ^ + [self->_aksRefKey hash] + ^ + [self->_aksWrappedKey hash] + ^ + [self->_backupWrappedKey hash] + ; +} + +- (void)mergeFrom:(SecDbBackupKeyClassSigningKey *)other +{ + if (other->_has.keyClass) + { + self->_keyClass = other->_keyClass; + self->_has.keyClass = YES; + } + if (other->_publicKey) + { + [self setPublicKey:other->_publicKey]; + } + if (other->_aksRefKey) + { + [self setAksRefKey:other->_aksRefKey]; + } + if (other->_aksWrappedKey) + { + [self setAksWrappedKey:other->_aksWrappedKey]; + } + if (other->_backupWrappedKey) + { + [self setBackupWrappedKey:other->_backupWrappedKey]; + } +} + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h new file mode 100644 index 00000000..b967187f --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h @@ -0,0 +1,44 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBBACKUPMETADATACLASSKEY_FUNCTION extern "C" +#else +#define SECDBBACKUPMETADATACLASSKEY_FUNCTION extern +#endif + +/** Insert into metadatakeys table, v12_metadatakeydata column */ +@interface SecDbBackupMetadataClassKey : PBCodable +{ + NSData *_backupWrappedMetadataKey; + int32_t _keyClass; + struct { + int keyClass:1; + } _has; +} + + +@property (nonatomic) BOOL hasKeyClass; +@property (nonatomic) int32_t keyClass; + +@property (nonatomic, readonly) BOOL hasBackupWrappedMetadataKey; +/** wrapped by appropriate backup keyclass for recovery */ +@property (nonatomic, retain) NSData *backupWrappedMetadataKey; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbBackupMetadataClassKey *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbBackupMetadataClassKey *)other; + +SECDBBACKUPMETADATACLASSKEY_FUNCTION BOOL SecDbBackupMetadataClassKeyReadFrom(__unsafe_unretained SecDbBackupMetadataClassKey *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m new file mode 100644 index 00000000..eae21ba4 --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m @@ -0,0 +1,174 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import "SecDbBackupMetadataClassKey.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbBackupMetadataClassKey + +@synthesize keyClass = _keyClass; +- (void)setKeyClass:(int32_t)v +{ + _has.keyClass = YES; + _keyClass = v; +} +- (void)setHasKeyClass:(BOOL)f +{ + _has.keyClass = f; +} +- (BOOL)hasKeyClass +{ + return _has.keyClass; +} +- (BOOL)hasBackupWrappedMetadataKey +{ + return _backupWrappedMetadataKey != nil; +} +@synthesize backupWrappedMetadataKey = _backupWrappedMetadataKey; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.keyClass) + { + [dict setObject:[NSNumber numberWithInt:self->_keyClass] forKey:@"keyClass"]; + } + if (self->_backupWrappedMetadataKey) + { + [dict setObject:self->_backupWrappedMetadataKey forKey:@"backupWrappedMetadataKey"]; + } + return dict; +} + +BOOL SecDbBackupMetadataClassKeyReadFrom(__unsafe_unretained SecDbBackupMetadataClassKey *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* keyClass */: + { + self->_has.keyClass = YES; + self->_keyClass = PBReaderReadInt32(reader); + } + break; + case 2 /* backupWrappedMetadataKey */: + { + NSData *new_backupWrappedMetadataKey = PBReaderReadData(reader); + self->_backupWrappedMetadataKey = new_backupWrappedMetadataKey; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbBackupMetadataClassKeyReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* keyClass */ + { + if (self->_has.keyClass) + { + PBDataWriterWriteInt32Field(writer, self->_keyClass, 1); + } + } + /* backupWrappedMetadataKey */ + { + if (self->_backupWrappedMetadataKey) + { + PBDataWriterWriteDataField(writer, self->_backupWrappedMetadataKey, 2); + } + } +} + +- (void)copyTo:(SecDbBackupMetadataClassKey *)other +{ + if (self->_has.keyClass) + { + other->_keyClass = _keyClass; + other->_has.keyClass = YES; + } + if (_backupWrappedMetadataKey) + { + other.backupWrappedMetadataKey = _backupWrappedMetadataKey; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbBackupMetadataClassKey *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.keyClass) + { + copy->_keyClass = _keyClass; + copy->_has.keyClass = YES; + } + copy->_backupWrappedMetadataKey = [_backupWrappedMetadataKey copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbBackupMetadataClassKey *other = (SecDbBackupMetadataClassKey *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.keyClass && other->_has.keyClass && self->_keyClass == other->_keyClass) || (!self->_has.keyClass && !other->_has.keyClass)) + && + ((!self->_backupWrappedMetadataKey && !other->_backupWrappedMetadataKey) || [self->_backupWrappedMetadataKey isEqual:other->_backupWrappedMetadataKey]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.keyClass ? PBHashInt((NSUInteger)self->_keyClass) : 0) + ^ + [self->_backupWrappedMetadataKey hash] + ; +} + +- (void)mergeFrom:(SecDbBackupMetadataClassKey *)other +{ + if (other->_has.keyClass) + { + self->_keyClass = other->_keyClass; + self->_has.keyClass = YES; + } + if (other->_backupWrappedMetadataKey) + { + [self setBackupWrappedMetadataKey:other->_backupWrappedMetadataKey]; + } +} + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h new file mode 100644 index 00000000..13490afc --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h @@ -0,0 +1,63 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import +#import + +@class SecDbBackupBagIdentity; + +#ifdef __cplusplus +#define SECDBBACKUPRECOVERYSET_FUNCTION extern "C" +#else +#define SECDBBACKUPRECOVERYSET_FUNCTION extern +#endif + +/** + * optional bytes aksWrappedMetadataKey = 3; // wrapped by device bag for daily use. Not in use right now. + * Insert into backuprecoverysets table, v12_recoverySet column + */ +@interface SecDbBackupRecoverySet : PBCodable +{ + SecDbBackupBagIdentity *_bagIdentity; + int32_t _recoveryType; + NSData *_wrappedBagSecret; + NSData *_wrappedKCSKSecret; + NSData *_wrappedRecoveryKey; + struct { + int recoveryType:1; + } _has; +} + + +@property (nonatomic) BOOL hasRecoveryType; +@property (nonatomic) int32_t recoveryType; + +@property (nonatomic, readonly) BOOL hasBagIdentity; +@property (nonatomic, retain) SecDbBackupBagIdentity *bagIdentity; + +@property (nonatomic, readonly) BOOL hasWrappedBagSecret; +/** 'passphrase' to unlock backup bag's private keys */ +@property (nonatomic, retain) NSData *wrappedBagSecret; + +@property (nonatomic, readonly) BOOL hasWrappedKCSKSecret; +/** recovers KCSKs to verify authenticity of IKs and MCKs */ +@property (nonatomic, retain) NSData *wrappedKCSKSecret; + +@property (nonatomic, readonly) BOOL hasWrappedRecoveryKey; +/** wraps the above two secrets */ +@property (nonatomic, retain) NSData *wrappedRecoveryKey; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbBackupRecoverySet *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbBackupRecoverySet *)other; + +SECDBBACKUPRECOVERYSET_FUNCTION BOOL SecDbBackupRecoverySetReadFrom(__unsafe_unretained SecDbBackupRecoverySet *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m new file mode 100644 index 00000000..1621b0d2 --- /dev/null +++ b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m @@ -0,0 +1,297 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbBackupRecoverySet.proto + +#import "SecDbBackupRecoverySet.h" +#import +#import +#import + +#import "SecDbBackupBagIdentity.h" + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbBackupRecoverySet + +@synthesize recoveryType = _recoveryType; +- (void)setRecoveryType:(int32_t)v +{ + _has.recoveryType = YES; + _recoveryType = v; +} +- (void)setHasRecoveryType:(BOOL)f +{ + _has.recoveryType = f; +} +- (BOOL)hasRecoveryType +{ + return _has.recoveryType; +} +- (BOOL)hasBagIdentity +{ + return _bagIdentity != nil; +} +@synthesize bagIdentity = _bagIdentity; +- (BOOL)hasWrappedBagSecret +{ + return _wrappedBagSecret != nil; +} +@synthesize wrappedBagSecret = _wrappedBagSecret; +- (BOOL)hasWrappedKCSKSecret +{ + return _wrappedKCSKSecret != nil; +} +@synthesize wrappedKCSKSecret = _wrappedKCSKSecret; +- (BOOL)hasWrappedRecoveryKey +{ + return _wrappedRecoveryKey != nil; +} +@synthesize wrappedRecoveryKey = _wrappedRecoveryKey; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.recoveryType) + { + [dict setObject:[NSNumber numberWithInt:self->_recoveryType] forKey:@"recoveryType"]; + } + if (self->_bagIdentity) + { + [dict setObject:[_bagIdentity dictionaryRepresentation] forKey:@"bagIdentity"]; + } + if (self->_wrappedBagSecret) + { + [dict setObject:self->_wrappedBagSecret forKey:@"wrappedBagSecret"]; + } + if (self->_wrappedKCSKSecret) + { + [dict setObject:self->_wrappedKCSKSecret forKey:@"wrappedKCSKSecret"]; + } + if (self->_wrappedRecoveryKey) + { + [dict setObject:self->_wrappedRecoveryKey forKey:@"wrappedRecoveryKey"]; + } + return dict; +} + +BOOL SecDbBackupRecoverySetReadFrom(__unsafe_unretained SecDbBackupRecoverySet *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* recoveryType */: + { + self->_has.recoveryType = YES; + self->_recoveryType = PBReaderReadInt32(reader); + } + break; + case 2 /* bagIdentity */: + { + SecDbBackupBagIdentity *new_bagIdentity = [[SecDbBackupBagIdentity alloc] init]; + self->_bagIdentity = new_bagIdentity; + PBDataReaderMark mark_bagIdentity; + BOOL markError = !PBReaderPlaceMark(reader, &mark_bagIdentity); + if (markError) + { + return NO; + } + BOOL inError = !SecDbBackupBagIdentityReadFrom(new_bagIdentity, reader); + if (inError) + { + return NO; + } + PBReaderRecallMark(reader, &mark_bagIdentity); + } + break; + case 3 /* wrappedBagSecret */: + { + NSData *new_wrappedBagSecret = PBReaderReadData(reader); + self->_wrappedBagSecret = new_wrappedBagSecret; + } + break; + case 4 /* wrappedKCSKSecret */: + { + NSData *new_wrappedKCSKSecret = PBReaderReadData(reader); + self->_wrappedKCSKSecret = new_wrappedKCSKSecret; + } + break; + case 5 /* wrappedRecoveryKey */: + { + NSData *new_wrappedRecoveryKey = PBReaderReadData(reader); + self->_wrappedRecoveryKey = new_wrappedRecoveryKey; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbBackupRecoverySetReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* recoveryType */ + { + if (self->_has.recoveryType) + { + PBDataWriterWriteInt32Field(writer, self->_recoveryType, 1); + } + } + /* bagIdentity */ + { + if (self->_bagIdentity != nil) + { + PBDataWriterWriteSubmessage(writer, self->_bagIdentity, 2); + } + } + /* wrappedBagSecret */ + { + if (self->_wrappedBagSecret) + { + PBDataWriterWriteDataField(writer, self->_wrappedBagSecret, 3); + } + } + /* wrappedKCSKSecret */ + { + if (self->_wrappedKCSKSecret) + { + PBDataWriterWriteDataField(writer, self->_wrappedKCSKSecret, 4); + } + } + /* wrappedRecoveryKey */ + { + if (self->_wrappedRecoveryKey) + { + PBDataWriterWriteDataField(writer, self->_wrappedRecoveryKey, 5); + } + } +} + +- (void)copyTo:(SecDbBackupRecoverySet *)other +{ + if (self->_has.recoveryType) + { + other->_recoveryType = _recoveryType; + other->_has.recoveryType = YES; + } + if (_bagIdentity) + { + other.bagIdentity = _bagIdentity; + } + if (_wrappedBagSecret) + { + other.wrappedBagSecret = _wrappedBagSecret; + } + if (_wrappedKCSKSecret) + { + other.wrappedKCSKSecret = _wrappedKCSKSecret; + } + if (_wrappedRecoveryKey) + { + other.wrappedRecoveryKey = _wrappedRecoveryKey; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbBackupRecoverySet *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.recoveryType) + { + copy->_recoveryType = _recoveryType; + copy->_has.recoveryType = YES; + } + copy->_bagIdentity = [_bagIdentity copyWithZone:zone]; + copy->_wrappedBagSecret = [_wrappedBagSecret copyWithZone:zone]; + copy->_wrappedKCSKSecret = [_wrappedKCSKSecret copyWithZone:zone]; + copy->_wrappedRecoveryKey = [_wrappedRecoveryKey copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbBackupRecoverySet *other = (SecDbBackupRecoverySet *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.recoveryType && other->_has.recoveryType && self->_recoveryType == other->_recoveryType) || (!self->_has.recoveryType && !other->_has.recoveryType)) + && + ((!self->_bagIdentity && !other->_bagIdentity) || [self->_bagIdentity isEqual:other->_bagIdentity]) + && + ((!self->_wrappedBagSecret && !other->_wrappedBagSecret) || [self->_wrappedBagSecret isEqual:other->_wrappedBagSecret]) + && + ((!self->_wrappedKCSKSecret && !other->_wrappedKCSKSecret) || [self->_wrappedKCSKSecret isEqual:other->_wrappedKCSKSecret]) + && + ((!self->_wrappedRecoveryKey && !other->_wrappedRecoveryKey) || [self->_wrappedRecoveryKey isEqual:other->_wrappedRecoveryKey]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.recoveryType ? PBHashInt((NSUInteger)self->_recoveryType) : 0) + ^ + [self->_bagIdentity hash] + ^ + [self->_wrappedBagSecret hash] + ^ + [self->_wrappedKCSKSecret hash] + ^ + [self->_wrappedRecoveryKey hash] + ; +} + +- (void)mergeFrom:(SecDbBackupRecoverySet *)other +{ + if (other->_has.recoveryType) + { + self->_recoveryType = other->_recoveryType; + self->_has.recoveryType = YES; + } + if (self->_bagIdentity && other->_bagIdentity) + { + [self->_bagIdentity mergeFrom:other->_bagIdentity]; + } + else if (!self->_bagIdentity && other->_bagIdentity) + { + [self setBagIdentity:other->_bagIdentity]; + } + if (other->_wrappedBagSecret) + { + [self setWrappedBagSecret:other->_wrappedBagSecret]; + } + if (other->_wrappedKCSKSecret) + { + [self setWrappedKCSKSecret:other->_wrappedKCSKSecret]; + } + if (other->_wrappedRecoveryKey) + { + [self setWrappedRecoveryKey:other->_wrappedRecoveryKey]; + } +} + +@end + diff --git a/keychain/securityd/SecDbBackupManager.h b/keychain/securityd/SecDbBackupManager.h new file mode 100644 index 00000000..2459ad75 --- /dev/null +++ b/keychain/securityd/SecDbBackupManager.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// For now at least, we'll support backups only on iOS and macOS +#define SECDB_BACKUPS_ENABLED ((TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_IOSMAC) && !TARGET_OS_SIMULATOR && !TARGET_DARWINOS) + +#if __OBJC2__ +#import +#if !TARGET_OS_BRIDGE // Specifically needed until rdar://problem/40583882 lands +#import +#endif +#import "SecAKSObjCWrappers.h" +#import "CheckV12DevEnabled.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, SecDbBackupRecoveryType) { + SecDbBackupRecoveryTypeInvalid = -1, + SecDbBackupRecoveryTypeAKS = 1, + SecDbBackupRecoveryTypeCylon = 2, + SecDbBackupRecoveryTypeRecoveryKey = 3, +}; + +extern NSString* const KeychainBackupsErrorDomain; + +typedef NS_ENUM(NSInteger, SecDbBackupErrorCode) { + SecDbBackupUnknownError = -1, + SecDbBackupSuccess = 0, + SecDbBackupAKSFailure, + SecDbBackupCryptoFailure, + SecDbBackupWriteFailure, + SecDbBackupDeserializationFailure, + SecDbBackupSetupFailure, + SecDbBackupNoBackupBagFound, + SecDbBackupNoKCSKFound, + SecDbBackupDuplicateBagFound, + SecDbBackupMultipleDefaultBagsFound, + SecDbBackupMalformedBagDataOnDisk, + SecDbBackupMalformedKCSKDataOnDisk, + SecDbBackupMalformedUUIDDataOnDisk, + SecDbBackupUUIDMismatch, + SecDbBackupDataMismatch, + SecDbBackupUnknownOption, + SecDbBackupKeychainLocked, + SecDbBackupInvalidArgument, + SecDbBackupNotSupported, + SecDbBackupInternalError, + + SecDbBackupTestCodeFailure = 255, // support code for testing is falling over somehow +}; + +@interface SecDbBackupWrappedItemKey : NSObject +@property (nonatomic) NSData* wrappedKey; +@property (nonatomic) NSData* baguuid; +@end + +@interface SecDbBackupManager : NSObject + ++ (instancetype)manager; +- (instancetype)init NS_UNAVAILABLE; + +#if !TARGET_OS_BRIDGE // Specifically needed until rdar://problem/40583882 lands +- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error; +#else +- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error; +#endif + +- (void)verifyBackupIntegrity:(bool)lightweight + completion:(void (^)(NSDictionary* results, NSError* _Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END +#endif // __OBJC2__ + +// Declare C functions here + +bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef _Nullable * _Nonnull error); diff --git a/keychain/securityd/SecDbBackupManager.m b/keychain/securityd/SecDbBackupManager.m new file mode 100644 index 00000000..ff4dc45a --- /dev/null +++ b/keychain/securityd/SecDbBackupManager.m @@ -0,0 +1,1055 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SecDbBackupManager.h" + +NSString* const KeychainBackupsErrorDomain = @"com.apple.security.keychain.backups"; + +// oink oink +@implementation SecDbBackupWrappedItemKey ++ (BOOL)supportsSecureCoding { + return YES; +} +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.wrappedKey forKey:@"wrappedKey"]; + [coder encodeObject:self.baguuid forKey:@"baguuid"]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + if (self = [super init]) { + _wrappedKey = [coder decodeObjectOfClass:[NSData class] forKey:@"wrappedKey"]; + _baguuid = [coder decodeObjectOfClass:[NSData class] forKey:@"baguuid"]; + } + return self; +} +@end + +#if !SECDB_BACKUPS_ENABLED + +@implementation SecDbBackupManager + ++ (instancetype)manager +{ + return nil; +} + +- (void)verifyBackupIntegrity:(bool)lightweight + completion:(void (^)(NSDictionary* results, NSError* _Nullable error))completion +{ + completion(nil, [NSError errorWithDomain:KeychainBackupsErrorDomain + code:SecDbBackupNotSupported + userInfo:@{NSLocalizedDescriptionKey : @"platform doesn't do backups"}]); +} + +- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error +{ + return nil; +} + +@end + +bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error) +{ + return true; +} + +#else // SECDB_BACKUPS_ENABLED is true, roll out the code + +#import "SecDbBackupManager_Internal.h" +#include +#import +#import "SecItemServer.h" +#import "SecItemDb.h" +#import "keychain/categories/NSError+UsefulConstructors.h" +#import "sec_action.h" +#import "SecItemServer.h" +#include "utilities/der_plist.h" + +// TODO: fire off metric on outcome +bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error) +{ + NSError* localError; + bool ok = [[SecDbBackupManager manager] createOrLoadBackupInfrastructure:&localError]; + if (!ok) { + // Translate this to intelligible constant in C, but other errors can be passed along + if (localError.code == SecDbBackupKeychainLocked) { + *error = CFErrorCreate(kCFAllocatorDefault, kSecErrorDomain, errSecInteractionNotAllowed, NULL); + } else { + *error = (CFErrorRef)CFBridgingRetain(localError); + } + } + return ok; +} + +// Reading from disk is relatively expensive. Keep wrapped key in memory and just delete the unwrapped copy on lock +@interface InMemoryKCSK : NSObject +@property aks_ref_key_t refKey; +@property (nonatomic) NSData* wrappedKey; +@property (nonatomic) SFECKeyPair* key; +@end + +@implementation InMemoryKCSK +- (void)dealloc +{ + if (_refKey) { + free(_refKey); + } +} + ++ (instancetype)kcskWithRefKey:(aks_ref_key_t)refKey wrappedKey:(NSData*)wrappedKey key:(SFECKeyPair*)key +{ + InMemoryKCSK* kcsk = [InMemoryKCSK new]; + kcsk.refKey = refKey; + kcsk.wrappedKey = wrappedKey; + kcsk.key = key; + return kcsk; +} + +@end + +@interface SecDbBackupManager () { + dispatch_queue_t _queue; + keybag_handle_t _handle; + SecDbBackupBagIdentity* _bagIdentity; + NSMutableDictionary* _cachedKCSKs; +} +@end + +@implementation SecDbBackupManager + +#pragma mark - Misc Helpers + +- (NSData*)getSHA256OfData:(NSData*)data +{ + NSMutableData* digest = [[NSMutableData alloc] initWithLength:CC_SHA512_DIGEST_LENGTH]; + if (!CC_SHA512(data.bytes, (CC_LONG)data.length, digest.mutableBytes)) { + return nil; + } + return digest; +} + +- (void)setBagIdentity:(SecDbBackupBagIdentity *)bagIdentity +{ + _bagIdentity = bagIdentity; +} + +- (SecDbBackupBagIdentity*)bagIdentity +{ + return _bagIdentity; +} + +- (bool)fillError:(NSError**)error code:(enum SecDbBackupErrorCode)code underlying:(NSError*)underlying description:(NSString*)format, ... NS_FORMAT_FUNCTION(4, 5) +{ + if (error) { + va_list ap; + va_start(ap, format); + NSString* desc = [[NSString alloc] initWithFormat:format arguments:ap]; + va_end(ap); + if (underlying) { + *error = [NSError errorWithDomain:KeychainBackupsErrorDomain code:code description:desc underlying:underlying]; + } else { + *error = [NSError errorWithDomain:KeychainBackupsErrorDomain code:code description:desc]; + } + } + + // analyzer gets upset when a method taking an error** doesn't return a value + return true; +} + +static SecDbBackupManager* staticManager; ++ (instancetype)manager +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + staticManager = [SecDbBackupManager new]; + }); + return staticManager; +} + +// Testing only please ++ (void)resetManager +{ + if (staticManager) { + staticManager = [SecDbBackupManager new]; + } +} + +- (instancetype)init +{ + if (!checkV12DevEnabled()) { + return nil; + } + if (self = [super init]) { + _queue = dispatch_queue_create("com.apple.security.secdbbackupmanager", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + _handle = bad_keybag_handle; + _cachedKCSKs = [NSMutableDictionary new]; + } + return self; +} + +- (SFECKeyPair*)getECKeyPairFromDERBytes:(void*)bytes length:(size_t)len error:(NSError**)error +{ + if (!bytes || len == 0) { + [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Need valid byte buffer to make EC keypair from"]; + return nil; + } + CFTypeRef cftype = NULL; + CFErrorRef cferr = NULL; + const uint8_t* derp = der_decode_plist(kCFAllocatorDefault, NSPropertyListImmutable, &cftype, &cferr, bytes, bytes + len); + free(bytes); + if (derp == NULL || derp != (bytes + len) || cftype == NULL) { + [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:CFBridgingRelease(cferr) description:@"Unable to parse der data"]; + return nil; + } + + return [[SFECKeyPair alloc] initWithData:(__bridge_transfer NSData*)cftype + specifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384] + error:error]; +} + +#pragma mark - Fixup And Verification + +- (void)verifyBackupIntegrity:(bool)lightweight + completion:(void (^)(NSDictionary* _Nonnull, NSError * _Nullable))completion +{ + NSError* error = nil; + completion(@{@"summary" : @"Unimplemented"}, error); +} + +#pragma mark - Backup Bag Management + +// Get the bag's UUID from AKS and the hash from provided data. This must always be the original bag's data +- (SecDbBackupBagIdentity*)bagIdentityWithHandle:(keybag_handle_t)handle data:(NSData*)data error:(NSError**)error { + assert(data); + secnotice("SecDbBackup", "Getting bag identity"); + SecDbBackupBagIdentity* identity = [SecDbBackupBagIdentity new]; + + uuid_t uuid = {0}; + kern_return_t aksResult = aks_get_bag_uuid(handle, uuid); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to get keybag UUID (%d)", aksResult]; + return nil; + } + identity.baguuid = [NSData dataWithBytes:uuid length:16]; + + NSData* digest = [self getSHA256OfData:data]; + if (!digest) { + [self fillError:error code:SecDbBackupCryptoFailure underlying:nil description:@"CC_SHA512 returned failure, can't get bag hash"]; + return nil; + } + identity.baghash = digest; + + secnotice("SecDbBackup", "Obtained bag identity: %@", identity); + + return identity; +} + +- (NSData*)createBackupBagSecret:(NSError**)error +{ + uint8_t* data = calloc(1, BACKUPBAG_PASSPHRASE_LENGTH); + if (!data) { + return nil; // Good luck allocating an error message + } + + CCRNGStatus rngResult = CCRandomGenerateBytes(data, BACKUPBAG_PASSPHRASE_LENGTH); + if (rngResult != kCCSuccess) { + [self fillError:error code:SecDbBackupCryptoFailure underlying:nil description:@"Unable to generate random bytes (%d)", rngResult]; + return nil; + } + + NSData* secret = [NSData _newZeroingDataWithBytesNoCopy:data length:BACKUPBAG_PASSPHRASE_LENGTH deallocator:NSDataDeallocatorNone]; + return secret; +} + +- (keybag_handle_t)onQueueCreateBackupBagWithSecret:(NSData*)secret error:(NSError**)error +{ + dispatch_assert_queue(_queue); + + keybag_handle_t handle = bad_keybag_handle; + kern_return_t aksresult = aks_create_bag(secret.bytes, BACKUPBAG_PASSPHRASE_LENGTH, kAppleKeyStoreAsymmetricBackupBag, &handle); + if (aksresult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to create keybag (%d)", aksresult]; + return bad_keybag_handle; + } + + // Make secret keys unavailable. Causes pubkeys to be destroyed so reload bag before use + aksresult = aks_lock_bag(handle); + if (aksresult != kAKSReturnSuccess) { // This would be rather surprising + [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to lock keybag (%d)", aksresult]; + aks_unload_bag(handle); + return bad_keybag_handle; + } + + return handle; +} + +- (BOOL)onQueueInTransaction:(SecDbConnectionRef)dbt saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error +{ + dispatch_assert_queue(_queue); + + void* buf = NULL; + int buflen = 0; + kern_return_t aksResult = aks_save_bag(handle, &buf, &buflen); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to serialize keybag (%d)", aksResult]; + return NO; + } + NSData* bagData = [NSData dataWithBytesNoCopy:buf length:buflen]; + + SecDbBackupBagIdentity* bagIdentity = [self bagIdentityWithHandle:handle data:bagData error:error]; + if (!bagIdentity) { + return NO; + } + SecDbBackupBag* bag = [SecDbBackupBag new]; + bag.bagIdentity = bagIdentity; + bag.keybag = bagData; + + __block CFErrorRef cfError = NULL; + __block bool ok = true; + if (asDefault) { + ok &= SecDbPrepare(dbt, CFSTR("UPDATE backupbags SET defaultvalue = 0 WHERE defaultvalue = 1"), &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { + // FIXME: Should this be an error? Should something else happen? + secwarning("SecDbBackup: Marking existing bag as non-default"); + }); + }); + } + if (!ok) { + return ok; + } + ok &= SecDbPrepare(dbt, CFSTR("INSERT INTO backupbags (backupUUID, backupbag, defaultvalue) VALUES (?,?,?)"), &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbBindObject(stmt, 1, (__bridge CFDataRef)bag.bagIdentity.baguuid, &cfError); + ok &= SecDbBindObject(stmt, 2, (__bridge CFDataRef)bag.data, &cfError); + ok &= SecDbBindInt(stmt, 3, asDefault ? 1 : 0, &cfError); + ok &= SecDbStep(dbt, stmt, &cfError, NULL); + }); + + if (!ok) { + secerror("SecDbBackup: unable to save keybag to disk: %@", cfError); + [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to save keybag to disk"]; + } + + return ok; +} + +- (keybag_handle_t)onQueueLoadBackupBag:(NSUUID*)uuid error:(NSError**)error { + dispatch_assert_queue(_queue); + + secnotice("SecDbBackup", "Attempting to load backup bag from disk"); + + __block CFErrorRef localErr = NULL; + __block bool ok = true; + __block NSData* readUUID; + __block NSData* readBagData; + __block unsigned found = 0; + ok &= kc_with_dbt_non_item_tables(false, &localErr, ^bool(SecDbConnectionRef dbt) { + NSString* sql = [NSString stringWithFormat:@"SELECT backupUUID, backupbag FROM backupbags WHERE %@", uuid ? @"backupUUID = ?" : @"defaultvalue = 1"]; + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &localErr, ^(sqlite3_stmt *stmt) { + if (uuid) { + unsigned char uuidbytes[UUIDBYTESLENGTH] = {0}; + [uuid getUUIDBytes:uuidbytes]; + ok &= SecDbBindBlob(stmt, 1, uuidbytes, UUIDBYTESLENGTH, SQLITE_TRANSIENT, &localErr); + } + ok &= SecDbStep(dbt, stmt, &localErr, ^(bool *stop) { + if (found > 0) { // For uuids this should have violated constraints + secerror("Encountered more than one backup bag by %@", uuid ? @"backupUUID" : @"defaultvalue"); + *stop = true; + } + readUUID = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; + readBagData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)]; + ++found; + }); + }); + return ok; + }); + + if (!ok) { + secerror("SecDbBackup: Unable to load backup bag from disk: %@", localErr); + [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(localErr) description:@"Unable to load backup bag from disk"]; + return bad_keybag_handle; + } + + if (!found) { + [self fillError:error code:SecDbBackupNoBackupBagFound underlying:nil description:@"No backup bag found to load from disk"]; + return bad_keybag_handle; + } else if (found > 1) { + [self fillError:error + code:uuid ? SecDbBackupDuplicateBagFound : SecDbBackupMultipleDefaultBagsFound + underlying:nil + description:@"More than one backup bag found"]; + return bad_keybag_handle; + } + + if (!readUUID || readUUID.length != UUIDBYTESLENGTH || !readBagData || !readBagData.length) { + [self fillError:error code:SecDbBackupMalformedBagDataOnDisk underlying:nil description:@"bags read from disk malformed"]; + return bad_keybag_handle; + } + + SecDbBackupBag* readBag = [[SecDbBackupBag alloc] initWithData:readBagData]; + if (!readBag) { + [self fillError:error code:SecDbBackupDeserializationFailure underlying:nil description:@"bag from disk does not deserialize"]; + return bad_keybag_handle; + } + + secnotice("SecDbBackup", "Successfully read backup bag from disk; loading and verifying. Read bag ID: %@", readBag.bagIdentity); + + keybag_handle_t handle = bad_keybag_handle; + kern_return_t aksResult = aks_load_bag(readBag.keybag.bytes, (int)readBag.keybag.length, &handle); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil description:@"Unable to load bag from disk (%d)", aksResult]; + return bad_keybag_handle; + } + + SecDbBackupBagIdentity* loadedID = [self bagIdentityWithHandle:handle data:readBag.keybag error:error]; + if (!loadedID) { + aks_unload_bag(handle); + return bad_keybag_handle; + } + + if (memcmp(loadedID.baguuid.bytes, readBag.bagIdentity.baguuid.bytes, UUIDBYTESLENGTH) || + memcmp(loadedID.baguuid.bytes, readUUID.bytes, UUIDBYTESLENGTH)) { + [self fillError:error code:SecDbBackupUUIDMismatch underlying:nil description:@"Loaded UUID does not match UUIDs on disk"]; + aks_unload_bag(handle); + return bad_keybag_handle; + } + + if (memcmp(loadedID.baghash.bytes, readBag.bagIdentity.baghash.bytes, CC_SHA512_DIGEST_LENGTH)) { + [self fillError:error code:SecDbBackupDeserializationFailure underlying:nil description:@"Keybag hash does not match its identity's hash"]; + return bad_keybag_handle; + } + + // TODO: verify that bag is still signed, rdar://problem/46702467 + + secnotice("SecDbBackup", "Backup bag loaded and verified."); + + // Must load readBag's identity because the hash from AKS is unstable. + // This is the hash of the original saved bag and is anchored in the KCSKes. + _bagIdentity = readBag.bagIdentity; + + return handle; +} + +- (BOOL)onQueueReloadDefaultBackupBagWithError:(NSError**)error +{ + if (_handle != bad_keybag_handle) { + aks_unload_bag(_handle); + } + + _handle = [self onQueueLoadBackupBag:nil error:error]; + return _handle != bad_keybag_handle; +} + +#pragma mark - KCSK Management + +- (SecDbBackupKeyClassSigningKey*)createKCSKForKeyClass:(keyclass_t)class withWrapper:(SFAESKey*)wrapper error:(NSError**)error +{ + if (!wrapper) { + [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Need wrapper for KCSK"]; + return nil; + } + + SecDbBackupKeyClassSigningKey* kcsk = [SecDbBackupKeyClassSigningKey new]; + kcsk.keyClass = class; + + SFECKeyPair* keypair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; + kcsk.publicKey = [keypair.publicKey.keyData copy]; + + // Create a DER-encoded dictionary of bag identity + void* der_blob; + size_t der_len; + CFErrorRef cfErr = NULL; + NSDictionary* identDict = @{@"baguuid" : _bagIdentity.baguuid, @"baghash" : _bagIdentity.baghash}; + NSData* identData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)identDict, &cfErr); + aks_operation_optional_params(NULL, 0, identData.bytes, identData.length, NULL, 0, &der_blob, &der_len); + + // Create ref key with embedded bag identity DER data + aks_ref_key_t refkey = NULL; + kern_return_t aksResult = aks_ref_key_create(KEYBAG_DEVICE, class, key_type_sym, der_blob, der_len, &refkey); + free(der_blob); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil + description:@"Unable to create AKS ref key for KCSK class %d: %d", class, aksResult]; + return nil; + } + + size_t refkeyblobsize = 0; + const uint8_t* refkeyblob = aks_ref_key_get_blob(refkey, &refkeyblobsize); + kcsk.aksRefKey = [NSData dataWithBytes:refkeyblob length:refkeyblobsize]; + + size_t wrappedKeyLen = 0; + void* wrappedKey = NULL; + NSData* keypairAsData = keypair.keyData; + aksResult = aks_ref_key_encrypt(refkey, NULL, 0, keypairAsData.bytes, keypairAsData.length, &wrappedKey, &wrappedKeyLen); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error code:SecDbBackupAKSFailure underlying:nil + description:@"Unable to encrypt KCSK class %d with AKS ref key: %d", class, aksResult]; + return nil; + } + aks_ref_key_free(&refkey); + kcsk.aksWrappedKey = [NSData dataWithBytesNoCopy:wrappedKey length:wrappedKeyLen]; + + // Also add DER-encoded bag identity here + SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]]; + SFAuthenticatedCiphertext* backupwrapped = [op encrypt:keypair.keyData withKey:wrapper additionalAuthenticatedData:identData error:error]; + kcsk.backupWrappedKey = [NSKeyedArchiver archivedDataWithRootObject:backupwrapped requiringSecureCoding:YES error:error]; + if (!kcsk.backupWrappedKey) { + return nil; + } + + return kcsk; +} + +- (BOOL)inTransaction:(SecDbConnectionRef)dbt writeKCSKToKeychain:(SecDbBackupKeyClassSigningKey*)kcsk error:(NSError**)error +{ + __block bool ok = true; + __block CFErrorRef cfError = NULL; + NSString* sql = @"INSERT INTO backupkeyclasssigningkeys (keyclass, backupUUID, signingkey) VALUES (?, ?, ?)"; + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbBindInt(stmt, 1, kcsk.keyClass, &cfError); + ok &= SecDbBindObject(stmt, 2, (__bridge CFTypeRef)(self->_bagIdentity.baguuid), &cfError); + ok &= SecDbBindObject(stmt, 3, (__bridge CFTypeRef)(kcsk.data), &cfError); + ok &= SecDbStep(dbt, stmt, &cfError, NULL); + }); + + if (!ok) { + secerror("SecDbBackup: Unable to write KCSK for class %d to keychain: %@", kcsk.keyClass, cfError); + [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to write KCSK for class %d to keychain", kcsk.keyClass]; + } + + return ok; +} + +- (InMemoryKCSK*)onQueueReadKCSKFromDiskForClass:(keyclass_t)keyclass error:(NSError**)error +{ + __block bool ok = true; + __block CFErrorRef cfError = NULL; + __block NSData* readUUID; + __block NSData* readKCSK; + NSString* sql = @"SELECT backupUUID, signingkey FROM backupkeyclasssigningkeys WHERE keyclass = ?"; + ok &= kc_with_dbt_non_item_tables(NO, &cfError, ^bool(SecDbConnectionRef dbt) { + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbBindInt(stmt, 1, keyclass, &cfError); + ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { + readUUID = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; + readKCSK = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 1) length:sqlite3_column_bytes(stmt, 1)]; + }); + }); + return ok; + }); + if (!readKCSK || !readUUID) { + [self fillError:error code:SecDbBackupNoKCSKFound underlying:nil description:@"KCSK for class %d not on disk", keyclass]; + return nil; + } + + SecDbBackupKeyClassSigningKey* kcsk = [[SecDbBackupKeyClassSigningKey alloc] initWithData:readKCSK]; + if (!kcsk) { + [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:nil description:@"Retrieved KCSK blob but it didn't become a KCSK"]; + return nil; + } + + aks_ref_key_t refkey = NULL; + kern_return_t aksResult = aks_ref_key_create_with_blob(KEYBAG_DEVICE, kcsk.aksRefKey.bytes, kcsk.aksRefKey.length, &refkey); + if (aksResult != kAKSReturnSuccess) { + [self fillError:error + code:SecDbBackupAKSFailure + underlying:nil + description:@"Failed to create refkey from KCSK blob for class %d: %d", keyclass, aksResult]; + return nil; + } + + size_t externalDataLen = 0; + const uint8_t* externalData = aks_ref_key_get_external_data(refkey, &externalDataLen); + NSData* derBagIdent = [NSData dataWithBytes:externalData length:externalDataLen]; + CFErrorRef cfErr = NULL; + NSDictionary* identData = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)derBagIdent, 0, NULL, &cfErr); + if (!identData || ![_bagIdentity.baghash isEqualToData:identData[@"baghash"]] || ![_bagIdentity.baguuid isEqualToData:identData[@"baguuid"]]) { + secerror("SecDbBackup: KCSK ref key embedded bag identity does not match loaded bag. %@ vs %@", identData, _bagIdentity); + [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:CFBridgingRelease(cfErr) description:@"KCSK ref key embedded bag identity does not match loaded bag."]; + return nil; + } + + // AKS refkey claims in its external data to belong to our backup bag. Let's see if the claim holds up: use the key. + void* keypairBytes = NULL; + size_t keypairLength = 0; + aksResult = aks_ref_key_decrypt(refkey, NULL, 0, kcsk.aksWrappedKey.bytes, kcsk.aksWrappedKey.length, &keypairBytes, &keypairLength); + if (aksResult == kSKSReturnNoPermission) { + [self fillError:error code:SecDbBackupKeychainLocked underlying:nil description:@"Unable to unwrap KCSK private key for class %d. Locked", keyclass]; + return nil; + } else if (aksResult != kAKSReturnSuccess) { + // Failure could indicate key was corrupted or tampered with + [self fillError:error + code:SecDbBackupAKSFailure + underlying:nil + description:@"AKS did not unwrap KCSK private key for class %d: %d", keyclass, aksResult]; + return nil; + } + + SFECKeyPair* keypair = [self getECKeyPairFromDERBytes:keypairBytes length:keypairLength error:error]; + return keypair ? [InMemoryKCSK kcskWithRefKey:refkey wrappedKey:kcsk.aksWrappedKey key:keypair] : nil; +} + +- (SFECKeyPair*)onQueueFetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error +{ + assert(error); + assert(_bagIdentity); + assert(_handle != bad_keybag_handle); + + InMemoryKCSK* cached = _cachedKCSKs[@(keyclass)]; + if (cached.key) { + return cached.key; + } + + if (cached) { + secnotice("SecDbBackup", "Cached but wrapped KCSK found for class %d, unwrapping", keyclass); + void* keybytes = NULL; + size_t keylen = 0; + kern_return_t aksResult = aks_ref_key_decrypt(cached.refKey, NULL, 0, cached.wrappedKey.bytes, cached.wrappedKey.length, &keybytes, &keylen); + if (aksResult == kAKSReturnSuccess) { + cached.key = [self getECKeyPairFromDERBytes:keybytes length:keylen error:error]; + return cached.key; + } else { + secerror("SecDbBackup: Cached KCSK isn't unwrapping key material. This is a bug."); + } + } + + secnotice("SecDbBackup", "No cached KCSK for class %d, reading from disk", keyclass); + cached = [self onQueueReadKCSKFromDiskForClass:keyclass error:error]; + if (!cached.key) { + secerror("SecDbBackup: Failed to obtain KCSK for class %d: %@", keyclass, *error); + if ((*error).code != SecDbBackupKeychainLocked) { + seccritical("SecDbBackup: KCSK unavailable, cannot backup-wrap class %d items. Need to perform recovery.", keyclass); + // TODO: We're borked. Need to recover from this. + } + } + _cachedKCSKs[@(keyclass)] = cached; + return cached.key; +} + +#pragma mark - Recovery Set Management + +- (BOOL)onQueueInTransaction:(SecDbConnectionRef)dbt writeRecoverySetToKeychain:(SecDbBackupRecoverySet*)set error:(NSError**)error +{ + dispatch_assert_queue(_queue); + __block bool ok = true; + __block CFErrorRef cfError = NULL; + + NSString* sql = @"INSERT INTO backuprecoverysets (backupUUID, recoverytype, recoveryset) VALUES (?, ?, ?)"; + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbBindObject(stmt, 1, (__bridge CFDataRef)set.bagIdentity.baguuid, &cfError); + ok &= SecDbBindObject(stmt, 2, (__bridge CFNumberRef)@(set.recoveryType), &cfError); + ok &= SecDbBindObject(stmt, 3, (__bridge CFDataRef)set.data, &cfError); + ok &= SecDbStep(dbt, stmt, &cfError, NULL); + }); + + if (!ok) { + secerror("SecDbBackup: Unable to write recovery set to keychain: %@", cfError); + [self fillError:error code:SecDbBackupWriteFailure underlying:CFBridgingRelease(cfError) description:@"Unable to write recovery set to keychain"]; + } + + return ok; +} + +- (SecDbBackupRecoverySet*)onQueueInTransaction:(SecDbConnectionRef)dbt createRecoverySetWithBagSecret:(NSData*)secret + forType:(SecDbBackupRecoveryType)type error:(NSError**)error +{ + dispatch_assert_queue(_queue); + if (!secret) { + [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Can't create recovery set without secret"]; + return nil; + } + + SecDbBackupRecoverySet* set; + switch (type) { + case SecDbBackupRecoveryTypeAKS: + set = [self inTransaction:dbt createAKSTypeRecoverySetWithBagSecret:secret handle:_handle error:error]; + break; + case SecDbBackupRecoveryTypeCylon: + secerror("SecDbBackup: Cylon recovery type not yet implemented"); + [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type Cylon not yet implemented"]; + break; + case SecDbBackupRecoveryTypeRecoveryKey: + secerror("SecDbBackup: RecoveryKey recovery type not yet implemented"); + [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type RecoveryKey not yet implemented"]; + break; + default: + secerror("SecDbBackup: Unknown type %ld", (long)type); + [self fillError:error code:SecDbBackupUnknownOption underlying:nil description:@"Recovery type %li unknown", (long)type]; + break; + } + + return set; +} + +- (SecDbBackupRecoverySet*)inTransaction:(SecDbConnectionRef)dbt createAKSTypeRecoverySetWithBagSecret:(NSData*)secret handle:(keybag_handle_t)handle error:(NSError**)error +{ + SecDbBackupRecoverySet* set = [SecDbBackupRecoverySet new]; + set.recoveryType = SecDbBackupRecoveryTypeAKS; + set.bagIdentity = _bagIdentity; + + NSError* cryptoError; + SFAESKeySpecifier* specifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; + SFAESKey* KCSKSecret = [[SFAESKey alloc] initRandomKeyWithSpecifier:specifier error:&cryptoError]; + if (!KCSKSecret) { + [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to create AKS recovery set"]; + return nil; + } + + // We explicitly do NOT want akpu. For the rest, create and write all KCSKs + for (NSNumber* class in @[@(key_class_ak), @(key_class_ck), @(key_class_dk), @(key_class_aku), @(key_class_cku), @(key_class_dku)]) { + SecDbBackupKeyClassSigningKey* kcsk = [self createKCSKForKeyClass:[class intValue] withWrapper:KCSKSecret error:error]; + if (!kcsk) { + secerror("SecDbBackup: Unable to create KCSK for class %@: %@", class, *error); + return nil; + } + if (![self inTransaction:dbt writeKCSKToKeychain:kcsk error:error]) { + secerror("SecDbBackup: Unable to write KCSK for class %@ to keychain: %@", class, *error); + return nil; + } + } + + SFAESKey* recoverykey = [[SFAESKey alloc] initRandomKeyWithSpecifier:specifier error:&cryptoError]; + if (!recoverykey) { + [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to create recovery key"]; + return nil; + } + + SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] + initWithKeySpecifier:[[SFAESKeySpecifier alloc] + initWithBitSize:SFAESKeyBitSize256]]; + SFAuthenticatedCiphertext* wrappedsecret = [op encrypt:secret withKey:recoverykey error:&cryptoError]; + if (!wrappedsecret) { + secerror("SecDbBackup: Unable to wrap keybag secret: %@", cryptoError); + [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to wrap keybag secret"]; + return nil; + } + set.wrappedBagSecret = [NSKeyedArchiver archivedDataWithRootObject:wrappedsecret requiringSecureCoding:YES error:error]; + + SFAuthenticatedCiphertext* wrappedkcsksecret = [op encrypt:KCSKSecret.keyData withKey:recoverykey error:&cryptoError]; + if (!wrappedkcsksecret) { + secerror("SecDbBackup: Unable to wrap KCSK secret: %@", cryptoError); + [self fillError:error code:SecDbBackupCryptoFailure underlying:cryptoError description:@"Unable to wrap KCSK secret"]; + return nil; + } + set.wrappedKCSKSecret = [NSKeyedArchiver archivedDataWithRootObject:wrappedkcsksecret requiringSecureCoding:YES error:error]; + + NSMutableData* wrappedrecoverykey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN]; + if (![SecAKSObjCWrappers aksEncryptWithKeybag:KEYBAG_DEVICE keyclass:key_class_aku plaintext:recoverykey.keyData outKeyclass:nil ciphertext:wrappedrecoverykey error:&cryptoError]) { + secerror("SecDbBackup: Unable to wrap recovery key to AKS: %@", cryptoError); + [self fillError:error code:SecDbBackupAKSFailure underlying:cryptoError description:@"Unable to wrap recovery key to AKS"]; + return nil; + } + set.wrappedRecoveryKey = [wrappedrecoverykey copy]; + + return set; +} + +#pragma mark - Backup System Initialization / Maintenance + +- (BOOL)createOrLoadBackupInfrastructure:(NSError**)error { + assert(error); + __block BOOL ok = true; + __block NSError* localError; + dispatch_sync(_queue, ^{ + ok = [self onQueueCreateOrLoadBackupInfrastructure:&localError]; + }); + + if (localError) { + *error = localError; + } + return ok; +} + +// TODO: if this creates the infrastructure, kick off a fixup routine +// TODO: if not, make sure we actually delete stuff. Nested transactions are not a thing (use checkpointing or delete explicitly) + +- (BOOL)onQueueCreateOrLoadBackupInfrastructure:(NSError**)error { + dispatch_assert_queue(_queue); + assert(error); + if (self->_handle != bad_keybag_handle) { + return true; + } + + self->_handle = [self onQueueLoadBackupBag:nil error:error]; + if (self->_handle != bad_keybag_handle) { + secnotice("SecDbBackup", "Keybag found and loaded"); + return true; + } else if (self->_handle == bad_keybag_handle && (*error).code != SecDbBackupNoBackupBagFound) { + return false; + } + *error = nil; + + __block BOOL ok = YES; + __block CFErrorRef cfError = NULL; + __block NSError* localError; + secnotice("SecDbBackup", "CreateOrLoad: No backup bag found, attempting to create new infrastructure"); + if (ok && !SecAKSDoWithUserBagLockAssertion(&cfError, ^{ + ok &= kc_with_dbt_non_item_tables(YES, &cfError, ^bool(SecDbConnectionRef dbt) { + ok &= kc_transaction(dbt, &cfError, ^bool{ + NSData* secret = [self createBackupBagSecret:&localError]; + if (!secret) { + return false; + } + + self->_handle = [self onQueueCreateBackupBagWithSecret:secret error:&localError]; + if (self->_handle == bad_keybag_handle) { + return false; + } + secnotice("SecDbBackup", "CreateOrLoad: Successfully created backup bag"); + + if (![self onQueueInTransaction:dbt saveBackupBag:self->_handle asDefault:YES error:&localError]) { + return false; + } + secnotice("SecDbBackup", "CreateOrLoad: Successfully saved backup bag"); + + if (![self onQueueReloadDefaultBackupBagWithError:&localError]) { + return false; + } + secnotice("SecDbBackup", "CreateOrLoad: Successfully reloaded backup bag"); + + SecDbBackupRecoverySet* set = [self onQueueInTransaction:dbt + createRecoverySetWithBagSecret:secret + forType:SecDbBackupRecoveryTypeAKS + error:&localError]; + if (!set) { + secnotice("SecDbBackup", "CreateOrLoad: Successfully created recovery set"); + return false; + } + + if (![self onQueueInTransaction:dbt writeRecoverySetToKeychain:set error:&localError]) { + return false; + } + secnotice("SecDbBackup", "CreateOrLoad: Successfully saved recovery set"); + + return true; + }); + return ok; + }); + })) { // could not perform action with lock assertion + static dispatch_once_t once; + static sec_action_t action; + dispatch_once(&once, ^{ + action = sec_action_create("keybag_locked_during_backup_setup_complaint", 5); + sec_action_set_handler(action, ^{ + secerror("SecDbBackup: Cannot obtain AKS lock assertion so cannot setup backup infrastructure"); + }); + }); + sec_action_perform(action); + [self fillError:&localError code:SecDbBackupKeychainLocked underlying:nil + description:@"Unable to initialize backup infrastructure, keychain locked"]; + ok = NO; + } + + if (!ok) { + self->_bagIdentity = nil; + aks_unload_bag(self->_handle); + self->_handle = bad_keybag_handle; + } + + if (ok) { + secnotice("SecDbBackup", "Hurray! Successfully created backup infrastructure"); + } else { + assert(localError || cfError); + if (localError) { + secerror("SecDbBackup: Could not initialize backup infrastructure: %@", localError); + *error = localError; + } else if (cfError) { + secerror("SecDbBackup: Could not initialize backup infrastructure: %@", cfError); + [self fillError:error code:SecDbBackupSetupFailure underlying:CFBridgingRelease(cfError) + description:@"Unable to initialize backup infrastructure"]; + } else { + secerror("SecDbBackup: Could not initialize backup infrastructure but have no error"); + [self fillError:error code:SecDbBackupSetupFailure underlying:nil + description:@"Unable to initialize backup infrastructure (not sure why)"]; + } + CFReleaseNull(cfError); + } + + return ok; +} + +#pragma mark - Item Encryption + +- (SecDbBackupWrappedItemKey*)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error +{ + assert(error); + if (keyclass == key_class_akpu) { + secwarning("SecDbBackup: Don't tempt me Frodo!"); + [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Do not call wrapItemKey with class akpu"]; + return nil; + } + + if (![self createOrLoadBackupInfrastructure:error]) { + if ((*error).domain != (__bridge NSString*)kSecErrorDomain || (*error).code != errSecInteractionNotAllowed) { + secerror("SecDbBackup: Could not create/load backup infrastructure: %@", *error); + } + return nil; + } + + __block SecDbBackupWrappedItemKey* backupWrappedKey; + + __block NSMutableData* wrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN]; + __block NSError* localError; + dispatch_sync(_queue, ^{ + if (![self onQueueCreateOrLoadBackupInfrastructure:&localError]) { + return; + } + if (![SecAKSObjCWrappers aksEncryptWithKeybag:self->_handle + keyclass:keyclass + plaintext:key.keyData + outKeyclass:nil + ciphertext:wrappedKey + error:&localError]) { + return; + } + SFSignedData* wrappedAndSigned = [self onQueueSignData:wrappedKey withKCSKForKeyclass:keyclass error:&localError]; + if (!wrappedAndSigned) { + if (localError.code != SecDbBackupKeychainLocked) { + secerror("SecDbBackup: Unable to sign item for class %d: %@", keyclass, localError); + return; + } + } + backupWrappedKey = [SecDbBackupWrappedItemKey new]; + backupWrappedKey.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedAndSigned requiringSecureCoding:YES error:&localError]; + backupWrappedKey.baguuid = self->_bagIdentity.baguuid; + }); + + if (localError) { + secerror("SecDbBackup: Unable to wrap-and-sign item of class %d: %@", keyclass, localError); + *error = localError; + return nil; + } + + return backupWrappedKey; +} + +- (SFSignedData*)onQueueSignData:(NSMutableData*)data withKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error +{ + SFECKeyPair* kcsk = [self onQueueFetchKCSKForKeyclass:keyclass error:error]; + if (!kcsk) { + return nil; + } + + SFEC_X962SigningOperation* op = [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; + return [op sign:data withKey:kcsk error:error]; +} + +#pragma mark - Testing Helpers + +- (keybag_handle_t)createBackupBagWithSecret:(NSData*)secret error:(NSError**)error +{ + assert(error); + __block keybag_handle_t handle = bad_keybag_handle; + __block NSError* localError; + dispatch_sync(_queue, ^{ + handle = [self onQueueCreateBackupBagWithSecret:secret error:&localError]; + }); + if (localError) { + *error = localError; + } else if (handle == bad_keybag_handle) { + [self fillError:error code:SecDbBackupTestCodeFailure underlying:nil description:@"Unable to create backup bag, but no reason"]; + } + return handle; +} + +- (BOOL)saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error +{ + assert(error); + __block bool ok = true; + __block NSError* localErr; + __block CFErrorRef cfError = NULL; + dispatch_sync(_queue, ^{ + ok &= kc_with_dbt_non_item_tables(YES, &cfError, ^bool(SecDbConnectionRef dbt) { + ok &= kc_transaction(dbt, &cfError, ^bool{ + ok &= [self onQueueInTransaction:dbt saveBackupBag:handle asDefault:asDefault error:&localErr]; + return ok; + }); + return ok; + }); + }); + + if (!ok) { + if (cfError) { + [self fillError:error code:SecDbBackupTestCodeFailure underlying:CFBridgingRelease(cfError) description:@"Unable to save keybag to disk"]; + } else if (localErr) { + *error = localErr; + } else if (!localErr) { + [self fillError:error code:SecDbBackupTestCodeFailure underlying:nil description:@"Unable to save keybag to disk but who knows why"]; + } + } + return ok; +} + +- (keybag_handle_t)loadBackupBag:(NSUUID*)uuid error:(NSError**)error { + __block keybag_handle_t handle = bad_keybag_handle; + __block NSError* localError; + dispatch_sync(_queue, ^{ + handle = [self onQueueLoadBackupBag:uuid error:&localError]; + }); + if (error && localError) { + *error = localError; + } + return handle; +} + +- (SecDbBackupRecoverySet*)createRecoverySetWithBagSecret:(NSData*)secret forType:(SecDbBackupRecoveryType)type error:(NSError**)error +{ + __block SecDbBackupRecoverySet* set; + __block BOOL ok = YES; + __block NSError* localError; + __block CFErrorRef cfError = NULL; + dispatch_sync(_queue, ^{ + ok &= kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) { + ok &= kc_transaction(dbt, &cfError, ^bool{ + set = [self onQueueInTransaction:dbt createRecoverySetWithBagSecret:secret forType:type error:&localError]; + return set != nil; + }); + return ok; + }); + }); + if (error && cfError) { + *error = CFBridgingRelease(cfError); + } else if (error && localError) { + *error = localError; + } + CFReleaseNull(cfError); + + return set; +} + +- (SFECKeyPair*)fetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error +{ + __block SFECKeyPair* keypair; + __block NSError* localError; + dispatch_sync(_queue, ^{ + keypair = [self onQueueFetchKCSKForKeyclass:keyclass error:&localError]; + }); + if (localError && error) { + *error = localError; + } + + return keypair; +} + +@end + +#endif // SECDB_BACKUPS_ENABLED diff --git a/keychain/securityd/SecDbBackupManager_Internal.h b/keychain/securityd/SecDbBackupManager_Internal.h new file mode 100644 index 00000000..71a3b3eb --- /dev/null +++ b/keychain/securityd/SecDbBackupManager_Internal.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// DO NOT INCLUDE ME (unless you're SecDbBackupManager.m or a unit test) +// These are for internal use and testing only + +#ifndef SecDbBackupManager_Internal_h +#define SecDbBackupManager_Internal_h + +// Need these things in tests, too +#import "SecDbBackupManager.h" + +#if SECDB_BACKUPS_ENABLED + +#import "SecDbBackupBag.h" +#import "SecDbBackupBagIdentity.h" +#import "SecDbBackupKeyClassSigningKey.h" +#import "SecDbBackupMetadataClassKey.h" +#import "SecDbBackupRecoverySet.h" + +#include + +#import +#import +#import +#import + +@interface SecDbBackupManager (Internal) +@property (nonatomic) SecDbBackupBagIdentity* bagIdentity; + +#define BACKUPBAG_PASSPHRASE_LENGTH 32 +#define UUIDBYTESLENGTH 16 + ++ (void)resetManager; +- (NSData*)createBackupBagSecret:(NSError**)error; +- (keybag_handle_t)createBackupBagWithSecret:(NSData*)secret error:(NSError**)error; +- (BOOL)saveBackupBag:(keybag_handle_t)handle asDefault:(BOOL)asDefault error:(NSError**)error; +- (keybag_handle_t)loadBackupBag:(NSUUID*)uuid error:(NSError**)error; +- (BOOL)createOrLoadBackupInfrastructure:(NSError**)error; +- (SecDbBackupKeyClassSigningKey*)createKCSKForKeyClass:(keyclass_t)keyclass withWrapper:(SFAESKey*)wrapper error:(NSError**)error; +- (SecDbBackupRecoverySet*)createRecoverySetWithBagSecret:(NSData*)secret forType:(SecDbBackupRecoveryType)type error:(NSError**)error; +- (SFECKeyPair*)fetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error; + +// Pure utilities +- (NSData*)getSHA256OfData:(NSData*)data; +- (SFECKeyPair*)ECKeyPairFromDerBytes:(void*)bytes length:(size_t)len error:(NSError**)error; + +@end + +#endif // SECDB_BACKUPS_ENABLED + +#endif /* SecDbBackupManager_Internal_h */ diff --git a/keychain/securityd/SecDbItem.c b/keychain/securityd/SecDbItem.c new file mode 100644 index 00000000..5b63b41a --- /dev/null +++ b/keychain/securityd/SecDbItem.c @@ -0,0 +1,1867 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecDbItem.c - CoreFoundation-based constants and functions representing + * database items (certificates, keys, identities, and passwords.) + */ + +#if TARGET_DARWINOS +#undef OCTAGON +#undef SECUREOBJECTSYNC +#undef SHAREDWEBCREDENTIALS +#endif + +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemDb.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "keychain/securityd/SecItemSchema.h" + +#include + +// MARK: type converters + +CFStringRef copyString(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFStringGetTypeID()) { + return CFStringCreateCopy(0, obj); + }else if (tid == CFDataGetTypeID()) { + return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8); + } else if (tid == CFUUIDGetTypeID()) { + return CFUUIDCreateString(NULL, obj); + } else { + return NULL; + } +} + +CFDataRef copyData(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFDataGetTypeID()) { + return CFDataCreateCopy(0, obj); + } else if (tid == CFStringGetTypeID()) { + return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0); + } else if (tid == CFNumberGetTypeID()) { + SInt32 value; + CFNumberGetValue(obj, kCFNumberSInt32Type, &value); + return CFDataCreate(0, (const UInt8 *)&value, sizeof(value)); + } else { + return NULL; + } +} + +CFTypeRef copyUUID(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFDataGetTypeID()) { + CFIndex length = CFDataGetLength(obj); + if (length != 0 && length != 16) + return NULL; + return CFDataCreateCopy(NULL, obj); + } else if (tid == CFNullGetTypeID()) { + return CFDataCreate(NULL, NULL, 0); + } else if (tid == CFUUIDGetTypeID()) { + CFUUIDBytes uuidbytes = CFUUIDGetUUIDBytes(obj); + CFDataRef uuiddata = CFDataCreate(NULL, (void*) &uuidbytes, sizeof(uuidbytes)); + return uuiddata; + } else { + return NULL; + } +} + + +CFTypeRef copyBlob(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFDataGetTypeID()) { + return CFDataCreateCopy(0, obj); + } else if (tid == CFStringGetTypeID()) { + return CFStringCreateCopy(0, obj); + } else if (tid == CFNumberGetTypeID()) { + CFRetain(obj); + return obj; + } else { + return NULL; + } +} + +CFDataRef copySHA1(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFDataGetTypeID() && CFDataGetLength(obj) == CCSHA1_OUTPUT_SIZE) { + return CFDataCreateCopy(CFGetAllocator(obj), obj); + } else { + return NULL; + } +} + +CFTypeRef copyNumber(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFNumberGetTypeID()) { + CFRetain(obj); + return obj; + } else if (tid == CFBooleanGetTypeID()) { + SInt32 value = CFBooleanGetValue(obj); + return CFNumberCreate(0, kCFNumberSInt32Type, &value); + } else if (tid == CFStringGetTypeID()) { + SInt32 value = CFStringGetIntValue(obj); + CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value); + /* If a string converted to an int isn't equal to the int printed as + a string, return a CFStringRef instead. */ + if (!CFEqual(t, obj)) { + CFRelease(t); + return CFStringCreateCopy(0, obj); + } + CFRelease(t); + return CFNumberCreate(0, kCFNumberSInt32Type, &value); + } else + return NULL; +} + +CFDateRef copyDate(CFTypeRef obj) { + CFTypeID tid = CFGetTypeID(obj); + if (tid == CFDateGetTypeID()) { + CFRetain(obj); + return obj; + } else + return NULL; +} + +// MARK: SecDbColumn accessors, to retrieve values as CF types in SecDbStep. + +static CFDataRef SecDbColumnCopyData(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { + return CFDataCreate(allocator, sqlite3_column_blob(stmt, col), + sqlite3_column_bytes(stmt, col)); + //return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col), + // sqlite3_column_bytes(stmt, col), + // kCFAllocatorNull); +} + +static CFDateRef SecDbColumnCopyDate(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { + return CFDateCreate(allocator, sqlite3_column_double(stmt, col)); +} + +static CFNumberRef SecDbColumnCopyDouble(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { + double number = sqlite3_column_double(stmt, col); + return CFNumberCreate(allocator, kCFNumberDoubleType, &number); +} + +static CFNumberRef SecDbColumnCopyNumber64(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { + sqlite_int64 number = sqlite3_column_int64(stmt, col); + return CFNumberCreate(allocator, kCFNumberSInt64Type, &number); +} + +static CFNumberRef SecDbColumnCopyNumber(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) { + sqlite_int64 number = sqlite3_column_int64(stmt, col); + if (INT32_MIN <= number && number <= INT32_MAX) { + int32_t num32 = (int32_t)number; + return CFNumberCreate(allocator, kCFNumberSInt32Type, &num32); + } else { + return CFNumberCreate(allocator, kCFNumberSInt64Type, &number); + } +} + +static CFTypeRef SecDbColumnCopyString(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error, + CFOptionFlags flags) { + const unsigned char *text = sqlite3_column_text(stmt, col); + if (!text || 0 == strlen((const char *)text)) { + if (flags & kSecDbDefaultEmptyFlag) { + return CFSTR(""); + } else if (flags & kSecDbDefault0Flag) { + return CFSTR("0"); + } else { + return kCFNull; + } + } + return CFStringCreateWithBytes(allocator, text, strlen((const char *)text), kCFStringEncodingUTF8, false); +} + +// MARK: SecDbClass helpers + +const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error) { + const SecDbAttr *result = NULL; + SecDbForEachAttr(class, desc) { + if (desc->kind == kind) + result = desc; + } + + if (!result) + SecError(errSecInternal, error, CFSTR("Can't find attribute of kind %d in class %@"), kind, class->name); + + return result; +} + +// MARK: SecDbAttr helpers + +static bool SecDbIsTombstoneDbSelectAttr(const SecDbAttr *attr) { + return attr->flags & kSecDbPrimaryKeyFlag || attr->kind == kSecDbTombAttr; +} + +#if 0 +static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) { + return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbModificationDateAttr; +} +#endif + +static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) { + // We add AuthenticatedData to include UUIDs, which can't be primary keys + return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr || (attr->flags & kSecDbInAuthenticatedDataFlag); +} + +CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error) { + CFTypeRef value = NULL; + switch (attr->kind) { + case kSecDbAccessAttr: + case kSecDbStringAttr: + case kSecDbAccessControlAttr: + value = CFSTR(""); + break; + case kSecDbBlobAttr: + case kSecDbDataAttr: + value = CFDataCreate(kCFAllocatorDefault, NULL, 0); + break; + case kSecDbUUIDAttr: + value = CFDataCreate(kCFAllocatorDefault, NULL, 0); + break; + case kSecDbNumberAttr: + case kSecDbSyncAttr: + case kSecDbTombAttr: + { + int32_t zero = 0; + value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &zero); + break; + } + case kSecDbDateAttr: + value = CFDateCreate(kCFAllocatorDefault, 0.0); + break; + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); + break; + default: + SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name); + value = NULL; + } + + return value; +} + +static CFTypeRef SecDbAttrCopyValueForDb(const SecDbAttr *attr, CFTypeRef value, CFErrorRef *error) { + CFDataRef data = NULL; + CFTypeRef result = NULL; + + if (value == NULL) + value = kCFNull; + + if (CFEqual(value, kCFNull) && attr->flags & kSecDbPrimaryKeyFlag) { + // SQLITE3 doesn't like NULL for primary key attributes, pretend kSecDbDefaultEmptyFlag was specified + require_quiet(result = SecDbAttrCopyDefaultValue(attr, error), out); + } else { + result = CFRetain(value); + } + + if (attr->flags & kSecDbSHA1ValueInFlag && !CFEqual(result, kCFNull)) { + require_action_quiet(data = copyData(result), out, + SecError(errSecInternal, error, CFSTR("failed to get attribute %@ data"), attr->name); + CFReleaseNull(result)); + CFAssignRetained(result, CFDataCopySHA1Digest(data, error)); + } + +out: + CFReleaseSafe(data); + return result; +} + +static CFStringRef SecDbAttrGetHashName(const SecDbAttr *attr) { + if ((attr->flags & kSecDbSHA1ValueInFlag) == 0) { + return attr->name; + } + + static dispatch_once_t once; + static CFMutableDictionaryRef hash_store; + static dispatch_queue_t queue; + dispatch_once(&once, ^{ + queue = dispatch_queue_create("secd-hash-name", NULL); + hash_store = CFDictionaryCreateMutableForCFTypes(NULL); + }); + + __block CFStringRef name; + dispatch_sync(queue, ^{ + name = CFDictionaryGetValue(hash_store, attr->name); + if (name == NULL) { + name = CFStringCreateWithFormat(NULL, NULL, CFSTR("#%@"), attr->name); + CFDictionarySetValue(hash_store, attr->name, name); + CFRelease(name); + } + }); + return name; +} + +// MARK: SecDbItem + +CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name) { + return CFDictionaryGetValue(item->attributes, name); +} + +static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *desc) { + return CFDictionaryGetValue(item->attributes, desc->name); +} + +CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SecDbForEachAttrWithMask(item->class, desc, mask) { + CFTypeRef value = SecDbItemGetValue(item, desc, error); + if (value) { + if (!CFEqual(kCFNull, value)) { + CFDictionarySetValue(dict, desc->name, value); + } else if (desc->flags & kSecDbNotNullFlag) { + SecError(errSecDecode, error, CFSTR("attribute %@ has NULL value"), desc->name); + secerror("%@", error ? *error : (CFErrorRef)CFSTR("error == NULL")); + CFReleaseNull(dict); + break; + } + } else { + CFReleaseNull(dict); + break; + } + } + return dict; +} + +void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle) { + CFRetainAssign(item->credHandle, cred_handle); +} + +void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups) { + CFRetainAssign(item->callerAccessGroups, caller_access_groups); +} + +CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error) { + CFDataRef edata = NULL; + keybag_handle_t keybag = (keybag_handle_t)handle; + CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); + CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); + if (attributes || auth_attributes) { + SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error); + if (access_control) { + if (ks_encrypt_data_legacy(keybag, access_control, item->credHandle, attributes, auth_attributes, &edata, false, error)) { + item->_edataState = kSecDbItemEncrypting; + } else { + seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR("")); + } + CFRelease(access_control); + } + CFReleaseNull(attributes); + CFReleaseNull(auth_attributes); + } + + return edata; +} + +bool SecDbItemEnsureDecrypted(SecDbItemRef item, bool decryptSecretData, CFErrorRef *error) { + + // If we haven't yet decrypted the item, make sure we do so now + bool result = true; + if (item->_edataState == kSecDbItemEncrypted || (decryptSecretData && item->_edataState == kSecDbItemSecretEncrypted)) { + const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error); + if (attr) { + CFDataRef edata = SecDbItemGetCachedValue(item, attr); + if (!edata) + return SecError(errSecInternal, error, CFSTR("state= encrypted but edata is NULL")); + // Decrypt calls set value a bunch of times which clears our edata and changes our state. + item->_edataState = kSecDbItemDecrypting; + result = SecDbItemDecrypt(item, decryptSecretData, edata, error); + if (result) + item->_edataState = decryptSecretData ? kSecDbItemClean : kSecDbItemSecretEncrypted; + else + item->_edataState = kSecDbItemEncrypted; + } + } + return result; +} + +// Only called if cached value is not found. +static CFTypeRef SecDbItemCopyValue(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { + if (attr->copyValue) { + return attr->copyValue(item, attr, error); + } + + CFTypeRef value = NULL; + switch (attr->kind) { + // These have an explicit copyValue; here to shut up compiler + case kSecDbSHA1Attr: + case kSecDbEncryptedDataAttr: + case kSecDbPrimaryKeyAttr: + value = NULL; + break; + case kSecDbAccessAttr: + case kSecDbStringAttr: + case kSecDbBlobAttr: + case kSecDbAccessControlAttr: + if (attr->flags & kSecDbNotNullFlag) { + if (attr->flags & kSecDbDefault0Flag) { + value = CFSTR("0"); + break; + } else if (attr->kind != kSecDbBlobAttr && attr->flags & kSecDbDefaultEmptyFlag) { + // blob drops through to data everything else is empty string + value = CFSTR(""); + break; + } + } + //DROPTHROUGH + case kSecDbDataAttr: + if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefaultEmptyFlag) { + value = CFDataCreate(CFGetAllocator(item), NULL, 0); + } else { + value = kCFNull; + } + break; + case kSecDbUUIDAttr: + value = CFDataCreate(CFGetAllocator(item), NULL, 0); + break; + case kSecDbNumberAttr: + case kSecDbSyncAttr: + case kSecDbTombAttr: + if (attr->flags & kSecDbNotNullFlag) { + int32_t zero = 0; + value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &zero); + } else { + value = kCFNull; + } + break; + case kSecDbDateAttr: + if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefault0Flag) { + value = CFDateCreate(kCFAllocatorDefault, 0.0); + } else { + value = kCFNull; + } + break; + case kSecDbRowIdAttr: + if (attr->flags & kSecDbNotNullFlag) { + // No can do, error? + } + value = kCFNull; + break; + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + value = CFDateCreate(CFGetAllocator(item), CFAbsoluteTimeGetCurrent()); + break; + case kSecDbUTombAttr: + value = kCFNull; + break; + } + + return value; +} + +// SecDbItemGetValue will return kCFNull if there is no value for an attribute and this was not +// an error. It will return NULL and optionally set *error if there was an error computing an +// attribute, or if a required attribute was missing a value and had no known way to compute +// it's value. +CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) { + // Propagate chained errors + if (!desc) + return NULL; + + if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag || desc->flags & kSecDbReturnDataFlag) { + if (!SecDbItemEnsureDecrypted(item, desc->flags & kSecDbReturnDataFlag, error)) + return NULL; + } + + CFTypeRef value = SecDbItemGetCachedValue(item, desc); + if (!value) { + value = SecDbItemCopyValue(item, desc, error); + if (value) { + if (CFEqual(kCFNull, value)) { + CFRelease(value); // This is redundant but it shuts clang's static analyzer up. + value = kCFNull; + } else { + SecDbItemSetValue(item, desc, value, error); + CFRelease(value); + value = SecDbItemGetCachedValue(item, desc); + } + } + } + return value; +} + +CFTypeRef SecDbItemGetValueKind(SecDbItemRef item, SecDbAttrKind descKind, CFErrorRef *error) { + CFTypeRef result = NULL; + + const SecDbClass * itemClass = SecDbItemGetClass(item); + const SecDbAttr * desc = SecDbClassAttrWithKind(itemClass, descKind, error); + + if (desc) { + result = SecDbItemGetValue(item, desc, error); + } + + return result; +} + + +// Similar as SecDbItemGetValue, but if attr represents attribute stored into DB field as hash, returns +// hashed value for the attribute. +static CFTypeRef SecDbItemCopyValueForDb(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) { + CFTypeRef value = NULL; + CFStringRef hash_name = NULL; + hash_name = SecDbAttrGetHashName(desc); + if ((desc->flags & kSecDbSHA1ValueInFlag) && (desc->flags & kSecDbInFlag)) { + value = CFRetainSafe(CFDictionaryGetValue(item->attributes, hash_name)); + } + + if (value == NULL) { + require_quiet(value = SecDbItemGetValue(item, desc, error), out); + require_action_quiet(value = SecDbAttrCopyValueForDb(desc, value, error), out, CFReleaseNull(value)); + if ((desc->flags & kSecDbSHA1ValueInFlag) != 0) { + CFDictionarySetValue(item->attributes, hash_name, value); + } + } + +out: + return value; +} + +static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool *bvalue, CFErrorRef *error) { + CFTypeRef value = SecDbItemGetValue(item, desc, error); + if (!value) + return false; + char cvalue; + *bvalue = (isNumber(value) && CFNumberGetValue(value, kCFNumberCharType, &cvalue) && cvalue == 1); + return true; +} + +static CFStringRef SecDbItemCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFStringRef desc; + if (isDictionary(formatOptions) && CFDictionaryContainsKey(formatOptions, kSecDebugFormatOption)) { + SecDbItemRef item = (SecDbItemRef)cf; + CFMutableStringRef mdesc = CFStringCreateMutable(CFGetAllocator(cf), 0); + CFStringAppendFormat(mdesc, NULL, CFSTR("<%@"), item->class->name); + SecDbForEachAttr(item->class, attr) { + CFTypeRef value = SecDbItemGetValue(item, attr, NULL); + if (value) { + CFStringAppend(mdesc, CFSTR(",")); + CFStringAppend(mdesc, attr->name); + CFStringAppend(mdesc, CFSTR("=")); + if (CFEqual(CFSTR("data"), attr->name)) { + CFStringAppendEncryptedData(mdesc, value); + } else if (CFEqual(CFSTR("v_Data"), attr->name)) { + CFStringAppend(mdesc, CFSTR("")); + } else if (isData(value)) { + CFStringAppendHexData(mdesc, value); + } else { + CFStringAppendFormat(mdesc, 0, CFSTR("%@"), value); + } + } + } + CFStringAppend(mdesc, CFSTR(">")); + desc = mdesc; + } else { + SecDbItemRef item = (SecDbItemRef)cf; + const UInt8 zero4[4] = {}; + const UInt8 *pk = &zero4[0], *sha1 = &zero4[0]; + char sync = 0; + char tomb = 0; + SInt64 rowid = 0; + CFStringRef access = NULL; + uint8_t mdatbuf[32] = {}; + uint8_t *mdat = &mdatbuf[0]; + CFMutableStringRef attrs = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringRef agrp = NULL; + CFBooleanRef utomb = NULL; + + SecDbForEachAttr(item->class, attr) { + CFTypeRef value; + switch (attr->kind) { + case kSecDbBlobAttr: + case kSecDbDataAttr: + case kSecDbStringAttr: + case kSecDbNumberAttr: + case kSecDbDateAttr: + case kSecDbEncryptedDataAttr: + if (attr->flags & (kSecDbReturnAttrFlag | kSecDbReturnDataFlag) && (value = SecDbItemGetValue(item, attr, NULL)) && !CFEqual(value, kCFNull)) { + if (isString(value) && CFEqual(attr->name, kSecAttrAccessGroup)) { + agrp = value; + } else { + // We don't log these, just record that we saw the attribute. + CFStringAppend(attrs, CFSTR(",")); + CFStringAppend(attrs, attr->name); + } + } + break; + case kSecDbUUIDAttr: + if ((value = SecDbItemGetValue(item, attr, NULL))) { + if (CFEqual(attr->name, kSecAttrMultiUser)) { + if (isData(value)) { + CFStringAppend(attrs, CFSTR(",")); + if (CFDataGetLength(value)) { + CFStringAppendHexData(attrs, value); + } else { + CFStringAppend(attrs, attr->name); + } + } + } + } + break; + case kSecDbCreationDateAttr: + // We don't care about this and every object has one. + break; + case kSecDbModificationDateAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isDate(value)) + mdat = der_encode_generalizedtime_body(CFDateGetAbsoluteTime(value), NULL, mdat, &mdatbuf[31]); + break; + case kSecDbSHA1Attr: + value = SecDbItemGetValue(item, attr, NULL); + if (isData(value) && CFDataGetLength(value) >= (CFIndex)sizeof(zero4)) + sha1 = CFDataGetBytePtr(value); + break; + case kSecDbRowIdAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isNumber(value)) + CFNumberGetValue(value, kCFNumberSInt64Type, &rowid); + break; + case kSecDbPrimaryKeyAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isData(value)) + pk = CFDataGetBytePtr(value); + break; + case kSecDbSyncAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isNumber(value)) + CFNumberGetValue(value, kCFNumberCharType, &sync); + break; + case kSecDbTombAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isNumber(value)) + CFNumberGetValue(value, kCFNumberCharType, &tomb); + break; + case kSecDbAccessAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isString(value)) + access = value; + break; + case kSecDbUTombAttr: + value = SecDbItemGetValue(item, attr, NULL); + if (isBoolean(value)) + utomb = value; + case kSecDbAccessControlAttr: + /* TODO: Add formatting of ACLs. */ + break; + } + } + + desc = CFStringCreateWithFormat(CFGetAllocator(cf), NULL, + CFSTR( + "%s," + "%@," + "%02X%02X%02X%02X," + "%s," + "%@," + "%@," + "%"PRId64 + "%@," + "%s," + "%s" + "%02X%02X%02X%02X"), + tomb ? "T" : "O", + item->class->name, + pk[0], pk[1], pk[2], pk[3], + sync ? "S" : "L", + access, + agrp, + rowid, + attrs, + mdat, + utomb ? (CFEqual(utomb, kCFBooleanFalse) ? "F," : "T,") : "", + sha1[0], sha1[1], sha1[2], sha1[3]); + CFReleaseSafe(attrs); + } + + return desc; +} + +static void SecDbItemDestroy(CFTypeRef cf) { + SecDbItemRef item = (SecDbItemRef)cf; + CFReleaseSafe(item->attributes); + CFReleaseSafe(item->credHandle); + CFReleaseSafe(item->callerAccessGroups); + CFReleaseSafe(item->cryptoOp); +} + +static CFHashCode SecDbItemHash(CFTypeRef cf) { + SecDbItemRef item = (SecDbItemRef)cf; + CFDataRef digest = SecDbItemGetSHA1(item, NULL); + CFHashCode code; + const UInt8 *p = CFDataGetBytePtr(digest); + // Read first 8 bytes of digest in order + code = p[0] + ((p[1] + ((p[2] + ((p[3] + ((p[4] + ((p[5] + ((p[6] + (p[7] << 8)) << 8)) << 8)) << 8)) << 8)) << 8)) << 8); + return code; +} + +static Boolean SecDbItemCompare(CFTypeRef cf1, CFTypeRef cf2) { + SecDbItemRef item1 = (SecDbItemRef)cf1; + SecDbItemRef item2 = (SecDbItemRef)cf2; + CFDataRef digest1 = NULL; + CFDataRef digest2 = NULL; + if (item1) + digest1 = SecDbItemGetSHA1(item1, NULL); + if (item2) + digest2 = SecDbItemGetSHA1(item2, NULL); + Boolean equal = CFEqual(digest1, digest2); + return equal; +} + +CFGiblisWithHashFor(SecDbItem) + +static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass *class, keybag_handle_t keybag) { + SecDbItemRef item = CFTypeAllocate(SecDbItem, struct SecDbItem, allocator); + item->class = class; + item->attributes = CFDictionaryCreateMutableForCFTypes(allocator); + item->keybag = keybag; + item->_edataState = kSecDbItemDirty; + item->cryptoOp = kAKSKeyOpDecrypt; + + return item; +} + +const SecDbClass *SecDbItemGetClass(SecDbItemRef item) { + return item->class; +} + +keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item) { + return item->keybag; +} + +bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error) { + if (!SecDbItemEnsureDecrypted(item, true, error)) + return false; + if (item->keybag != keybag) { + item->keybag = keybag; + if (item->_edataState == kSecDbItemClean) { + SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL); + } + } + + return true; +} + +bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error) { + // Propagate chained errors. + if (!desc) + return false; + + if (!value) + value = kCFNull; + + if (desc->setValue) + return desc->setValue(item, desc, value, error); + + if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) { + if (!SecDbItemEnsureDecrypted(item, true, error)) { + return false; + } + } + + bool changed = false; + CFTypeRef attr = NULL; + switch (desc->kind) { + case kSecDbPrimaryKeyAttr: + case kSecDbDataAttr: + attr = copyData(value); + break; + case kSecDbEncryptedDataAttr: + attr = copyData(value); + if (attr) { + if (item->_edataState == kSecDbItemEncrypting) + item->_edataState = kSecDbItemClean; + else + item->_edataState = kSecDbItemEncrypted; + } else if (!value || CFEqual(kCFNull, value)) { + item->_edataState = kSecDbItemDirty; + } + break; + case kSecDbBlobAttr: + case kSecDbAccessControlAttr: + attr = copyBlob(value); + break; + case kSecDbDateAttr: + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + attr = copyDate(value); + break; + case kSecDbNumberAttr: + case kSecDbSyncAttr: + case kSecDbTombAttr: + case kSecDbRowIdAttr: + attr = copyNumber(value); + break; + case kSecDbAccessAttr: + case kSecDbStringAttr: + attr = copyString(value); + break; + case kSecDbSHA1Attr: + attr = copySHA1(value); + break; + case kSecDbUTombAttr: + attr = CFRetainSafe(asBoolean(value, NULL)); + break; + case kSecDbUUIDAttr: + attr = copyUUID(value); + break; + } + + if (attr) { + CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name); + changed = (!ovalue || !CFEqual(ovalue, attr)); + CFDictionarySetValue(item->attributes, desc->name, attr); + CFRelease(attr); + } else { + if (value && !CFEqual(kCFNull, value)) { + SecError(errSecItemInvalidValue, error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value); + return false; + } + CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name); + changed = (ovalue && !CFEqual(ovalue, kCFNull)); + CFDictionaryRemoveValue(item->attributes, desc->name); + } + + if (changed) { + if (desc->flags & kSecDbInHashFlag) + SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL), kCFNull, NULL); + if (desc->flags & kSecDbPrimaryKeyFlag) + SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, NULL), kCFNull, NULL); + if ((desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) && (item->_edataState == kSecDbItemClean || (item->_edataState == kSecDbItemSecretEncrypted && (desc->flags & kSecDbReturnDataFlag) == 0))) + SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL); + if (desc->flags & kSecDbSHA1ValueInFlag) + CFDictionaryRemoveValue(item->attributes, SecDbAttrGetHashName(desc)); + } + + return true; +} + +bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error) { + SecDbForEachAttr(item->class, attr) { + CFTypeRef value = CFDictionaryGetValue(values, attr->name); + if (value && !SecDbItemSetValue(item, attr, value, error)) + return false; + } + return true; +} + +bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error) { + SecDbForEachAttr(item->class, attr) { + if (CFEqual(attr->name, name)) { + return SecDbItemSetValue(item, attr, value, error); + } + } + return false; +} + +bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error) { + bool ok = true; + if (item->_edataState == kSecDbItemClean) + ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error), kCFNull, error); + if (ok && access_control) { //added check for access_control because ks_decrypt_data can leave NULL in access_control in case of error + item->_edataState = kSecDbItemDirty; + CFDataRef data = SecAccessControlCopyData(access_control); + ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), data, error); + CFRelease(data); + } + return ok; +} + +SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error) { + SecDbItemRef item = SecDbItemCreate(kCFAllocatorDefault, class, keybag); + if (item && !SecDbItemSetValues(item, attributes, error)) + CFReleaseNull(item); + return item; +} + +static CFTypeRef +SecDbColumnCopyValueWithAttr(CFAllocatorRef allocator, sqlite3_stmt *stmt, const SecDbAttr *attr, int col, CFErrorRef *error) { + CFTypeRef value = NULL; + switch (attr->kind) { + case kSecDbDateAttr: + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + value = SecDbColumnCopyDate(allocator, stmt, col, error); + break; + case kSecDbBlobAttr: + case kSecDbNumberAttr: + switch (sqlite3_column_type(stmt, col)) { + case SQLITE_INTEGER: + value = SecDbColumnCopyNumber(allocator, stmt, col, error); + break; + case SQLITE_FLOAT: + value = SecDbColumnCopyDouble(allocator, stmt, col, error); + break; + case SQLITE_TEXT: + value = SecDbColumnCopyString(allocator, stmt, col, error, + attr->flags); + break; + case SQLITE_BLOB: + value = SecDbColumnCopyData(allocator, stmt, col, error); + break; + case SQLITE_NULL: + value = kCFNull; + break; + } + break; + case kSecDbAccessAttr: + case kSecDbStringAttr: + value = SecDbColumnCopyString(allocator, stmt, col, error, + attr->flags); + break; + case kSecDbDataAttr: + case kSecDbUUIDAttr: + case kSecDbSHA1Attr: + case kSecDbPrimaryKeyAttr: + case kSecDbEncryptedDataAttr: + value = SecDbColumnCopyData(allocator, stmt, col, error); + break; + case kSecDbSyncAttr: + case kSecDbTombAttr: + value = SecDbColumnCopyNumber(allocator, stmt, col, error); + break; + case kSecDbRowIdAttr: + value = SecDbColumnCopyNumber64(allocator, stmt, col, error); + break; + case kSecDbAccessControlAttr: + case kSecDbUTombAttr: + /* This attributes does not have any database column associated, exists only inside encrypted blob as metadata. */ + break; + } + return value; +} + +SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)) { + SecDbItemRef item = SecDbItemCreate(allocator, class, keybag); + int col = 0; + SecDbForEachAttr(class, attr) { + if (return_attr(attr)) { + CFTypeRef value = SecDbColumnCopyValueWithAttr(allocator, stmt, attr, col++, error); + require_action_quiet(value, errOut, CFReleaseNull(item)); + + CFDictionarySetValue(item->attributes, SecDbAttrGetHashName(attr), value); + CFRelease(value); + } + + const SecDbAttr *data_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, NULL); + if (data_attr != NULL && CFDictionaryGetValue(item->attributes, data_attr->name) != NULL) { + item->_edataState = kSecDbItemEncrypted; + } + } + +errOut: + return item; +} + +SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class, + CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error) { + SecDbItemRef item = SecDbItemCreate(allocator, class, keybag); + const SecDbAttr *edata_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, error); + if (edata_attr) { + if (!SecDbItemSetValue(item, edata_attr, edata, error)) + CFReleaseNull(item); + } + return item; +} + +// TODO: Hack -- Replace with real filtering + +// Return true iff an item for which SecDbItemIsSyncable() already returns true should be part of the v2 view. +bool SecDbItemInV2(SecDbItemRef item) { + const SecDbClass *iclass = SecDbItemGetClass(item); + return (SecDbItemGetCachedValueWithName(item, kSecAttrSyncViewHint) == NULL && + (iclass == genp_class() || iclass == inet_class() || iclass == keys_class() || iclass == cert_class())); +} + +// Return true iff an item for which SecDbItemIsSyncable() and SecDbItemInV2() already return true should be part of the v0 view. +bool SecDbItemInV2AlsoInV0(SecDbItemRef item) { + return (SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL && SecDbItemGetClass(item) != cert_class()); +} + +SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) { + SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag); + SecDbItemSetCredHandle(new_item, item->credHandle); + SecDbForEachAttr(item->class, attr) { + // Copy each attribute, except the mod date attribute (it will be reset to now when needed), + // from the updates dict unless it's not there in which case we copy the attribute from the passed in item. + if (attr->kind != kSecDbModificationDateAttr && attr->kind != kSecDbEncryptedDataAttr && attr->kind != kSecDbSHA1Attr && attr->kind != kSecDbPrimaryKeyAttr) { + CFTypeRef value = NULL; + if (CFDictionaryGetValueIfPresent(updates, attr->name, &value)) { + if (!value) + SecError(errSecParam, error, CFSTR("NULL value in dictionary")); + } else { + value = SecDbItemGetValue(item, attr, error); + } + if (!value || !SecDbItemSetValue(new_item, attr, value, error)) { + CFReleaseNull(new_item); + break; + } + } + } + return new_item; +} + +// Ensure that the date value of attr of new_item is greater than that of old_item. +static bool SecDbItemMakeAttrYounger(SecDbItemRef new_item, SecDbItemRef old_item, const SecDbAttr *attr, CFErrorRef *error) { + CFDateRef old_date = SecDbItemGetValue(old_item, attr, error); + if (!old_date) + return false; + CFDateRef new_date = SecDbItemGetValue(new_item, attr, error); + if (!new_date) + return false; + bool ok = true; + if (CFDateCompare(new_date, old_date, NULL) != kCFCompareGreaterThan) { + CFDateRef adjusted_date = CFDateCreate(kCFAllocatorDefault, CFDateGetAbsoluteTime(old_date) + 0.001); + if (adjusted_date) { + ok = SecDbItemSetValue(new_item, attr, adjusted_date, error); + CFRelease(adjusted_date); + } + } + return ok; +} + +// Ensure that the mod date of new_item is greater than that of old_item. +static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, CFErrorRef *error) { + const SecDbAttr *attr = SecDbClassAttrWithKind(new_item->class, kSecDbModificationDateAttr, error); + return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error); +} + +static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeTombStone, CFErrorRef *error) { + SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag); + SecDbForEachAttr(item->class, attr) { + if (attr->kind == kSecDbTombAttr) { + // Set the tomb attr to true to indicate a tombstone. + if (!SecDbItemSetValue(new_item, attr, kCFBooleanTrue, error)) { + CFReleaseNull(new_item); + break; + } + } else if (SecDbIsTombstoneDbUpdateAttr(attr)) { + // Copy all primary key attributes and creation timestamps from the original item. + CFTypeRef value = SecDbItemGetValue(item, attr, error); + if (!value || (!CFEqual(kCFNull, value) && !SecDbItemSetValue(new_item, attr, value, error))) { + CFReleaseNull(new_item); + break; + } + } else if (attr->kind == kSecDbModificationDateAttr) { + if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) { + CFReleaseNull(new_item); + break; + } + } else if (makeTombStone && attr->kind == kSecDbUTombAttr) { + if (makeTombStone) + SecDbItemSetValue(new_item, attr, makeTombStone, error); + } + } + + return new_item; +} + +bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject) { + // Only used for controlling logging + // Use agrp=com.apple.security.sos, since it is not encrypted + if (!itemObject) { + return false; + } + const SecDbAttr *agrp = SecDbAttrWithKey(SecDbItemGetClass(itemObject), kSecAttrAccessGroup, NULL); + CFTypeRef cfval = SecDbItemGetValue(itemObject, agrp, NULL); + return cfval && CFStringCompareSafe(cfval, kSOSInternalAccessGroup, NULL) == kCFCompareEqualTo; +} + + +// MARK: - +// MARK: SQL Construction helpers -- These should become private in the future + +void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma) { + assert(needComma); + if (*needComma) { + CFStringAppend(sql, CFSTR(",")); + } else { + *needComma = true; + } + CFStringAppend(sql, value); +} + +static void SecDbAppendElementEquals(CFMutableStringRef sql, CFStringRef value, bool *needComma) { + SecDbAppendElement(sql, value, needComma); + CFStringAppend(sql, CFSTR("=?")); +} + +/* Append AND is needWhere is NULL or *needWhere is false. Append WHERE + otherwise. Upon return *needWhere will be false. */ +void +SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) { + if (!needWhere || !*needWhere) { + CFStringAppend(sql, CFSTR(" AND ")); + } else { + CFStringAppend(sql, CFSTR(" WHERE ")); + *needWhere = false; + } +} + +void +SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) { + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppend(sql, col); + CFStringAppend(sql, CFSTR("=?")); +} + +void +SecDbAppendWhereOrAndNotEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) { + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppend(sql, col); + CFStringAppend(sql, CFSTR("!=?")); +} + +static void SecDbAppendCountArgsAndCloseParen(CFMutableStringRef sql, CFIndex count) { + bool needComma = false; + while (count-- > 0) + SecDbAppendElement(sql, CFSTR("?"), &needComma); + CFStringAppend(sql, CFSTR(")")); +} + +void +SecDbAppendWhereOrAndIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) { + if (count == 1) + return SecDbAppendWhereOrAndEquals(sql, col, needWhere); + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppend(sql, col); + CFStringAppend(sql, CFSTR(" IN (")); + SecDbAppendCountArgsAndCloseParen(sql, count); +} + +void +SecDbAppendWhereOrAndNotIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) { + if (count == 1) + return SecDbAppendWhereOrAndNotEquals(sql, col, needWhere); + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppend(sql, col); + CFStringAppend(sql, CFSTR(" NOT IN (")); + SecDbAppendCountArgsAndCloseParen(sql, count); +} + +static CFStringRef SecDbItemCopyInsertSQL(SecDbItemRef item, bool(^use_attr)(const SecDbAttr *attr)) { + CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0); + CFStringAppend(sql, CFSTR("INSERT INTO ")); + CFStringAppend(sql, item->class->name); + CFStringAppend(sql, CFSTR("(")); + bool needComma = false; + CFIndex used_attr = 0; + SecDbForEachAttr(item->class, attr) { + if (use_attr(attr)) { + ++used_attr; + SecDbAppendElement(sql, attr->name, &needComma); + } + } + CFStringAppend(sql, CFSTR(")VALUES(?")); + while (used_attr-- > 1) { + CFStringAppend(sql, CFSTR(",?")); + } + CFStringAppend(sql, CFSTR(")")); + return sql; + +} + +static bool SecDbItemInsertBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr)(const SecDbAttr *attr)) { + bool ok = true; + int param = 0; + SecDbForEachAttr(item->class, attr) { + if (use_attr(attr)) { + CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error); + ok = value && SecDbBindObject(stmt, ++param, value, error); + CFReleaseSafe(value); + if (!ok) + break; + } + } + return ok; +} + +sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error) { + sqlite3_int64 row_id = 0; + const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); + if (attr) { + CFNumberRef number = SecDbItemGetValue(item, attr, error); + if (!isNumber(number)|| !CFNumberGetValue(number, kCFNumberSInt64Type, &row_id)) + SecDbError(SQLITE_ERROR, error, CFSTR("rowid %@ is not a 64 bit number"), number); + } + + return row_id; +} + +static CFNumberRef SecDbItemCreateRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) { + return CFNumberCreate(CFGetAllocator(item), kCFNumberSInt64Type, &rowid); +} + +bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) { + bool ok = true; + const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); + if (attr) { + CFNumberRef value = SecDbItemCreateRowId(item, rowid, error); + if (!value) + return false; + + ok = SecDbItemSetValue(item, attr, value, error); + CFRelease(value); + } + return ok; +} + +bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error) { + bool ok = true; + const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error); + if (attr) { + CFDictionaryRemoveValue(item->attributes, attr->name); + //ok = SecDbItemSetValue(item, attr, kCFNull, error); + } + return ok; +} + +static bool SecDbItemSetLastInsertRowId(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { + sqlite3_int64 rowid = sqlite3_last_insert_rowid(SecDbHandle(dbconn)); + return SecDbItemSetRowId(item, rowid, error); +} + +bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item) { + bool is_syncable_or_corrupted = false; + CFErrorRef localError = NULL; + if (!SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, &localError), + &is_syncable_or_corrupted, &localError)) { + is_syncable_or_corrupted = SecErrorGetOSStatus(localError) == errSecDecode; + } + CFReleaseSafe(localError); + return is_syncable_or_corrupted; +} + +bool SecDbItemIsSyncable(SecDbItemRef item) { + bool is_syncable; + if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, NULL), &is_syncable, NULL)) + return is_syncable; + return false; +} + +bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error) +{ + return SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, error), sync ? kCFBooleanTrue : kCFBooleanFalse, error); +} + +bool SecDbItemIsTombstone(SecDbItemRef item) { + bool is_tomb; + if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbTombAttr, NULL), &is_tomb, NULL)) + return is_tomb; + return false; +} + +CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error) { + return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, error), error); +} + +CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error) { + return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), error); +} + +static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErrorRef *error) { + CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, error); + if (!dict) + return NULL; + + SecDbQueryRef query = query_create(item->class, NULL, NULL, error); + if (query) { + CFReleaseSafe(query->q_item); + query->q_item = dict; + } + else + CFRelease(dict); + + return query; +} + +static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *error) { + CFErrorRef localError = NULL; + // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. + const struct SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, &localError); + CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, &localError)); + bool akpu = false; + + if (localError || !SecDbItemEnsureDecrypted(item, true, &localError)) { + if (SecErrorGetOSStatus(localError) == errSecDecode) { + // We failed to decrypt the item + const SecDbAttr *desc = SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, &localError); + SecAccessControlRef accc = NULL; + CFDataRef acccData = NULL; + + acccData = (CFDataRef)SecDbItemGetValue(item, desc, &localError); + if (isData(acccData)) { + accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, &localError); + } + + if (accc && CFEqualSafe(SecAccessControlGetProtection(accc), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { + akpu = true; + secwarning("cannot decrypt item %@, item is irrecoverably lost with older passcode (error %@)", item, localError); + } else { + secerror("error %@ reading item %@ (corrupted)", localError, item); + __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem); + } + CFReleaseNull(localError); + *is_corrupt = true; + } + } + + // Recompute sha1 hash attribute and compare with the cached one. + CFDataRef computedSHA1 = SecDbItemCopyValue(item, sha1attr, &localError); + if (storedSHA1 && computedSHA1 && !CFEqual(storedSHA1, computedSHA1)) { + CFStringRef storedHex = CFDataCopyHexString(storedSHA1), computedHex = CFDataCopyHexString(computedSHA1); + secerror("error %@ %@ != %@ item %@ (corrupted)", sha1attr->name, storedHex, computedHex, item); + __security_simulatecrash(CFSTR("Corrupted item (sha1 mismatch) found in keychain"), __sec_exception_code_CorruptItem); + CFReleaseSafe(storedHex); + CFReleaseSafe(computedHex); + *is_corrupt = true; + } + + // Sanity check that all attributes that must not be NULL actually aren't + if (!localError) SecDbForEachAttr(item->class, attr) { + if (attr->flags & (kSecDbInCryptoDataFlag | kSecDbInAuthenticatedDataFlag)) { + CFTypeRef value = SecDbItemGetValue(item, attr, &localError); + if (value) { + if (CFEqual(kCFNull, value) && attr->flags & kSecDbNotNullFlag) { + secerror("error attribute %@ has NULL value in item %@ (corrupted)", attr->name, item); + __security_simulatecrash(CFSTR("Corrupted item (attr NULL) found in keychain"), __sec_exception_code_CorruptItem); + *is_corrupt = true; + break; + } + } else { + if (SecErrorGetOSStatus(localError) == errSecDecode) { + // We failed to decrypt the item + if (akpu) { + secwarning("attribute %@: %@ item %@ (item lost with older passcode)", attr->name, localError, item); + } else { + secerror("error attribute %@: %@ item %@ (corrupted)", attr->name, localError, item); + __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem); + } + *is_corrupt = true; + CFReleaseNull(localError); + } + break; + } + } + } + + CFReleaseSafe(computedSHA1); + CFReleaseSafe(storedSHA1); + return SecErrorPropagate(localError, error); +} + +static void SecDbItemRecordUpdate(SecDbConnectionRef dbconn, SecDbItemRef deleted, SecDbItemRef inserted) { + SecDbRecordChange(dbconn, deleted, inserted); +} + +static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { + bool (^use_attr)(const SecDbAttr *attr) = ^bool(const SecDbAttr *attr) { + return (attr->flags & kSecDbInFlag); + }; + + if (!SecDbItemEnsureDecrypted(item, true, error)) { + return false; + } + + CFStringRef sql = SecDbItemCopyInsertSQL(item, use_attr); + __block bool ok = sql; + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + ok = (SecDbItemInsertBind(item, stmt, error, use_attr) && + SecDbStep(dbconn, stmt, error, NULL) && + SecDbItemSetLastInsertRowId(item, dbconn, error)); + }); + CFRelease(sql); + } + if (ok) { + secnotice("item", "inserted %@", item); + SecDbItemRecordUpdate(dbconn, NULL, item); + } else { + if (SecDbItemIsEngineInternalState(item)) { + secdebug ("item", "insert failed for item %@ with %@", item, error ? *error : NULL); + } else { + secnotice("item", "insert failed for item %@ with %@", item, error ? *error : NULL); + } + } + + return ok; +} + +bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error) { + return error && CFErrorGetCode(error) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(error)); +} + +bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) { + __block CFErrorRef localError = NULL; + __block bool ok = SecDbItemDoInsert(item, dbconn, &localError); + if (!ok && localError && CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { + SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(item, error); + if (query) { + CFRetainAssign(query->q_use_cred_handle, item->credHandle); + SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { + return attr->flags & kSecDbPrimaryKeyFlag; + }, NULL, NULL, ^(SecDbItemRef old_item, bool *stop) { + bool is_corrupt = false; + ok = SecDbItemIsCorrupt(old_item, &is_corrupt, error); + SecDbItemRef replace = NULL; + if (is_corrupt) { + // If old_item is corrupted pretend it's not there and just replace it. + replace = item; + CFRetain(replace); + if(error) + CFReleaseNull(*error); //item is corrupted and will be replaced, so drop the error + } else if (ok && duplicate) { + duplicate(old_item, &replace); + } + if (replace) { + const SecDbAttr *rowid_attr = SecDbClassAttrWithKind(old_item->class, kSecDbRowIdAttr, error); + CFNumberRef oldrowid = SecDbItemGetCachedValue(old_item, rowid_attr); + if (oldrowid) { + ok = SecDbItemSetValue(replace, rowid_attr, oldrowid, &localError); + if (ok && !is_corrupt) { + ok = SecDbItemMakeYounger(replace, old_item, error); + } + ok = ok && SecDbItemDoUpdate(old_item, replace, dbconn, &localError, ^bool (const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + } else { + ok = SecError(errSecInternal, &localError, CFSTR("no rowid for %@"), old_item); + } + CFRelease(replace); + if (ok) + CFReleaseNull(localError); // Clear the error, since we replaced the item. + } + }); + SecDbItemSetCredHandle(item, query->q_use_cred_handle); + ok &= query_destroy(query, error); + } + } + + return ok & SecErrorPropagate(localError, error); // Don't use && here! +} + +bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { + return SecDbItemInsertOrReplace(item, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) { + if (SecDbItemIsTombstone(old_item)) { + CFRetain(item); + *replace = item; + } + }); +} + +static CFStringRef SecDbItemCopyUpdateSQL(SecDbItemRef old_item, SecDbItemRef new_item, bool(^use_attr_in_where)(const SecDbAttr *attr)) { + CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(new_item), 0); + CFStringAppend(sql, CFSTR("UPDATE ")); + CFStringAppend(sql, new_item->class->name); + CFStringAppend(sql, CFSTR(" SET ")); + bool needComma = false; + CFIndex used_attr = 0; + SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) { + ++used_attr; + SecDbAppendElementEquals(sql, attr->name, &needComma); + } + + bool needWhere = true; + SecDbForEachAttr(old_item->class, attr) { + if (use_attr_in_where(attr)) { + SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); + } + } + + return sql; +} + +static bool SecDbItemUpdateBind(SecDbItemRef old_item, SecDbItemRef new_item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) { + bool ok = true; + int param = 0; + SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) { + CFTypeRef value = SecDbItemCopyValueForDb(new_item, attr, error); + ok &= value && SecDbBindObject(stmt, ++param, value, error); + CFReleaseSafe(value); + if (!ok) + break; + } + SecDbForEachAttr(old_item->class, attr) { + if (use_attr_in_where(attr)) { + CFTypeRef value = SecDbItemCopyValueForDb(old_item, attr, error); + ok &= value && SecDbBindObject(stmt, ++param, value, error); + CFReleaseSafe(value); + if (!ok) + break; + } + } + return ok; +} + +// Primary keys are the same -- do an update +bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { + CFStringRef sql = SecDbItemCopyUpdateSQL(old_item, new_item, use_attr_in_where); + __block bool ok = sql; + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + ok = SecDbItemUpdateBind(old_item, new_item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL); + }); + CFRelease(sql); + } + if (ok) { + if (SecDbItemIsEngineInternalState(old_item)) { + secdebug ("item", "replaced %@ in %@", old_item, dbconn); + secdebug ("item", " with %@ in %@", new_item, dbconn); + } else { + secnotice("item", "replaced %@ in %@", old_item, dbconn); + secnotice("item", " with %@ in %@", new_item, dbconn); + } + SecDbItemRecordUpdate(dbconn, old_item, new_item); + } + return ok; +} + +static CFStringRef SecDbItemCopyDeleteSQL(SecDbItemRef item, bool(^use_attr_in_where)(const SecDbAttr *attr)) { + CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0); + CFStringAppend(sql, CFSTR("DELETE FROM ")); + CFStringAppend(sql, item->class->name); + bool needWhere = true; + SecDbForEachAttr(item->class, attr) { + if (use_attr_in_where(attr)) { + SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); + } + } + + return sql; +} + +static bool SecDbItemDeleteBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) { + bool ok = true; + int param = 0; + SecDbForEachAttr(item->class, attr) { + if (use_attr_in_where(attr)) { + CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error); + ok &= value && SecDbBindObject(stmt, ++param, value, error); + CFReleaseSafe(value); + if (!ok) + break; + } + } + return ok; +} + +static bool SecDbItemDoDeleteOnly(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { + CFStringRef sql = SecDbItemCopyDeleteSQL(item, use_attr_in_where); + __block bool ok = sql; + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + ok = SecDbItemDeleteBind(item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL); + }); + CFRelease(sql); + } + return ok; +} + +bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { + return SecDbItemDoDeleteOnly(item, dbconn, error, ^bool(const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); +} + +static bool SecDbItemDoDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) { + bool ok = SecDbItemDoDeleteOnly(item, dbconn, error, use_attr_in_where); + if (ok) { + secnotice("item", "deleted %@ from %@", item, dbconn); + SecDbItemRecordUpdate(dbconn, item, NULL); + } + return ok; +} + +#if 0 +static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) { + bool ok = true; + // TODO: Treat non decryptable items like tombstones here too and delete them + SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error); + ok = tombstone; + if (tombstone) { + ok = SecDbItemClearRowId(tombstone, error); + if (ok) { + ok = SecDbItemDoDelete(tombstone, dbconn, error, ^bool (const SecDbAttr *attr) { + return SecDbIsTombstoneDbSelectAttr(attr); + }); + } + CFRelease(tombstone); + } + return ok; +} +#endif + +static bool +isCKKSEnabled(void) +{ +#if OCTAGON + return SecCKKSIsEnabled(); +#else + return false; +#endif +} + +// Replace old_item with new_item. If primary keys are the same this does an update otherwise it does a delete + add +bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error) { + __block bool ok = true; + __block CFErrorRef localError = NULL; + + CFDataRef old_pk = SecDbItemGetPrimaryKey(old_item, error); + CFDataRef new_pk = SecDbItemGetPrimaryKey(new_item, error); + + ok = old_pk && new_pk; + + bool pk_equal = ok && CFEqual(old_pk, new_pk); + if (pk_equal) { + ok = SecDbItemMakeYounger(new_item, old_item, error); + } else if(!CFEqualSafe(makeTombstone, kCFBooleanFalse) && isCKKSEnabled()) { + // The primary keys aren't equal, and we're going to make a tombstone. + // Help CKKS out: the tombstone should have the existing item's UUID, and the newly updated item should have a new UUID. + + s3dl_item_make_new_uuid(new_item, uuid_from_primary_key, error); + } + ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + + if (localError) { + if(CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { + /* Update failed because we changed the PrimaryKey and there was a dup. + Find the dup and see if it is a tombstone or corrupted item. */ + SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(new_item, error); + ok = query; + if (query) { + ok &= SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { + return attr->flags & kSecDbPrimaryKeyFlag; + }, NULL, NULL, ^(SecDbItemRef duplicate_item, bool *stop) { + bool is_corrupt = false; + bool is_tomb = false; + ok = SecDbItemIsCorrupt(duplicate_item, &is_corrupt, error); + if (ok && !is_corrupt) { + if ((is_tomb = SecDbItemIsTombstone(duplicate_item))) + ok = SecDbItemMakeYounger(new_item, duplicate_item, error); + } + if (ok && (is_corrupt || is_tomb)) { + ok = SecDbItemDoDelete(old_item, dbconn, error, ^bool (const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + ok = ok && SecDbItemDoUpdate(duplicate_item, new_item, dbconn, error, ^bool (const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + CFReleaseNull(localError); + } + }); + ok &= query_destroy(query, error); + } + } + + if (localError) { + ok = false; + if (error && *error == NULL) { + *error = localError; + localError = NULL; + } + CFReleaseSafe(localError); + } + } + + if (ok && !pk_equal && !CFEqualSafe(makeTombstone, kCFBooleanFalse)) { + /* The primary key of new_item is different than that of old_item, we + have been asked to make a tombstone so leave one for the old_item. */ + SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, makeTombstone, error); + ok = tombstone; + if (tombstone) { + ok = (SecDbItemClearRowId(tombstone, error) && + SecDbItemDoInsert(tombstone, dbconn, error)); + CFRelease(tombstone); + } + } + + return ok; +} + +// Replace the object with a tombstone +bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error) { + bool ok = false; + if (!CFEqualSafe(makeTombstone, kCFBooleanFalse)) { + SecDbItemRef tombstone = SecDbItemCopyTombstone(item, makeTombstone, error); + if (tombstone) { + ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + CFRelease(tombstone); + } + } else { + ok = SecDbItemDoDelete(item, dbconn, error, ^bool(const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + }); + } + return ok; +} + +CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query, + bool (^return_attr)(const SecDbAttr *attr), + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)) { + CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringAppend(sql, CFSTR("SELECT ")); + // What are we selecting? + bool needComma = false; + SecDbForEachAttr(query->q_class, attr) { + if (return_attr(attr)) + SecDbAppendElement(sql, attr->name, &needComma); + } + + // From which table? + CFStringAppend(sql, CFSTR(" FROM ")); + CFStringAppend(sql, query->q_class->name); + + // And which elements do we want to select + bool needWhere = true; + SecDbForEachAttr(query->q_class, attr) { + if (use_attr_in_where(attr)) { + CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name); + if (isArray(value)) { + CFArrayRef array = (CFArrayRef)value; + CFIndex length = CFArrayGetCount(array); + if (length > 0) { + CFTypeRef head = CFArrayGetValueAtIndex(array, 0); + if (CFEqualSafe(head, kCFNull)) { + SecDbAppendWhereOrAndNotIn(sql, attr->name, &needWhere, length - 1); + } else { + SecDbAppendWhereOrAndIn(sql, attr->name, &needWhere, length); + } + } + } else { + SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere); + } + } + } + // Append SQL for access groups and limits. + if (add_where_sql) + add_where_sql(sql, &needWhere); + + return sql; +} + +static bool SecDbItemSelectBindValue(SecDbQueryRef query, sqlite3_stmt *stmt, int param, const SecDbAttr *attr, CFTypeRef inValue, CFErrorRef *error) { + bool ok = true; + CFTypeRef value = NULL; + if (attr->kind == kSecDbRowIdAttr) { + // TODO: Ignores inValue and uses rowid directly instead HACK should go + value = CFNumberCreate(NULL, kCFNumberSInt64Type, &query->q_row_id); + } else { + value = SecDbAttrCopyValueForDb(attr, inValue, error); + } + ok = ok && value != NULL && SecDbBindObject(stmt, ++param, value, error); + CFReleaseSafe(value); + return ok; +} + +bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error, + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^bind_added_where)(sqlite3_stmt *stmt, int col)) { + __block bool ok = true; + __block int param = 0; + SecDbForEachAttr(query->q_class, attr) { + if (use_attr_in_where(attr)) { + CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name); + if (isArray(value)) { + CFArrayRef array = (CFArrayRef)value; + CFRange range = {.location = 0, .length = CFArrayGetCount(array) }; + if (range.length > 0) { + CFTypeRef head = CFArrayGetValueAtIndex(array, 0); + if (CFEqualSafe(head, kCFNull)) { + range.length--; + range.location++; + } + } + CFArrayApplyFunction(array, range, apply_block_1, (void (^)(const void *value)) ^(const void *arrayValue) { + ok = SecDbItemSelectBindValue(query, stmt, param++, attr, arrayValue, error); + }); + } else { + ok = SecDbItemSelectBindValue(query, stmt, param++, attr, value, error); + } + + if (!ok) + break; + } + } + // TODO: Bind arguments for access groups and limits. + if (bind_added_where) + bind_added_where(stmt, ++param); + + return ok; +} + +bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, + bool (^return_attr)(const SecDbAttr *attr), + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), + bool (^bind_added_where)(sqlite3_stmt *stmt, int col), + void (^handle_row)(SecDbItemRef item, bool *stop)) { + __block bool ok = true; + if (return_attr == NULL) { + return_attr = ^bool (const SecDbAttr * attr) { + return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr || attr->kind == kSecDbSHA1Attr; + }; + } + if (use_attr_in_where == NULL) { + use_attr_in_where = ^bool (const SecDbAttr* attr) { return false; }; + } + + CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql); + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) && + SecDbStep(dbconn, stmt, error, ^(bool *stop) { + SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr); + if (item) { + CFRetainAssign(item->credHandle, query->q_use_cred_handle); + handle_row(item, stop); + CFRelease(item); + } else { + //*stop = true; + //ok = false; + } + })); + }); + CFRelease(sql); + } else { + ok = false; + } + return ok; +} + diff --git a/keychain/securityd/SecDbItem.h b/keychain/securityd/SecDbItem.h new file mode 100644 index 00000000..586b8c00 --- /dev/null +++ b/keychain/securityd/SecDbItem.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecDbItem + The functions provided in SecDbItem provide an interface to + database items (certificates, keys, identities, and passwords). + */ + +#ifndef _SECURITYD_SECDBITEM_H_ +#define _SECURITYD_SECDBITEM_H_ + +#include +#include +#include // For CCSHA1_OUTPUT_SIZE +#include +#include "utilities/SecCFError.h" +#include "utilities/SecCFWrappers.h" +#include "utilities/SecDb.h" +#include "keychain/securityd/SecKeybagSupport.h" +#include +#include + +// MARK SecDbAttrKind, SecDbFlag + +typedef enum { + kSecDbBlobAttr, // CFString or CFData, preserves caller provided type. + kSecDbDataAttr, + kSecDbStringAttr, + kSecDbNumberAttr, + kSecDbDateAttr, + kSecDbCreationDateAttr, + kSecDbModificationDateAttr, + kSecDbSHA1Attr, + kSecDbRowIdAttr, + kSecDbEncryptedDataAttr, + kSecDbPrimaryKeyAttr, + kSecDbSyncAttr, + kSecDbTombAttr, + kSecDbUTombAttr, + kSecDbAccessAttr, + kSecDbAccessControlAttr, + kSecDbUUIDAttr, +} SecDbAttrKind; + +enum { + kSecDbPrimaryKeyFlag = (1 << 0), // attr is part of primary key + kSecDbInFlag = (1 << 1), // attr exists in db + kSecDbIndexFlag = (1 << 2), // attr should have a db index + kSecDbSHA1ValueInFlag = (1 << 3), // col in db is sha1 of attr value + kSecDbReturnAttrFlag = (1 << 4), + kSecDbReturnDataFlag = (1 << 5), + kSecDbReturnRefFlag = (1 << 6), + kSecDbInCryptoDataFlag = (1 << 7), + kSecDbInHashFlag = (1 << 8), + kSecDbInBackupFlag = (1 << 9), + kSecDbDefault0Flag = (1 << 10), // default attr value is 0 + kSecDbDefaultEmptyFlag = (1 << 11), // default attr value is "" + kSecDbNotNullFlag = (1 << 12), // attr value can't be null + kSecDbInAuthenticatedDataFlag = (1 << 13), // attr is in authenticated data + kSecDbSyncPrimaryKeyV0 = (1 << 14), + kSecDbSyncPrimaryKeyV2 = (1 << 15), + kSecDbSyncFlag = (1 << 16), +}; + +#define SecVersionDbFlag(v) ((v & 0xFF) << 8) + +#define SecDbFlagGetVersion(flags) ((flags >> 8) & 0xFF) + +#define SECDB_ATTR(var, name, kind, flags, copyValue, setValue) const SecDbAttr var = { CFSTR(name), kSecDb ## kind ## Attr, flags, copyValue, setValue } + +typedef struct SecDbItem *SecDbItemRef; +typedef struct SecDbAttr SecDbAttr; + +typedef CFTypeRef (*SecDbItemCopyAttrValue)(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); +typedef bool (*SecDbItemSetAttrValue)(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error); + +struct SecDbAttr { + CFStringRef name; + SecDbAttrKind kind; + CFOptionFlags flags; + SecDbItemCopyAttrValue copyValue; + SecDbItemSetAttrValue setValue; +}; + +typedef struct SecDbClass { + CFStringRef name; + bool itemclass; // true if keychain items are stored in this class, false otherwise + const SecDbAttr *attrs[]; +} SecDbClass; + +typedef struct SecDbSchema { + int majorVersion; + int minorVersion; + const SecDbClass *classes[]; +} SecDbSchema; + + +#define SecDbForEachAttr(class, attr) for (const SecDbAttr * const* _pattr = (class)->attrs, *attr = *_pattr; attr; attr = *(++_pattr)) + +#define SecDbForEachAttrWithMask(class, attr, flag_mask) SecDbForEachAttr(class, attr) if ((attr->flags & (flag_mask)) == (flag_mask)) + +CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error); + + +// MARK: SecDbItem + +enum SecDbItemState { + kSecDbItemDirty, // We have no edata (or if we do it's invalid), attributes are the truth + kSecDbItemEncrypted, // Attributes haven't been decrypted yet from edata + kSecDbItemClean, // Attributes and _edata are in sync. + kSecDbItemDecrypting, // Temporary state while we are decrypting so set knows not to blow away the edata. + kSecDbItemEncrypting, // Temporary state while we are encrypting so set knows to move to clean. + kSecDbItemAlwaysEncrypted, // As kSecDbItemEncrypted, but decryption is never attempted + kSecDbItemSecretEncrypted, // Metadata is clean, but the secret data remains encrypted +}; + +struct SecDbItem { + CFRuntimeBase _base; + const SecDbClass *class; + keyclass_t keyclass; + keybag_handle_t keybag; + enum SecDbItemState _edataState; + CFMutableDictionaryRef attributes; + CFDataRef credHandle; + CFTypeRef cryptoOp; + CFArrayRef callerAccessGroups; +}; + +// TODO: Make this a callback to client +bool SecDbItemDecrypt(SecDbItemRef item, bool decryptSecretData, CFDataRef edata, CFErrorRef *error); + +CFTypeID SecDbItemGetTypeID(void); + +static inline size_t SecDbClassAttrCount(const SecDbClass *dbClass) { + size_t n_attrs = 0; + SecDbForEachAttr(dbClass, attr) { n_attrs++; } + return n_attrs; +} + +const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error); + +SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error); + +const SecDbClass *SecDbItemGetClass(SecDbItemRef item); +keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item); +bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error); +void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle); +void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups); + +CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name); +CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error); +CFTypeRef SecDbItemGetValueKind(SecDbItemRef item, SecDbAttrKind desc, CFErrorRef *error); + +bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error); +bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error); +bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error); + +sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error); +bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error); +bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error); + +bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item); +bool SecDbItemIsSyncable(SecDbItemRef item); + +bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error); + +bool SecDbItemIsTombstone(SecDbItemRef item); + +CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error); + +CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error); +CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error); + +CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error); + +SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)); + +SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class, + CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error); + +SecDbItemRef SecDbItemCreateWithPrimaryKey(CFAllocatorRef allocator, const SecDbClass *class, CFDataRef primary_key); + +#if 0 +SecDbItemRef SecDbItemCreateWithRowId(CFAllocatorRef allocator, const SecDbClass *class, sqlite_int64 row_id, keybag_handle_t keybag, CFErrorRef *error); +#endif + +bool SecDbItemEnsureDecrypted(SecDbItemRef item, bool decryptSecretData, CFErrorRef *error); + +SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error); + +bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)); + +// SecDbItemInsertOrReplace returns an error even when it succeeds; use this to determine if it's spurious +bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error); + +bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error); + +bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error); + +bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error); + +// Low level update, just do the update +bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)); + +// High level update, will replace tombstones and create them if needed. +bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error); + + +// MARK: - +// MARK: SQL Construction helpers -- These should become private in the future + +void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma); +void SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere); +void SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere); +void SecDbAppendWhereOrAndNotEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere); +void SecDbAppendWhereOrAndIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count); +void SecDbAppendWhereOrAndNotIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count); + +// MARK: type converters. +// TODO: these should be static and private to SecDbItem, or part of the schema + +CFStringRef copyString(CFTypeRef obj); +CFDataRef copyData(CFTypeRef obj); +CFTypeRef copyBlob(CFTypeRef obj); +CFDataRef copySHA1(CFTypeRef obj); +CFTypeRef copyNumber(CFTypeRef obj); +CFDateRef copyDate(CFTypeRef obj); +CFTypeRef copyUUID(CFTypeRef obj); + +// MARK: cFErrorPropagate which handles errSecAuthNeeded +static inline +bool SecErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) { + if (possibleError && error && *error && CFErrorGetCode(*error) == errSecAuthNeeded) + CFReleaseNull(*error); + return CFErrorPropagate(possibleError, error); +} + +// TODO: Hack +bool SecDbItemInV2(SecDbItemRef item); +bool SecDbItemInV2AlsoInV0(SecDbItemRef item); + +// For debug output filtering +bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject); + +__END_DECLS + +#endif /* _SECURITYD_SECDBITEM_H_ */ diff --git a/keychain/securityd/SecDbKeychainItem.h b/keychain/securityd/SecDbKeychainItem.h new file mode 100644 index 00000000..ce889868 --- /dev/null +++ b/keychain/securityd/SecDbKeychainItem.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecDbKeychainItem.h - The thing that does the stuff with the gibli. + */ + +#ifndef _SECURITYD_SECKEYCHAINITEM_H_ +#define _SECURITYD_SECKEYCHAINITEM_H_ + +#include "keychain/securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbQuery.h" + +__BEGIN_DECLS + +bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error); +bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error); +bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error); // used for backup +bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context, + CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups, + CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error); +bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, + CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error); +SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error); +bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error); +bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error); + +CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); +CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error); +CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); +CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); +CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error); + +SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error); +bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error); + +void SecDbResetMetadataKeys(void); + +__END_DECLS + +#endif /* _SECURITYD_SECKEYCHAINITEM_H_ */ diff --git a/keychain/securityd/SecDbKeychainItem.m b/keychain/securityd/SecDbKeychainItem.m new file mode 100644 index 00000000..7e52fc36 --- /dev/null +++ b/keychain/securityd/SecDbKeychainItem.m @@ -0,0 +1,1542 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecDbKeychainItem.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#include "keychain/securityd/SecDbKeychainItem.h" + +#import "SecInternalReleasePriv.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#import "SecDbKeychainItemV7.h" +#import "SecDbKeychainMetadataKeyStore.h" +#import "sec_action.h" + +#if USE_KEYSTORE +#include +#include +#include +#include +#include "keychain/securityd/spi.h" + +#endif /* USE_KEYSTORE */ + +#include "OSX/utilities/SecAKSWrappers.h" + +pthread_key_t CURRENT_CONNECTION_KEY; + +// From SecItemServer, should be a acl-check block +bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); + +static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error); +static CFTypeRef kc_encode_keyclass(keyclass_t keyclass); +static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control); +static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end); +static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error); +static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error); +#if USE_KEYSTORE +static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version, + CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error); +static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes); +static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error); +#endif + +static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFOptionFlags mutability, CFPropertyListRef* cf, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end)); +static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end)); +static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end)); +static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end)); +static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFSetRef* set, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end)); + +const uint32_t kUseDefaultIVMask = 1<<31; +const int16_t kIVSizeAESGCM = 12; + +// echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i +static const uint8_t gcmIV[kIVSizeAESGCM] = { + 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24 +}; + +/* Given plainText create and return a CFDataRef containing: + BULK_KEY = RandomKey() + version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) || + AES(BULK_KEY, NULL_IV, plainText || padding) + */ +bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) { + CFMutableDataRef blob = NULL; + CFDataRef ac_data = NULL; + bool ok = true; + //check(keybag >= 0); + + /* Precalculate output blob length. */ + const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */ + const uint32_t maxKeyWrapOverHead = 8 + 32; + uint8_t bulkKey[bulkKeySize]; + CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0); + CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead); + uint32_t key_wrapped_size; + size_t ivLen = 0; + const uint8_t *iv = NULL; + const uint8_t *aad = NULL; // Additional Authenticated Data + ptrdiff_t aadLen = 0; + +#if USE_KEYSTORE + CFDataRef auth_data = NULL; +#endif + + /* If access_control specifies only protection and no ACL, use legacy blob format version 3, + which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */ + bool hasACLConstraints = SecAccessControlGetConstraints(access_control); + const uint32_t version = (hasACLConstraints ? 6 : 3); + CFDataRef plainText = NULL; + if (version < 4) { + CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); + if (authenticated_attributes) { + CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { + CFDictionaryAddValue(attributes_dict, key, value); + }); + } + + if (attributes_dict) { + // Drop the accc attribute for non v6 items during encode. + CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl); + plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error); + CFRelease(attributes_dict); + } + } else { +#if USE_KEYSTORE + if (attributes) { + plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes, error); + } +#else + CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); + if (authenticated_attributes) { + CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { + CFDictionaryAddValue(attributes_dict, key, value); + }); + } + + if (attributes_dict) { + plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error); + CFRelease(attributes_dict); + } +#endif + } + + if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID() + || access_control == 0) { + ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text")); + goto out; + } + + size_t ptLen = CFDataGetLength(plainText); + size_t ctLen = ptLen; + size_t tagLen = 16; + keyclass_t actual_class = 0; + + if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) { + ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed")); + goto out; + } + + /* Extract keyclass from access control. */ + keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); + if (!keyclass) + goto out; + +#if USE_KEYSTORE + if (version >= 4) { + auth_data = kc_create_auth_data(access_control, authenticated_attributes); + require_quiet(ok = ks_encrypt_acl(keybag, keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, auth_data, acm_context, access_control, error), out); + } else +#endif + { + /* Encrypt bulkKey. */ + require_quiet(ok = ks_crypt(kAKSKeyOpEncrypt, keybag, + keyclass, bulkKeySize, bulkKey, + &actual_class, bulkKeyWrapped, + error), out); + } + + key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped); + UInt8 *cursor; + size_t blobLen = sizeof(version); + uint32_t prot_length = 0; + + if (!hasACLConstraints) { + blobLen += sizeof(actual_class); + } else { + require_quiet(ac_data = kc_copy_protection_data(access_control), out); + prot_length = (uint32_t)CFDataGetLength(ac_data); + blobLen += sizeof(prot_length) + prot_length; + } + + blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen; + require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out); + CFDataSetLength(blob, blobLen); + cursor = CFDataGetMutableBytePtr(blob); + + *((uint32_t *)cursor) = useDefaultIV ? (version | kUseDefaultIVMask) : version; + cursor += sizeof(version); + + //secerror("class: %d actual class: %d", keyclass, actual_class); + if (!hasACLConstraints) { + *((keyclass_t *)cursor) = actual_class; + cursor += sizeof(keyclass); + } else { + *((uint32_t *)cursor) = prot_length; + cursor += sizeof(prot_length); + + CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor); + cursor += prot_length; + } + + *((uint32_t *)cursor) = key_wrapped_size; + cursor += sizeof(key_wrapped_size); + + if (useDefaultIV) { + iv = gcmIV; + ivLen = kIVSizeAESGCM; + // AAD is (version || ac_data || key_wrapped_size) + aad = CFDataGetMutableBytePtr(blob); + aadLen = cursor - aad; + } + + memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size); + cursor += key_wrapped_size; + + /* Encrypt the plainText with the bulkKey. */ + CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128, + bulkKey, bulkKeySize, + iv, ivLen, /* iv */ + aad, aadLen, /* auth data */ + CFDataGetBytePtr(plainText), ptLen, + cursor, + cursor + ctLen, &tagLen); + if (ccerr) { + ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr); + goto out; + } + if (tagLen != 16) { + ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); + goto out; + } + + out: + memset(bulkKey, 0, sizeof(bulkKey)); + CFReleaseSafe(ac_data); + CFReleaseSafe(bulkKeyWrapped); + CFReleaseSafe(plainText); + if (!ok) { + CFReleaseSafe(blob); + } else { + *pBlob = blob; + } + +#if USE_KEYSTORE + CFReleaseSafe(auth_data); +#endif + return ok; +} + +static void +ks_warn_non_device_keybag(void) +{ + static dispatch_once_t once; + static sec_action_t action; + + dispatch_once(&once, ^{ + action = sec_action_create("non-device keybag", 2); + sec_action_set_handler(action, ^{ + secwarning("ks_encrypt_data: called with non-device keybag - call should be rerouted to ks_encrypt_data_legacy"); + }); + }); + sec_action_perform(action); +} + +bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) { + return ks_encrypt_data_with_backupuuid(keybag, access_control, acm_context, secretData, attributes, authenticated_attributes, pBlob, NULL, useDefaultIV, error); +} + +bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context, + CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error) { + if (keybag != KEYBAG_DEVICE) { + ks_warn_non_device_keybag(); + + CFMutableDictionaryRef allAttributes = CFDictionaryCreateMutableCopy(NULL, CFDictionaryGetCount(secretData) + CFDictionaryGetCount(attributes), attributes); + CFDictionaryForEach(secretData, ^(const void *key, const void *value) { + CFDictionaryAddValue(allAttributes, key, value); + }); + bool result = ks_encrypt_data_legacy(keybag, access_control, acm_context, allAttributes, authenticated_attributes, pBlob, useDefaultIV, error); + CFReleaseNull(allAttributes); + return result; + } + + keyclass_t key_class = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); + if (!key_class) { + return false; + } + + if (SecAccessControlGetConstraints(access_control)) { + NSMutableDictionary* allAttributes = [(__bridge NSDictionary*)attributes mutableCopy]; + [allAttributes addEntriesFromDictionary:(__bridge NSDictionary*)secretData]; + return ks_encrypt_data_legacy(keybag, access_control, acm_context, (__bridge CFDictionaryRef)allAttributes, authenticated_attributes, pBlob, useDefaultIV, error); + } + + bool success = false; + @autoreleasepool { + NSMutableDictionary* metadataAttributes = attributes ? [(__bridge NSDictionary*)attributes mutableCopy] : [NSMutableDictionary dictionary]; + [metadataAttributes addEntriesFromDictionary:(__bridge NSDictionary*)authenticated_attributes]; + metadataAttributes[@"SecAccessControl"] = (__bridge_transfer NSData*)SecAccessControlCopyData(access_control); + + NSString* tamperCheck = [[NSUUID UUID] UUIDString]; // can use the item persistent reference when that starts getting filled in + SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:(__bridge NSDictionary*)secretData metadataAttributes:metadataAttributes tamperCheck:tamperCheck keyclass:key_class]; + + NSError* localError = nil; + NSData* encryptedBlob = [item encryptedBlobWithKeybag:keybag accessControl:access_control acmContext:(__bridge NSData*)acm_context error:&localError]; + if (encryptedBlob) { + NSMutableData* encryptedBlobWithVersion = [NSMutableData dataWithLength:encryptedBlob.length + sizeof(uint32_t)]; + *((uint32_t*)encryptedBlobWithVersion.mutableBytes) = (uint32_t)7; + memcpy((uint32_t*)encryptedBlobWithVersion.mutableBytes + 1, encryptedBlob.bytes, encryptedBlob.length); + *pBlob = (__bridge_retained CFDataRef)encryptedBlobWithVersion; + if (bkUUID && item.backupUUID) { // TODO: Failing this should turn into at least a stern warning at some point + *bkUUID = (__bridge_retained CFDataRef)[item.backupUUID copy]; + } + success = true; + } + else { + if (error) { + *error = (__bridge_retained CFErrorRef)localError; + } + } + } + + return success; +} + +/* Given cipherText containing: + version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) || + AES(BULK_KEY, NULL_IV, plainText || padding) + return the plainText. */ +bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context, + CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups, + CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error) { + const uint32_t v0KeyWrapOverHead = 8; + CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */ + CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */ + bool ok = true; + SecAccessControlRef access_control = NULL; + + if (attributes_p) + *attributes_p = NULL; + if (version_p) + *version_p = 0; + + CFMutableDataRef plainText = NULL; + CFMutableDictionaryRef attributes = NULL; + uint32_t version = 0; + size_t ivLen = 0; + const uint8_t *iv = NULL; + const uint8_t *aad = NULL; // Additional Authenticated Data + ptrdiff_t aadLen = 0; + +#if USE_KEYSTORE + CFMutableDictionaryRef authenticated_attributes = NULL; + CFDataRef caller_access_groups_data = NULL; + CFDataRef ed_data = NULL; + aks_ref_key_t ref_key = NULL; +#if TARGET_OS_IPHONE + check(keybag >= 0); +#else + check((keybag >= 0) || (keybag == session_keybag_handle)); +#endif +#endif + + if (!blob) { + ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob")); + goto out; + } + + size_t blobLen = CFDataGetLength(blob); + const uint8_t *cursor = CFDataGetBytePtr(blob); + keyclass_t keyclass; + + if (blobLen < sizeof(version)) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (length)")); + goto out; + } + + version = *((uint32_t *)cursor); + if (version & kUseDefaultIVMask) { + version &= ~kUseDefaultIVMask; + iv = gcmIV; + ivLen = kIVSizeAESGCM; + } + + cursor += sizeof(version); + blobLen -= sizeof(version); + + bool hasProtectionData = (version >= 4 && version < 7); + + if (version >= 7) { + @autoreleasepool { + NSError* localError = nil; + NSData* encryptedBlob = [NSData dataWithBytes:cursor length:blobLen]; + SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithData:encryptedBlob decryptionKeybag:keybag error:&localError]; + if (outKeyclass) { + *outKeyclass = item.keyclass; + } + + NSMutableDictionary* itemAttributes = [[item metadataAttributesWithError:&localError] mutableCopy]; + if (itemAttributes && !localError) { + NSData* accessControlData = itemAttributes[@"SecAccessControl"]; + access_control = SecAccessControlCreateFromData(NULL, (__bridge CFDataRef)accessControlData, error); + [itemAttributes removeObjectForKey:@"SecAccessControl"]; + + if (decryptSecretData) { + NSDictionary* secretAttributes = [item secretAttributesWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError]; + if (secretAttributes) { + [itemAttributes addEntriesFromDictionary:secretAttributes]; + } + else { + ok = false; + } + } + + if (ok) { + if (CFEqual(kAKSKeyOpDelete, cryptoOp)) { + ok = [item deleteWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError]; + } + + attributes = (__bridge_retained CFMutableDictionaryRef)itemAttributes; + } + } + else { + ok = false; + } + + if (!ok && error) { + *error = (__bridge_retained CFErrorRef)localError; + } + } + goto out; + } + + if (hasProtectionData) { + /* Deserialize SecAccessControl object from the blob. */ + uint32_t prot_length; + + /* + * Parse proto length + */ + + if (blobLen < sizeof(prot_length)) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot_length)")); + goto out; + } + + prot_length = *((uint32_t *)cursor); + cursor += sizeof(prot_length); + blobLen -= sizeof(prot_length); + + /* + * Parse proto itself + */ + + if (blobLen < prot_length) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot)")); + goto out; + } + + CFTypeRef protection = kc_copy_protection_from(cursor, cursor + prot_length); + if (!protection) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); + goto out; + } else { + access_control = SecAccessControlCreate(NULL, NULL); + require_quiet(access_control, out); + ok = SecAccessControlSetProtection(access_control, protection, NULL); + CFRelease(protection); + if (!ok) { + SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); + goto out; + } + } + + cursor += prot_length; + blobLen -= prot_length; + + /* + * Get numeric value of keyclass from the access_control. + */ + keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); + if (!keyclass) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); + goto out; + } + } else { + if (blobLen < sizeof(keyclass)) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (keyclass)")); + goto out; + } + + keyclass = *((keyclass_t *)cursor); + +#if USE_KEYSTORE + CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation +#else + CFTypeRef protection = kc_encode_keyclass(keyclass); +#endif + require_action_quiet(protection, out, ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected"))); + require_action_quiet(access_control = SecAccessControlCreate(kCFAllocatorDefault, error), out, + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlCreate failed"))); + require_action_quiet(SecAccessControlSetProtection(access_control, protection, error), out, + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed"))); + + cursor += sizeof(keyclass); + blobLen -= sizeof(keyclass); + } + + size_t tagLen = 0; + uint32_t wrapped_key_size = 0; + + switch (version) { + case 0: + wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead; + break; + case 2: + case 3: + /* DROPTHROUGH */ + /* v2 and v3 have the same crypto, just different dictionary encodings. */ + /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */ + case 4: + case 5: + case 6: + tagLen = 16; + /* DROPTHROUGH */ + case 1: + if (blobLen < sizeof(wrapped_key_size)) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key_size)")); + goto out; + } + wrapped_key_size = *((uint32_t *)cursor); + + cursor += sizeof(wrapped_key_size); + blobLen -= sizeof(wrapped_key_size); + + break; + default: + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version); + goto out; + } + + if (blobLen < tagLen + wrapped_key_size) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key/taglen)")); + goto out; + } + + size_t ctLen = blobLen - tagLen - wrapped_key_size; + + /* + * Pre-version 2 have some additial constraints since it use AES in CBC mode + */ + if (version < 2) { + if (ctLen < kCCBlockSizeAES128) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (CBC check)")); + goto out; + } + if ((ctLen & 0xF) != 0) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid length on CBC data")); + goto out; + } + } + +#if USE_KEYSTORE + if (hasProtectionData) { + if (caller_access_groups) { + caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error); + require_quiet(ok = (caller_access_groups_data != NULL), out); + } + + require_quiet(ok = kc_attribs_key_encrypted_data_from_blob(keybag, db_class, cursor, wrapped_key_size, access_control, version, + &authenticated_attributes, &ref_key, &ed_data, error), out); + if (CFEqual(cryptoOp, kAKSKeyOpDecrypt)) { + require_quiet(ok = ks_decrypt_acl(ref_key, ed_data, bulkKey, acm_context, caller_access_groups_data, access_control, error), out); + } else if (CFEqual(cryptoOp, kAKSKeyOpDelete)) { + require_quiet(ok = ks_delete_acl(ref_key, ed_data, acm_context, caller_access_groups_data, access_control, error), out); + attributes = CFRetainSafe(authenticated_attributes); + goto out; + } else { + ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: invalid operation")); + goto out; + } + } else +#endif + { + /* Now unwrap the bulk key using a key in the keybag. */ + require_quiet(ok = ks_crypt(cryptoOp, keybag, + keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out); + } + + if (iv) { + // AAD is (version || ... [|| key_wrapped_size ]) + aad = CFDataGetBytePtr(blob); + aadLen = cursor - aad; + } + + cursor += wrapped_key_size; + + plainText = CFDataCreateMutable(NULL, ctLen); + if (!plainText) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text")); + goto out; + } + CFDataSetLength(plainText, ctLen); + + /* Decrypt the cipherText with the bulkKey. */ + CCCryptorStatus ccerr; + if (tagLen) { + uint8_t tag[tagLen]; + ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128, + CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), + iv, ivLen, /* iv */ + aad, aadLen, /* auth data */ + cursor, ctLen, + CFDataGetMutableBytePtr(plainText), + tag, &tagLen); + if (ccerr) { + /* TODO: Should this be errSecDecode once AppleKeyStore correctly + identifies uuid unwrap failures? */ + /* errSecInteractionNotAllowed; */ + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr); + goto out; + } + if (tagLen != 16) { + ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); + goto out; + } + cursor += ctLen; + if (timingsafe_bcmp(tag, cursor, tagLen)) { + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob")); + goto out; + } + } else { + size_t ptLen; + ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, + CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen, + CFDataGetMutableBytePtr(plainText), ctLen, &ptLen); + if (ccerr) { + /* TODO: Should this be errSecDecode once AppleKeyStore correctly + identifies uuid unwrap failures? */ + /* errSecInteractionNotAllowed; */ + ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr); + goto out; + } + CFDataSetLength(plainText, ptLen); + } + + if (version < 2) { + attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText); + } else if (version < 3) { + attributes = s3dl_item_v2_decode(plainText, error); + } else { + attributes = s3dl_item_v3_decode(plainText, error); + } + + require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@", version, error ? *error : NULL); }); + +#if USE_KEYSTORE + if (version >= 4 && authenticated_attributes != NULL) { + CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { + CFDictionaryAddValue(attributes, key, value); + }); + } +#endif + +out: + memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey)); + CFReleaseNull(bulkKey); + CFReleaseNull(plainText); + + // Always copy access control data (if present), because if we fail it may indicate why. + if (paccess_control) + *paccess_control = access_control; + else + CFReleaseNull(access_control); + + if (ok) { + if (attributes_p) + CFRetainAssign(*attributes_p, attributes); + if (version_p) + *version_p = version; + } + CFReleaseNull(attributes); +#if USE_KEYSTORE + CFReleaseNull(authenticated_attributes); + CFReleaseNull(caller_access_groups_data); + CFReleaseNull(ed_data); + if (ref_key) aks_ref_key_free(&ref_key); +#endif + return ok; +} + +static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) { + if (!isString(value)) { + SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value); + } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) { + return key_class_ak; + } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) { + return key_class_ck; + } else if (CFEqual(value, kSecAttrAccessibleAlwaysPrivate)) { + return key_class_dk; + } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) { + return key_class_aku; + } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) { + return key_class_cku; + } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) { + return key_class_dku; + } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { + return key_class_akpu; + } else { + SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value); + } + return 0; +} + +static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) { + switch (keyclass) { + case key_class_ak: + return kSecAttrAccessibleWhenUnlocked; + case key_class_ck: + return kSecAttrAccessibleAfterFirstUnlock; + case key_class_dk: + return kSecAttrAccessibleAlwaysPrivate; + case key_class_aku: + return kSecAttrAccessibleWhenUnlockedThisDeviceOnly; + case key_class_cku: + return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + case key_class_dku: + return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate; + case key_class_akpu: + return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; + default: + return 0; + } +} + +#if USE_KEYSTORE +static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version, + CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error) +{ + CFMutableDictionaryRef acl = NULL; + CFDictionaryRef blob_dict = NULL; + aks_ref_key_t tmp_ref_key = NULL; + CFDataRef key_data = NULL; + CFDataRef ed = NULL; + bool ok = false; + + der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len); + require_action_quiet(blob_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'"))); + + if (!ks_separate_data_and_key(blob_dict, &ed, &key_data)) { + ed = CFDataCreate(kCFAllocatorDefault, blob_data, blob_data_len); + key_data = CFRetain(ed); + } + require_action_quiet(ed, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'"))); + require_action_quiet(key_data, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'"))); + + const void *external_data = NULL; + size_t external_data_len = 0; + require_quiet(external_data = ks_ref_key_get_external_data(keybag, key_data, &tmp_ref_key, &external_data_len, error), out); + + CFPropertyListRef external_data_dict = NULL; + der_decode_plist(NULL, kCFPropertyListImmutable, &external_data_dict, NULL, external_data, external_data + external_data_len); + require_action_quiet(external_data_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'"))); + acl = CFDictionaryCreateMutableCopy(NULL, 0, external_data_dict); + SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) { + CFDictionaryRemoveValue(acl, attr_desc->name); + CFTypeRef value = CFDictionaryGetValue(external_data_dict, attr_desc->name); + if (value) { + if (!*authenticated_attributes) + *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value); + } + } + CFReleaseSafe(external_data_dict); + + if (acl) { + /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */ + if (version == 4) { + SecAccessControlSetConstraints(access_control, acl); + } else { + CFDictionaryRef constraints = CFDictionaryGetValue(acl, kAKSKeyAcl); + require_action_quiet(isDictionary(constraints), out, + SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: acl missing"))); + SecAccessControlSetConstraints(access_control, constraints); + } + + /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */ + if (version < 6) { + SecAccessConstraintRef encryptConstraint = SecAccessControlGetConstraint(access_control, kAKSKeyOpEncrypt); + if (!encryptConstraint) + SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL); + } + + } + + if (encrypted_data) + *encrypted_data = CFRetain(ed); + + if (ref_key) { + *ref_key = tmp_ref_key; + tmp_ref_key = NULL; + } + + ok = true; + +out: + if (tmp_ref_key) + aks_ref_key_free(&tmp_ref_key); + CFReleaseSafe(blob_dict); + CFReleaseSafe(key_data); + CFReleaseSafe(ed); + CFReleaseSafe(acl); + + + return ok; +} + +static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) { + CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control); + CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, auth_attributes); + CFDictionarySetValue(auth_data, kAKSKeyAcl, constraints); + CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL); + CFReleaseSafe(auth_data); + return encoded; +} + +static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error) +{ + size_t ag_size = der_sizeof_plist(access_groups, error); + CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0); + CFDataSetLength(result, ag_size); + if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) { + CFRelease(result); + return NULL; + } + else + return result; +} + +#endif /* USE_KEYSTORE */ + +static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control) +{ + CFTypeRef protection = SecAccessControlGetProtection(access_control); + size_t protection_size = der_sizeof_plist(protection, NULL); + CFMutableDataRef result = CFDataCreateMutable(NULL, 0); + CFDataSetLength(result, protection_size); + if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) { + CFRelease(result); + return NULL; + } + else + return result; +} + +static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end) +{ + CFTypeRef result = NULL; + der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, der, der_end); + return result; +} + +/* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */ +static CF_RETURNS_RETAINED +CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) { + if (plist && !isDictionary(plist)) { + CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist)); + SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName); + CFReleaseSafe(typeName); + CFReleaseNull(plist); + } + return (CFMutableDictionaryRef)plist; +} + +static CF_RETURNS_RETAINED +CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) { + CFPropertyListRef item; + item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error); + return dictionaryFromPlist(item, error); +} + +static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) = + ^const uint8_t*(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) { + if (error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) { + CFAbsoluteTime date = 0; + CFCalendarRef calendar = CFCalendarCreateWithIdentifier(allocator, kCFGregorianCalendar); + CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, 0); + CFCalendarSetTimeZone(calendar, tz); + CFCalendarComposeAbsoluteTime(calendar, &date, "yMd", 2001, 3, 24); // random date for 15A143: can't recover keychain + CFReleaseSafe(tz); + CFReleaseSafe(calendar); + + *pl = CFDateCreate(allocator, date); + if (NULL != *pl) { + CFReleaseNull(*error); + return der_end; + } + } + return NULL; +}; + +static CF_RETURNS_RETAINED +CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) { + CFPropertyListRef item = NULL; + const uint8_t *der_beg = CFDataGetBytePtr(plain); + const uint8_t *der_end = der_beg + CFDataGetLength(plain); + const uint8_t *der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end); + if (!der && error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) { + CFReleaseNull(*error); + der = der_decode_plist_with_repair(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date); + } + if (der && der != der_end) { + SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error); + CFReleaseNull(item); + } + return dictionaryFromPlist(item, error); +} + +bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, + CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error) { + SecAccessControlRef ac = NULL; + CFDataRef ac_data = NULL; + bool ok = false; + + /* Decrypt and decode the item and check the decoded attributes against the query. */ + uint32_t version = 0; + + bool decryptSecretData = false; + if ((q->q_return_type & kSecReturnDataMask) || (q->q_return_type & kSecReturnRefMask)) { + decryptSecretData = true; + } + else if (q->q_match_policy || q->q_match_valid_on_date || q->q_match_trusted_only) { + decryptSecretData = true; + } + + require_quiet((ok = ks_decrypt_data(q->q_keybag, kAKSKeyOpDecrypt, &ac, q->q_use_cred_handle, edata, q->q_class, + q->q_caller_access_groups, item, &version, decryptSecretData, keyclass, error)), out); + if (version < 2) { + SecError(errSecDecode, error, CFSTR("version is unexpected: %d"), (int)version); + ok = false; + goto out; + } + + ac_data = SecAccessControlCopyData(ac); + if (!itemInAccessGroup(*item, accessGroups)) { + secerror("items accessGroup '%@' not in %@", + CFDictionaryGetValue(*item, kSecAttrAccessGroup), + accessGroups); + // We likely don't want to surface it to clients like this, but this is most accurate + SecError(errSecMissingEntitlement, error, CFSTR("item's access group '%@' not in %@"), + CFDictionaryGetValue(*item, kSecAttrAccessGroup), accessGroups); + CFReleaseNull(*item); + ok = false; + goto out; + } + + /* AccessControl attribute does not exist in the db, so synthesize it. */ + if (version > 3) + CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data); + + /* TODO: Validate access_control attribute. */ + +out: + if (access_control) + *access_control = CFRetainSafe(ac); + CFReleaseSafe(ac); + CFReleaseSafe(ac_data); + return ok; +} + +/* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items + being imported from a backup. */ +static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) { + bool ok = true; + CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); + CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); + + if (!isString(agrp) || !isString(accessible)) + return ok; + if (SecDbItemGetClass(item) == genp_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { + CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService); + if (!isString(svce)) return ok; + if (CFEqual(agrp, CFSTR("apple"))) { + if (CFEqual(svce, CFSTR("AirPort"))) { + ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); + } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) { + ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); + } else if (CFEqual(svce, CFSTR("YouTube"))) { + ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) && + SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error)); + } else { + CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription); + if (!isString(desc)) return ok; + if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) { + ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); + } + } + } + } else if (SecDbItemGetClass(item) == inet_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { + if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) { + ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); + } else if (CFEqual(agrp, CFSTR("apple"))) { + CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); + bool is_proxy = false; + if (isNumber(ptcl)) { + SInt32 iptcl; + CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl); + is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') || + iptcl == FOUR_CHAR_CODE('htsx') || + iptcl == FOUR_CHAR_CODE('ftpx') || + iptcl == FOUR_CHAR_CODE('rtsx') || + iptcl == FOUR_CHAR_CODE('xpth') || + iptcl == FOUR_CHAR_CODE('xsth') || + iptcl == FOUR_CHAR_CODE('xptf') || + iptcl == FOUR_CHAR_CODE('xstr')); + } else if (isString(ptcl)) { + is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) || + CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) || + CFEqual(ptcl, kSecAttrProtocolRTSPProxy) || + CFEqual(ptcl, kSecAttrProtocolFTPProxy)); + } + if (is_proxy) + ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); + } + } + return ok; +} + +bool SecDbItemDecrypt(SecDbItemRef item, bool decryptSecretData, CFDataRef edata, CFErrorRef *error) { + bool ok = true; + CFMutableDictionaryRef dict = NULL; + SecAccessControlRef access_control = NULL; + uint32_t version = 0; + + require_quiet(ok = ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, item->credHandle, edata, + item->class, item->callerAccessGroups, &dict, &version, decryptSecretData, NULL, error), out); + + if (version < 2) { + /* Old V4 style keychain backup being imported. */ + ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) && + SecDbItemImportMigrate(item, error); + } else { + ok = dict && SecDbItemSetValues(item, dict, error); + } + + SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error); + if (!my_access_control) { + ok = false; + goto out; + } + + /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got + back from decoding the data blob. */ + if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) { + ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"), + SecAccessControlGetProtection(my_access_control), + SecAccessControlGetProtection(access_control)); + } + CFRelease(my_access_control); + +out: + // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else + // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually + // decrypt the data. + ok = SecDbItemSetAccessControl(item, access_control, NULL) && ok; + + CFReleaseSafe(dict); + CFReleaseSafe(access_control); + return ok; +} + +/* Automagically make a item syncable, based on various attributes. */ +bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error) +{ + CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); + + if (!isString(agrp)) + return true; + + if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == inet_class()) { + CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer); + CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); + CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType); + + if (isString(srvr) && isString(ptcl) && isString(atyp)) { + /* This looks like a Mobile Safari Password, make syncable */ + secnotice("item", "Make this item syncable: %@", item); + return SecDbItemSetSyncable(item, true, error); + } + } + + return true; +} + +/* This create a SecDbItem from the item dictionnary that are exported for backups. + Item are stored in the backup as a dictionary containing two keys: + - v_Data: the encrypted data blob + - v_PersistentRef: a persistent Ref. + src_keybag is normally the backup keybag. + dst_keybag is normally the device keybag. + */ +SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error) +{ + CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data")); + SecDbItemRef item = NULL; + + if (edata) { + item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error); + if (item) + if (!SecDbItemSetKeybag(item, dst_keybag, error)) + CFReleaseNull(item); + } else { + SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict); + } + + return item; +} + +bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) { + CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef")); + if (!ref) + return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict); + + CFStringRef className; + sqlite3_int64 rowid; + if (!_SecItemParsePersistentRef(ref, &className, &rowid, NULL)) + return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref); + + if (!CFEqual(SecDbItemGetClass(item)->name, className)) + return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className); + + return SecDbItemSetRowId(item, rowid, error); +} + +static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { + CFDataRef der = NULL; + CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error); + if (dict) { + der = CFPropertyListCreateDERData(kCFAllocatorDefault, dict, error); + CFRelease(dict); + } + return der; +} + +static CFTypeRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { + CFDataRef digest = NULL; + CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error); + if (der) { + digest = CFDataCopySHA1Digest(der, error); + CFRelease(der); + } + return digest; +} + +static CFTypeRef SecDbItemCopySHA256DigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { + CFDataRef digest = NULL; + CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error); + if (der) { + digest = CFDataCopySHA256Digest(der, error); + CFRelease(der); + } + return digest; +} + +CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { + return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error); +} + +CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error) { + return SecDbItemCopySHA256DigestWithMask(item, kSecDbPrimaryKeyFlag, error); +} + +CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { + return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error); +} + +CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { + CFDataRef edata = NULL; + CFDataRef bkuuid = NULL; + CFMutableDictionaryRef secretStuff = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error); + CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); + CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); + if (secretStuff || attributes || auth_attributes) { + SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error); + CFDataRef sha1 = SecDbKeychainItemCopySHA1(item, attr, error); + if (access_control && sha1) { + if (!auth_attributes) { + auth_attributes = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(auth_attributes, kSecAttrSHA1, sha1); + + CFDictionaryForEach(secretStuff, ^(const void *key, const void *value) { + CFDictionaryRemoveValue(attributes, key); + CFDictionaryRemoveValue(auth_attributes, key); + }); + + if (ks_encrypt_data_with_backupuuid(item->keybag, access_control, item->credHandle, secretStuff, attributes, auth_attributes, &edata, &bkuuid, true, error)) { + item->_edataState = kSecDbItemEncrypting; + } else if (!error || !*error || CFErrorGetCode(*error) != errSecAuthNeeded || !CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain) ) { + seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR("")); + } + CFRelease(access_control); + } + CFReleaseNull(secretStuff); + CFReleaseNull(attributes); + CFReleaseNull(auth_attributes); + CFReleaseNull(sha1); + if (bkuuid) { + // "data" is defined first in the schema so called first. The UUID will therefore be in the cache when ForEach gets to it + CFErrorRef localError = NULL; + SecDbItemSetValueWithName(item, CFSTR("backupUUID"), bkuuid, &localError); + if (localError) { + // Don't want to propagate this. It's bad but should be handled in the manager and not interrupt production + secerror("Unable to wrap keychain item to backup: %@", localError); + CFReleaseNull(localError); + CFReleaseNull(bkuuid); + } + } + } + return edata; +} + +CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { + CFTypeRef value = NULL; + switch (attr->kind) { + case kSecDbDateAttr: + value = CFDateCreate(kCFAllocatorDefault, 0.0); + break; + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); + break; + default: + SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name); + value = NULL; + } + + return value; +} + +SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error) { + SecAccessControlRef accc = NULL, pdmn = NULL, result = NULL; + CFTypeRef acccData = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), error); + CFTypeRef pdmnValue = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error); + + if (!acccData || !pdmnValue) + return NULL; + if (!CFEqual(acccData, kCFNull)) + require_quiet(accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, error), out); + + if (!CFEqual(pdmnValue, kCFNull)) { + require_quiet(pdmn = SecAccessControlCreate(CFGetAllocator(item), error), out); + require_quiet(SecAccessControlSetProtection(pdmn, pdmnValue, error), out); + } + + if (accc && pdmn) { + CFTypeRef acccProt = SecAccessControlGetProtection(accc); + CFTypeRef pdmnProt = SecAccessControlGetProtection(pdmn); + if (!acccProt || !pdmnProt || !CFEqual(acccProt, pdmnProt)) { + secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt, pdmnProt); + __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem); + // Setting pdmn to accc prot value. + require_quiet(SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), acccProt, error), out); + } + } + + if (accc) + CFRetainAssign(result, accc); + else if(pdmn) + CFRetainAssign(result, pdmn); + +out: + CFReleaseSafe(accc); + CFReleaseSafe(pdmn); + + return result; +} + +static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, + CFPropertyListRef* pl, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, + const uint8_t*, const uint8_t*)) +{ + if (NULL == der) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); + return NULL; + } + + ccder_tag tag; + if (NULL == ccder_decode_tag(&tag, der, der_end)) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error); + return NULL; + } + + switch (tag) { + case CCDER_NULL: + return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end); + case CCDER_BOOLEAN: + return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end); + case CCDER_OCTET_STRING: + return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end); + case CCDER_GENERALIZED_TIME: { + const uint8_t* der_result = der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end); + if (!der_result) { + der_result = repairBlock(allocator, mutability, pl, error, der, der_end); + } + return der_result; + } + case CCDER_CONSTRUCTED_SEQUENCE: + return der_decode_array_with_repair(allocator, mutability, (CFArrayRef*)pl, error, der, der_end, repairBlock); + case CCDER_UTF8_STRING: + return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end); + case CCDER_INTEGER: + return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end); + case CCDER_CONSTRUCTED_SET: + return der_decode_dictionary_with_repair(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end, repairBlock); + case CCDER_CONSTRUCTED_CFSET: + return der_decode_set_with_repair(allocator, mutability, (CFSetRef*)pl, error, der, der_end, repairBlock); + default: + SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error); + return NULL; + } +} + +static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, + CFDictionaryRef* dictionary, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, + const uint8_t*, const uint8_t*)) +{ + if (NULL == der) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); + return NULL; + } + + const uint8_t *payload_end = 0; + const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end); + + if (NULL == payload) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error); + return NULL; + } + + + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + if (NULL == dict) { + SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error); + payload = NULL; + goto exit; + } + + while (payload != NULL && payload < payload_end) { + CFTypeRef key = NULL; + CFTypeRef value = NULL; + + payload = der_decode_key_value_with_repair(allocator, mutability, &key, &value, error, payload, payload_end, repairBlock); + + if (payload) { + CFDictionaryAddValue(dict, key, value); + } + + CFReleaseNull(key); + CFReleaseNull(value); + } + + +exit: + if (payload == payload_end) { + *dictionary = dict; + dict = NULL; + } + + CFReleaseNull(dict); + + return payload; +} + +static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, + CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, + const uint8_t*, const uint8_t*)) +{ + const uint8_t *payload_end = 0; + const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end); + + if (NULL == payload) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error); + return NULL; + } + + CFTypeRef keyObject = NULL; + CFTypeRef valueObject = NULL; + + + payload = der_decode_plist_with_repair(allocator, mutability, &keyObject, error, payload, payload_end, repairBlock); + payload = der_decode_plist_with_repair(allocator, mutability, &valueObject, error, payload, payload_end, repairBlock); + + if (payload != NULL) { + *key = keyObject; + *value = valueObject; + } else { + CFReleaseNull(keyObject); + CFReleaseNull(valueObject); + } + return payload; +} + +static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, + CFArrayRef* array, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, + const uint8_t*, const uint8_t*)) +{ + if (NULL == der) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); + return NULL; + } + + CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + + const uint8_t *elements_end; + const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end); + + while (current_element != NULL && current_element < elements_end) { + CFPropertyListRef element = NULL; + current_element = der_decode_plist_with_repair(allocator, mutability, &element, error, current_element, elements_end, repairBlock); + if (current_element) { + CFArrayAppendValue(result, element); + CFReleaseNull(element); + } + } + + if (current_element) { + *array = result; + result = NULL; + } + + CFReleaseNull(result); + return current_element; +} + +static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, + CFSetRef* set, CFErrorRef *error, + const uint8_t* der, const uint8_t *der_end, + const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, + const uint8_t*, const uint8_t*)) +{ + if (NULL == der) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error); + return NULL; + } + + const uint8_t *payload_end = 0; + const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end); + + if (NULL == payload) { + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL, error); + return NULL; + } + + CFMutableSetRef theSet = (set && *set) ? CFSetCreateMutableCopy(allocator, 0, *set) + : CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); + + if (NULL == theSet) { + SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create set"), NULL, error); + payload = NULL; + goto exit; + } + + while (payload != NULL && payload < payload_end) { + CFTypeRef value = NULL; + + payload = der_decode_plist_with_repair(allocator, mutability, &value, error, payload, payload_end, repairBlock); + + if (payload) { + CFSetAddValue(theSet, value); + } + CFReleaseNull(value); + } + + +exit: + if (set && payload == payload_end) { + CFTransferRetained(*set, theSet); + } + + CFReleaseNull(theSet); + + return payload; +} + +void SecDbResetMetadataKeys(void) { + [SecDbKeychainMetadataKeyStore resetSharedStore]; +} diff --git a/keychain/securityd/SecDbKeychainItemV7.h b/keychain/securityd/SecDbKeychainItemV7.h new file mode 100644 index 00000000..7c96a0a3 --- /dev/null +++ b/keychain/securityd/SecDbKeychainItemV7.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SecKeybagSupport.h" +#import +#import +#import "CheckV12DevEnabled.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SecDbKeychainItemV7 : NSObject + +@property (nonatomic, readonly) keyclass_t keyclass; +@property (nonatomic, readonly) NSData* backupUUID; + +- (nullable instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error; +- (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass; + +- (nullable NSDictionary*)metadataAttributesWithError:(NSError**)error; +- (nullable NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error; +- (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error; + +- (nullable NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(nullable NSData*)acmContext error:(NSError**)error; + +@end + +extern NSString* const SecDbKeychainErrorDomain; +extern const NSInteger SecDbKeychainErrorDeserializationFailed; + + +@class SecDbKeychainSerializedMetadata; +@class SecDbKeychainSerializedSecretData; + +@interface SecDbKeychainItemV7 (UnitTesting) + ++ (bool)isKeychainUnlocked; + +@property (readonly) NSData* encryptedMetadataBlob; +@property (readonly) NSData* encryptedSecretDataBlob; + +- (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error; +- (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(nullable NSData*)acmContext error:(NSError**)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/securityd/SecDbKeychainItemV7.m b/keychain/securityd/SecDbKeychainItemV7.m new file mode 100644 index 00000000..1fd3957d --- /dev/null +++ b/keychain/securityd/SecDbKeychainItemV7.m @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SecDbKeychainItemV7.h" +#import "SecKeybagSupport.h" +#import "SecItemServer.h" +#import "SecAccessControl.h" +#import "SecDbKeychainSerializedItemV7.h" +#import "SecDbKeychainSerializedAKSWrappedKey.h" +#import "SecDbKeychainSerializedMetadata.h" +#import "SecDbKeychainSerializedSecretData.h" +#import +#import +#import "SecAKSObjCWrappers.h" +#import +#import +#import +#import + +#import + +#if USE_KEYSTORE && __has_include() +#import +#endif + +#import "SecDbKeychainMetadataKeyStore.h" +#import "SecDbBackupManager.h" + +#define KEYCHAIN_ITEM_PADDING_MODULUS 20 + +// See corresponding "reasonable size" client-side limit(s) in SecItem. + +// Generally the secret data dictionary contains a single key +// with the client's password/key NSData therein, so 4k feels extremely luxurious +#define REASONABLE_SECRET_DATA_SIZE 4096 + +// This feels similarly generous, but let's find out +#define REASONABLE_METADATA_SIZE 2048 + +NSString* const SecDbKeychainErrorDomain = @"SecDbKeychainErrorDomain"; +const NSInteger SecDbKeychainErrorDeserializationFailed = 1; + +static NSString* const SecDBTamperCheck = @"TamperCheck"; + +static NSDictionary* dictionaryFromDERData(NSData* data) +{ + NSDictionary* dict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)data, 0, NULL, NULL); + return [dict isKindOfClass:[NSDictionary class]] ? dict : nil; +} + +typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) { + SecDbKeychainAKSWrappedKeyTypeRegular, + SecDbKeychainAKSWrappedKeyTypeRefKey +}; + +@interface SecDbKeychainAKSWrappedKey : NSObject + +@property (readonly) NSData* wrappedKey; +@property (readonly) NSData* refKeyBlob; +@property (readonly) SecDbKeychainAKSWrappedKeyType type; + +@property (readonly) NSData* serializedRepresentation; + +- (instancetype)initWithData:(NSData*)data; +- (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey; +- (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob; + +@end + +@interface SecDbKeychainMetadata : NSObject + +@property (readonly) SFAuthenticatedCiphertext* ciphertext; +@property (readonly) SFAuthenticatedCiphertext* wrappedKey; +@property (readonly) NSString* tamperCheck; + +@property (readonly) NSData* serializedRepresentation; + +- (instancetype)initWithData:(NSData*)data; +- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error; + +@end + +@interface SecDbKeychainSecretData : NSObject + +@property (readonly) SFAuthenticatedCiphertext* ciphertext; +@property (readonly) SecDbKeychainAKSWrappedKey* wrappedKey; +@property (readonly) NSString* tamperCheck; + +@property (readonly) NSData* serializedRepresentation; + +- (instancetype)initWithData:(NSData*)data; +- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey error:(NSError**)error; + +@end + +@implementation SecDbKeychainAKSWrappedKey { + SecDbKeychainSerializedAKSWrappedKey* _serializedHolder; +} + +- (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; + _serializedHolder.wrappedKey = wrappedKey; + _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRegular; + } + + return self; +} + +- (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; + _serializedHolder.wrappedKey = wrappedKey; + _serializedHolder.refKeyBlob = refKeyBlob; + _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRefKey; + } + + return self; +} + +- (instancetype)initWithData:(NSData*)data +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] initWithData:data]; + if (!_serializedHolder.wrappedKey || (_serializedHolder.type == SecDbKeychainAKSWrappedKeyTypeRefKey && !_serializedHolder.refKeyBlob)) { + self = nil; + } + } + + return self; +} + +- (NSData*)serializedRepresentation +{ + return _serializedHolder.data; +} + +- (NSData*)wrappedKey +{ + return _serializedHolder.wrappedKey; +} + +- (NSData*)refKeyBlob +{ + return _serializedHolder.refKeyBlob; +} + +- (SecDbKeychainAKSWrappedKeyType)type +{ + return _serializedHolder.type; +} + +@end + +@implementation SecDbKeychainMetadata { + SecDbKeychainSerializedMetadata* _serializedHolder; +} + +- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext + wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey + tamperCheck:(NSString*)tamperCheck + error:(NSError**)error +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] init]; + _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; + _serializedHolder.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedKey requiringSecureCoding:YES error:error]; + _serializedHolder.tamperCheck = tamperCheck; + if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { + self = nil; + } + } + + return self; +} + +- (instancetype)initWithData:(NSData*)data +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] initWithData:data]; + if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { + self = nil; + } + } + + return self; +} + +- (NSData*)serializedRepresentation +{ + return _serializedHolder.data; +} + +- (SFAuthenticatedCiphertext*)ciphertext +{ + NSError* error = nil; + SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; + if (!ciphertext) { + secerror("SecDbKeychainItemV7: error deserializing ciphertext from metadata: %@", error); + } + + return ciphertext; +} + +- (SFAuthenticatedCiphertext*)wrappedKey +{ + NSError* error = nil; + SFAuthenticatedCiphertext* wrappedKey = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.wrappedKey error:&error]; + if (!wrappedKey) { + secerror("SecDbKeychainItemV7: error deserializing wrappedKey from metadata: %@", error); + } + + return wrappedKey; +} + +- (NSString*)tamperCheck +{ + return _serializedHolder.tamperCheck; +} + +@end + +@implementation SecDbKeychainSecretData { + SecDbKeychainSerializedSecretData* _serializedHolder; +} + +- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext + wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey + tamperCheck:(NSString*)tamperCheck + backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey + error:(NSError**)error +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] init]; + _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; + _serializedHolder.wrappedKey = wrappedKey.serializedRepresentation; + _serializedHolder.tamperCheck = tamperCheck; + _serializedHolder.secDbBackupWrappedItemKey = backupWrappedKey ? [NSKeyedArchiver archivedDataWithRootObject:backupWrappedKey requiringSecureCoding:YES error:error] : nil; + if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { + self = nil; + } + } + + return self; +} + +- (instancetype)initWithData:(NSData*)data +{ + if (self = [super init]) { + _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] initWithData:data]; + if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { + self = nil; + } + } + + return self; +} + +- (NSData*)serializedRepresentation +{ + return _serializedHolder.data; +} + +- (SFAuthenticatedCiphertext*)ciphertext +{ + NSError* error = nil; + SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; + if (!ciphertext) { + secerror("SecDbKeychainItemV7: error deserializing ciphertext from secret data: %@", error); + } + + return ciphertext; +} + +- (SecDbKeychainAKSWrappedKey*)wrappedKey +{ + return [[SecDbKeychainAKSWrappedKey alloc] initWithData:_serializedHolder.wrappedKey]; +} + +- (NSString*)tamperCheck +{ + return _serializedHolder.tamperCheck; +} + +@end + +@interface SecDbKeychainItemV7 () +@property (nonatomic) NSData* backupUUID; +@end; + +@implementation SecDbKeychainItemV7 { + SecDbKeychainSecretData* _encryptedSecretData; + SecDbKeychainMetadata* _encryptedMetadata; + NSDictionary* _secretAttributes; + NSDictionary* _metadataAttributes; + NSString* _tamperCheck; + keyclass_t _keyclass; + keybag_handle_t _keybag; +} + +@synthesize keyclass = _keyclass; + +// bring back with +#if 0 ++ (bool)isKeychainUnlocked +{ + return kc_is_unlocked(); +} +#endif + +- (instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error +{ + if (self = [super init]) { + SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] initWithData:data]; + if (serializedItem) { + + // Add 10% for serializing overhead. We're trying to catch blatant overstuffing, not enforce hard limits + if (data.length > ((REASONABLE_SECRET_DATA_SIZE + REASONABLE_METADATA_SIZE) * 1.1)) { + secwarning("SecDbKeychainItemV7: serialized item exceeds reasonable size (%lu bytes)", (unsigned long)data.length); + } + + _keybag = decryptionKeybag; + _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithData:serializedItem.encryptedSecretData]; + _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithData:serializedItem.encryptedMetadata]; + _keyclass = serializedItem.keyclass; + if (![_encryptedSecretData.tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { + self = nil; + } + } + else { + self = nil; + } + } + + if (!self && error) { + *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecItemNotFound userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}]; + } + + return self; +} + +- (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass +{ + NSParameterAssert(tamperCheck); + + if (self = [super init]) { + _secretAttributes = secretAttributes ? secretAttributes.copy : [NSDictionary dictionary]; + _metadataAttributes = metadataAttributes ? metadataAttributes.copy : [NSDictionary dictionary]; + _tamperCheck = tamperCheck.copy; + _keyclass = keyclass; + } + + return self; +} + ++ (SFAESKeySpecifier*)keySpecifier +{ + static SFAESKeySpecifier* keySpecifier = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; + }); + + return keySpecifier; +} + ++ (SFAuthenticatedEncryptionOperation*)encryptionOperation +{ + static SFAuthenticatedEncryptionOperation* encryptionOperation = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; + }); + + return encryptionOperation; +} + ++ (SFAuthenticatedEncryptionOperation*)decryptionOperation +{ + static SFAuthenticatedEncryptionOperation* decryptionOperation = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + decryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; + }); + + return decryptionOperation; +} + +- (NSDictionary*)metadataAttributesWithError:(NSError**)error +{ + if (!_metadataAttributes) { + SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:_keybag + createKeyIfMissing:false + overwriteCorruptKey:false + error:error]; + if (metadataClassKey) { + NSError* localError = nil; + NSData* keyData = [[self.class decryptionOperation] decrypt:_encryptedMetadata.wrappedKey withKey:metadataClassKey error:&localError]; + if (!keyData) { + secerror("SecDbKeychainItemV7: error unwrapping item metadata key (class %d, bag %d): %@", (int)self.keyclass, _keybag, localError); + // TODO: track this in LocalKeychainAnalytics + if (error) { + CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error + SecError(errSecDecode, &secError, CFSTR("failed to unwrap item metadata key")); + *error = CFBridgingRelease(secError); + } + return nil; + } + SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:[self.class keySpecifier] error:error]; + if (!key) { + return nil; + } + + NSData* metadata = [[self.class decryptionOperation] decrypt:_encryptedMetadata.ciphertext withKey:key error:&localError]; + if (!metadata) { + secerror("SecDbKeychainItemV7: error decrypting metadata content: %@", localError); + if (error) { + CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error + SecError(errSecDecode, &secError, CFSTR("failed to decrypt item metadata contents")); + *error = CFBridgingRelease(secError); + } + return nil; + } + NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(metadata).mutableCopy; + NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; + if ([tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { + [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; + _metadataAttributes = decryptedAttributes; + } + else { + secerror("SecDbKeychainItemV7: tamper check failed for metadata decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); + if (error) { + CFErrorRef secError = NULL; + SecError(errSecDecode, &secError, CFSTR("tamper check failed for metadata decryption")); + *error = CFBridgingRelease(secError); + } + } + } + } + + return _metadataAttributes; +} + +- (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error +{ + if (!_secretAttributes) { + SFAESKey* key = [self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:NO error:error]; + if (key) { + NSError* localError = nil; + NSData* secretDataWithPadding = [[self.class decryptionOperation] decrypt:_encryptedSecretData.ciphertext withKey:key error:&localError]; + if (!secretDataWithPadding) { + secerror("SecDbKeychainItemV7: error decrypting item secret data contents: %@", localError); + if (error) { + CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error + SecError(errSecDecode, &secError, CFSTR("error decrypting item secret data contents")); + *error = CFBridgingRelease(secError); + } + return nil; + } + int8_t paddingLength = *((int8_t*)secretDataWithPadding.bytes + secretDataWithPadding.length - 1); + NSData* secretDataWithoutPadding = [secretDataWithPadding subdataWithRange:NSMakeRange(0, secretDataWithPadding.length - paddingLength)]; + + NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(secretDataWithoutPadding).mutableCopy; + NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; + if ([tamperCheck isEqualToString:_encryptedSecretData.tamperCheck]) { + [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; + _secretAttributes = decryptedAttributes; + } + else { + secerror("SecDbKeychainItemV7: tamper check failed for secret data decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); + } + } + } + + return _secretAttributes; +} + +- (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error +{ + NSError* localError = nil; + (void)[self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:YES error:&localError]; + if (localError) { + secerror("SecDbKeychainItemV7: failed to delete item secret key from aks"); + if (error) { + *error = localError; + } + + return NO; + } + + return YES; +} + +- (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error +{ + NSError* localError = nil; + BOOL success = [self encryptMetadataWithKeybag:keybag error:&localError]; + if (!success || !_encryptedMetadata || localError) { + if (error) { + *error = localError; + } + return nil; + } + + success = [self encryptSecretDataWithKeybag:keybag accessControl:accessControl acmContext:acmContext error:&localError]; + if (!success || !_encryptedSecretData || localError) { + if (error) { + *error = localError; + } + return nil; + } + + SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init]; + serializedItem.encryptedMetadata = self.encryptedMetadataBlob; + serializedItem.encryptedSecretData = self.encryptedSecretDataBlob; + serializedItem.keyclass = _keyclass; + return serializedItem.data; +} + +- (NSData*)encryptedMetadataBlob +{ + return _encryptedMetadata.serializedRepresentation; +} + +- (NSData*)encryptedSecretDataBlob +{ + return _encryptedSecretData.serializedRepresentation; +} + +- (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error +{ + SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; + if (!key) { + return NO; + } + SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; + + NSMutableDictionary* attributesToEncrypt = _metadataAttributes.mutableCopy; + attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; + NSData* metadata = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL); + + if (metadata.length > REASONABLE_METADATA_SIZE) { + NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; + secwarning("SecDbKeychainItemV7: item's metadata exceeds reasonable size (%lu bytes) (%@)", (unsigned long)metadata.length, agrp); + } + + SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error]; + + SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag + createKeyIfMissing:true + overwriteCorruptKey:true + error:error]; + if (metadataClassKey) { + SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error]; + _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error]; + } + + return _encryptedMetadata != nil; +} + +- (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error +{ + SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; + if (!key) { + return NO; + } + SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; + + NSMutableDictionary* attributesToEncrypt = _secretAttributes.mutableCopy; + attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; + NSMutableData* secretData = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL) mutableCopy]; + + if (secretData.length > REASONABLE_SECRET_DATA_SIZE) { + NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; + secwarning("SecDbKeychainItemV7: item's secret data exceeds reasonable size (%lu bytes) (%@)", (unsigned long)secretData.length, agrp); + } + + int8_t paddingLength = KEYCHAIN_ITEM_PADDING_MODULUS - (secretData.length % KEYCHAIN_ITEM_PADDING_MODULUS); + int8_t paddingBytes[KEYCHAIN_ITEM_PADDING_MODULUS]; + for (int i = 0; i < KEYCHAIN_ITEM_PADDING_MODULUS; i++) { + paddingBytes[i] = paddingLength; + } + [secretData appendBytes:paddingBytes length:paddingLength]; + + SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error]; + SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error]; + + SecDbBackupWrappedItemKey* backupWrappedKey; + if (checkV12DevEnabled()) { + backupWrappedKey = [[SecDbBackupManager manager] wrapItemKey:key forKeyclass:_keyclass error:error]; + if (backupWrappedKey) { + _backupUUID = backupWrappedKey.baguuid; + } else { + secwarning("SecDbKeychainItemV7: backup manager didn't return wrapped key: %@", error ? *error : nil); + if (error) { + *error = nil; + } + } + } + + _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithCiphertext:ciphertext + wrappedKey:wrappedKey + tamperCheck:_tamperCheck + backupWrappedKey:backupWrappedKey + error:error]; + return _encryptedSecretData != nil; +} + +- (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag + createKeyIfMissing:(bool)createIfMissing + overwriteCorruptKey:(bool)force + error:(NSError**)error +{ + return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass + keybag:keybag + keySpecifier:[self.class keySpecifier] + createKeyIfMissing:(bool)createIfMissing + overwriteCorruptKey:force + error:error]; +} + +- (SecDbKeychainAKSWrappedKey*)wrapToAKS:(SFAESKey*)key withKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error +{ + NSData* keyData = key.keyData; + +#if USE_KEYSTORE + NSDictionary* constraints = (__bridge NSDictionary*)SecAccessControlGetConstraints(accessControl); + if (constraints) { + aks_ref_key_t refKey = NULL; + CFErrorRef cfError = NULL; + NSData* authData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)@{(id)kAKSKeyAcl : constraints}, &cfError); + + if (!acmContext || !SecAccessControlIsBound(accessControl)) { + secerror("SecDbKeychainItemV7: access control error"); + if (error) { + CFDataRef accessControlData = SecAccessControlCopyData(accessControl); + ks_access_control_needed_error(&cfError, accessControlData, SecAccessControlIsBound(accessControl) ? kAKSKeyOpEncrypt : CFSTR("")); + CFReleaseNull(accessControlData); + } + + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + + void* aksParams = NULL; + size_t aksParamsLength = 0; + aks_operation_optional_params(0, 0, authData.bytes, authData.length, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); + + int aksResult = aks_ref_key_create(keybag, _keyclass, key_type_sym, aksParams, aksParamsLength, &refKey); + if (aksResult != 0) { + CFDataRef accessControlData = SecAccessControlCopyData(accessControl); + create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); + CFReleaseNull(accessControlData); + free(aksParams); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + + size_t wrappedKeySize = 0; + void* wrappedKeyBytes = NULL; + aksResult = aks_ref_key_encrypt(refKey, aksParams, aksParamsLength, keyData.bytes, keyData.length, &wrappedKeyBytes, &wrappedKeySize); + if (aksResult != 0) { + CFDataRef accessControlData = SecAccessControlCopyData(accessControl); + create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); + CFReleaseNull(accessControlData); + free(aksParams); + aks_ref_key_free(&refKey); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + free(aksParams); + + BridgeCFErrorToNSErrorOut(error, cfError); + + NSData* wrappedKey = [[NSData alloc] initWithBytesNoCopy:wrappedKeyBytes length:wrappedKeySize]; + + size_t refKeyBlobLength = 0; + const void* refKeyBlobBytes = aks_ref_key_get_blob(refKey, &refKeyBlobLength); + NSData* refKeyBlob = [[NSData alloc] initWithBytesNoCopy:(void*)refKeyBlobBytes length:refKeyBlobLength]; + aks_ref_key_free(&refKey); + return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob]; + } + else { + NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40]; + bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; + return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; + } +#else + NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40]; + bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; + return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; +#endif +} + +- (SFAESKey*)unwrapFromAKS:(SecDbKeychainAKSWrappedKey*)wrappedKey accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext callerAccessGroups:(NSArray*)callerAccessGroups delete:(BOOL)delete error:(NSError**)error +{ + NSData* wrappedKeyData = wrappedKey.wrappedKey; + + if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) { + NSMutableData* unwrappedKey = [NSMutableData dataWithCapacity:wrappedKeyData.length + 40]; + unwrappedKey.length = wrappedKeyData.length + 40; + bool result = [SecAKSObjCWrappers aksDecryptWithKeybag:_keybag keyclass:_keyclass ciphertext:wrappedKeyData outKeyclass:&_keyclass plaintext:unwrappedKey error:error]; + if (result) { + return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error]; + } + else { + return nil; + } + } +#if USE_KEYSTORE + else if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRefKey) { + aks_ref_key_t refKey = NULL; + aks_ref_key_create_with_blob(_keybag, wrappedKey.refKeyBlob.bytes, wrappedKey.refKeyBlob.length, &refKey); + + CFErrorRef cfError = NULL; + size_t refKeyExternalDataLength = 0; + const uint8_t* refKeyExternalDataBytes = aks_ref_key_get_external_data(refKey, &refKeyExternalDataLength); + if (!refKeyExternalDataBytes) { + aks_ref_key_free(&refKey); + return nil; + } + NSDictionary* aclDict = nil; + der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength); + if (!aclDict) { + SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict")); + } + SecAccessControlSetConstraints(accessControl, (__bridge CFDictionaryRef)aclDict); + if (!SecAccessControlGetConstraint(accessControl, kAKSKeyOpEncrypt)) { + SecAccessControlAddConstraintForOperation(accessControl, kAKSKeyOpEncrypt, kCFBooleanTrue, &cfError); + } + + size_t derPlistLength = der_sizeof_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError); + NSMutableData* accessGroupDERData = [[NSMutableData alloc] initWithLength:derPlistLength]; + der_encode_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError, accessGroupDERData.mutableBytes, accessGroupDERData.mutableBytes + derPlistLength); + void* aksParams = NULL; + size_t aksParamsLength = 0; + aks_operation_optional_params(accessGroupDERData.bytes, derPlistLength, NULL, 0, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); + + void* unwrappedKeyDERData = NULL; + size_t unwrappedKeyDERLength = 0; + int aksResult = aks_ref_key_decrypt(refKey, aksParams, aksParamsLength, wrappedKeyData.bytes, wrappedKeyData.length, &unwrappedKeyDERData, &unwrappedKeyDERLength); + if (aksResult != 0) { + CFDataRef accessControlData = SecAccessControlCopyData(accessControl); + create_cferror_from_aks(aksResult, kAKSKeyOpDecrypt, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); + CFReleaseNull(accessControlData); + aks_ref_key_free(&refKey); + free(aksParams); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + if (!unwrappedKeyDERData) { + SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); + aks_ref_key_free(&refKey); + free(aksParams); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + + CFPropertyListRef unwrappedKeyData = NULL; + der_decode_plist(NULL, kCFPropertyListImmutable, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength); + SFAESKey* result = nil; + if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) { + result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error]; + CFReleaseNull(unwrappedKeyDERData); + } + else { + SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); + aks_ref_key_free(&refKey); + free(aksParams); + free(unwrappedKeyDERData); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + + if (delete) { + aksResult = aks_ref_key_delete(refKey, aksParams, aksParamsLength); + if (aksResult != 0) { + CFDataRef accessControlData = SecAccessControlCopyData(accessControl); + create_cferror_from_aks(aksResult, kAKSKeyOpDelete, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); + CFReleaseNull(accessControlData); + aks_ref_key_free(&refKey); + free(aksParams); + free(unwrappedKeyDERData); + BridgeCFErrorToNSErrorOut(error, cfError); + return nil; + } + } + + BridgeCFErrorToNSErrorOut(error, cfError); + aks_ref_key_free(&refKey); + free(aksParams); + free(unwrappedKeyDERData); + return result; + } +#endif + else { + return nil; + } +} + +@end diff --git a/keychain/securityd/SecDbKeychainMetadataKeyStore.h b/keychain/securityd/SecDbKeychainMetadataKeyStore.h new file mode 100644 index 00000000..5c35094a --- /dev/null +++ b/keychain/securityd/SecDbKeychainMetadataKeyStore.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import +#import +#import "SecKeybagSupport.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +// This class is intended for SecDbKeychainItemV7, db resets and SecDbKeychainManager _only_ + +@interface SecDbKeychainMetadataKeyStore : NSObject + ++ (bool)cachingEnabled; + ++ (void)resetSharedStore; ++ (instancetype)sharedStore; + +- (instancetype)init NS_UNAVAILABLE; + +- (void)dropClassAKeys; + +- (SFAESKey*)keyForKeyclass:(keyclass_t)keyClass + keybag:(keybag_handle_t)keybag + keySpecifier:(SFAESKeySpecifier*)keySpecifier + createKeyIfMissing:(bool)createIfMissing + overwriteCorruptKey:(bool)overwriteCorruptKey + error:(NSError**)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/securityd/SecDbKeychainMetadataKeyStore.m b/keychain/securityd/SecDbKeychainMetadataKeyStore.m new file mode 100644 index 00000000..9a366661 --- /dev/null +++ b/keychain/securityd/SecDbKeychainMetadataKeyStore.m @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import "SecDbKeychainMetadataKeyStore.h" +#import +#import +#import +#import "SecItemServer.h" +#import "SecAKSObjCWrappers.h" +#import "sec_action.h" + +static SecDbKeychainMetadataKeyStore* sharedStore = nil; +static dispatch_queue_t sharedMetadataStoreQueue; +static void initializeSharedMetadataStoreQueue(void) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedMetadataStoreQueue = dispatch_queue_create("metadata_store", DISPATCH_QUEUE_SERIAL); + }); +} + +@implementation SecDbKeychainMetadataKeyStore { + NSMutableDictionary* _keysDict; + dispatch_queue_t _queue; +} + ++ (void)resetSharedStore +{ + initializeSharedMetadataStoreQueue(); + dispatch_sync(sharedMetadataStoreQueue, ^{ + if(sharedStore) { + dispatch_sync(sharedStore->_queue, ^{ + [sharedStore _onQueueDropAllKeys]; + }); + } + sharedStore = nil; + }); +} + ++ (instancetype)sharedStore +{ + __block SecDbKeychainMetadataKeyStore* ret; + initializeSharedMetadataStoreQueue(); + dispatch_sync(sharedMetadataStoreQueue, ^{ + if(!sharedStore) { + sharedStore = [[self alloc] _init]; + } + + ret = sharedStore; + }); + + return ret; +} + ++ (bool)cachingEnabled +{ + return true; +} + +- (instancetype)_init +{ + if (self = [super init]) { + _keysDict = [[NSMutableDictionary alloc] init]; + _queue = dispatch_queue_create("SecDbKeychainMetadataKeyStore", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + int token = 0; + __weak __typeof(self) weakSelf = self; + notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int inToken) { + bool locked = true; + CFErrorRef error = NULL; + if (!SecAKSGetIsLocked(&locked, &error)) { + secerror("SecDbKeychainMetadataKeyStore: error getting lock state: %@", error); + CFReleaseNull(error); + } + + if (locked) { + [weakSelf _onQueueDropClassAKeys]; + } + }); + } + + return self; +} + +- (void)dropClassAKeys +{ + dispatch_sync(_queue, ^{ + [self _onQueueDropClassAKeys]; + }); +} + +- (void)_onQueueDropClassAKeys +{ + dispatch_assert_queue(_queue); + + secnotice("SecDbKeychainMetadataKeyStore", "dropping class A metadata keys"); + _keysDict[@(key_class_ak)] = nil; + _keysDict[@(key_class_aku)] = nil; + _keysDict[@(key_class_akpu)] = nil; +} + +- (void)_onQueueDropAllKeys +{ + dispatch_assert_queue(_queue); + + secnotice("SecDbKeychainMetadataKeyStore", "dropping all metadata keys"); + [_keysDict removeAllObjects]; +} + +- (void)_updateActualKeyclassIfNeeded:(keyclass_t)actualKeyclassToWriteBackToDB keyclass:(keyclass_t)keyclass +{ + __block CFErrorRef cfError = NULL; + + secnotice("SecDbKeychainItemV7", "saving actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass); + + kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) { + __block bool actualKeyWriteBackOk = true; + + // we did not find an actualKeyclass entry in the db, so let's add one in now. + NSString *sql = @"UPDATE metadatakeys SET actualKeyclass = ? WHERE keyclass = ? AND actualKeyclass IS NULL"; + __block CFErrorRef actualKeyWriteBackError = NULL; + actualKeyWriteBackOk &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &actualKeyWriteBackError, ^(sqlite3_stmt* stmt) { + actualKeyWriteBackOk &= SecDbBindInt(stmt, 1, actualKeyclassToWriteBackToDB, &actualKeyWriteBackError); + actualKeyWriteBackOk &= SecDbBindInt(stmt, 2, keyclass, &actualKeyWriteBackError); + actualKeyWriteBackOk &= SecDbStep(dbt, stmt, &actualKeyWriteBackError, ^(bool* stop) { + // woohoo + }); + }); + + if (actualKeyWriteBackOk) { + secnotice("SecDbKeychainItemV7", "successfully saved actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass); + + } + else { + // we can always try this again in the future if it failed + secerror("SecDbKeychainItemV7: failed to save actualKeyclass %d for metadata keyclass %d; error: %@", actualKeyclassToWriteBackToDB, keyclass, actualKeyWriteBackError); + } + return actualKeyWriteBackOk; + }); +} + +- (SFAESKey*)keyForKeyclass:(keyclass_t)keyclass + keybag:(keybag_handle_t)keybag + keySpecifier:(SFAESKeySpecifier*)keySpecifier + createKeyIfMissing:(bool)createIfMissing + overwriteCorruptKey:(bool)overwriteCorruptKey + error:(NSError**)error +{ + __block SFAESKey* key = nil; + __block NSError* nsErrorLocal = nil; + __block CFErrorRef cfError = NULL; + static __thread BOOL reentrant = NO; + + NSAssert(!reentrant, @"re-entering -[%@ %@] - that shouldn't happen!", NSStringFromClass(self.class), NSStringFromSelector(_cmd)); + reentrant = YES; + + keyclass = SecAKSSanitizedKeyclass(keyclass); + + dispatch_sync(_queue, ^{ + // if we think we're locked, it's possible AKS will still give us access to keys, such as during backup, + // but we should force AKS to be the truth and not used cached class A keys while locked + bool allowKeyCaching = [SecDbKeychainMetadataKeyStore cachingEnabled]; + + // However, we must not cache a newly-created key, just in case someone above us in the stack rolls back our database transaction and the stored key is lost. + __block bool keyIsNewlyCreated = false; +#if 0 + // Fix keychain lock state check to be both secure and fast for EDU mode + if (![SecDbKeychainItemV7 isKeychainUnlocked]) { + [self _onQueueDropClassAKeys]; + allowKeyCaching = !(keyclass == key_class_ak || keyclass == key_class_aku || keyclass == key_class_akpu); + } +#endif + + key = allowKeyCaching ? self->_keysDict[@(keyclass)] : nil; + if (!key) { + __block bool ok = true; + __block bool metadataKeyDoesntAuthenticate = false; + ok &= kc_with_dbt_non_item_tables(createIfMissing, &cfError, ^bool(SecDbConnectionRef dbt) { + __block NSString* sql = [NSString stringWithFormat:@"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = %d", keyclass]; + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) { + ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { + NSData* wrappedKeyData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)]; + NSMutableData* unwrappedKeyData = [NSMutableData dataWithLength:wrappedKeyData.length]; + + keyclass_t actualKeyclass = sqlite3_column_int(stmt, 1); + + keyclass_t actualKeyclassToWriteBackToDB = 0; + keyclass_t keyclassForUnwrapping = actualKeyclass == 0 ? keyclass : actualKeyclass; + ok &= [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyclassForUnwrapping ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&nsErrorLocal]; + if (ok) { + key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&nsErrorLocal]; + + if(!key) { + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted, but didn't become a key: %@", keyclass, nsErrorLocal); + } + } + + if (actualKeyclass == 0) { + actualKeyclassToWriteBackToDB = keyclassForUnwrapping; + } + } +#if USE_KEYSTORE + else if (actualKeyclass == 0 && keyclass <= key_class_last) { + // in this case we might have luck decrypting with a key-rolled keyclass + keyclass_t keyrolledKeyclass = keyclass | (key_class_last + 1); + secerror("SecDbKeychainItemV7: failed to decrypt metadata key for class %d, but trying keyrolled keyclass (%d); error: %@", keyclass, keyrolledKeyclass, nsErrorLocal); + + // we don't want to pollute subsequent error-handling logic with what happens on our retry + // we'll give it a shot, and if it works, great - if it doesn't work, we'll just report that error in the log and move on + NSError* retryError = nil; + ok = [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyrolledKeyclass ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&retryError]; + + if (ok) { + secerror("SecDbKeychainItemV7: successfully decrypted metadata key using keyrolled keyclass %d", keyrolledKeyclass); + key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&retryError]; + + if(!key) { + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), + "Metadata class key (%d) decrypted using keyrolled keyclass %d, but didn't become a key: %@", + keyclass, keyrolledKeyclass, retryError); + } + nsErrorLocal = retryError; + } + } + else { + secerror("SecDbKeychainItemV7: failed to decrypt metadata key with keyrolled keyclass %d; error: %@", keyrolledKeyclass, retryError); + } + } +#endif + + if (ok && key) { + if (actualKeyclassToWriteBackToDB > 0) { + // check if we have updated this keyclass or not already + static NSMutableDictionary* updated = NULL; + if (!updated) { + updated = [NSMutableDictionary dictionary]; + } + if (!updated[@(keyclass)]) { + updated[@(keyclass)] = @YES; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ + [self _updateActualKeyclassIfNeeded:actualKeyclassToWriteBackToDB keyclass:keyclass]; + }); + } + } + } + else { + if (nsErrorLocal && [nsErrorLocal.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && nsErrorLocal.code == errSecInteractionNotAllowed) { + static dispatch_once_t kclockedtoken; + static sec_action_t kclockedaction; + dispatch_once(&kclockedtoken, ^{ + kclockedaction = sec_action_create("keychainlockedlogmessage", 1); + sec_action_set_handler(kclockedaction, ^{ + secerror("SecDbKeychainItemV7: failed to decrypt metadata key because the keychain is locked (%d)", (int)errSecInteractionNotAllowed); + }); + }); + sec_action_perform(kclockedaction); + } else { + secerror("SecDbKeychainItemV7: failed to decrypt and create metadata key for class %d; error: %@", keyclass, nsErrorLocal); + + // If this error is errSecDecode, then it's failed authentication and likely will forever. Other errors are scary. + metadataKeyDoesntAuthenticate = [nsErrorLocal.domain isEqualToString:NSOSStatusErrorDomain] && nsErrorLocal.code == errSecDecode; + if(metadataKeyDoesntAuthenticate) { + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal); + } + } + } + } + }); + }); + + bool keyNotYetCreated = ok && !key; + bool forceOverwriteBadKey = !key && metadataKeyDoesntAuthenticate && overwriteCorruptKey; + + if (createIfMissing && (keyNotYetCreated || forceOverwriteBadKey)) { + // we completed the database query, but no key exists or it's broken - we should create one + if(forceOverwriteBadKey) { + secerror("SecDbKeychainItemV7: metadata key is irreparably corrupt; throwing away forever"); + // TODO: track this in LocalKeychainAnalytics + } + + ok = true; // Reset 'ok': we have a second chance + + key = [[SFAESKey alloc] initRandomKeyWithSpecifier:keySpecifier error:&nsErrorLocal]; + keyIsNewlyCreated = true; + + if (key) { + NSMutableData* wrappedKey = [NSMutableData dataWithLength:key.keyData.length + 40]; + keyclass_t outKeyclass = keyclass; + ok &= [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:keyclass plaintext:key.keyData outKeyclass:&outKeyclass ciphertext:wrappedKey error:&nsErrorLocal]; + if (ok) { + secinfo("SecDbKeychainItemV7", "attempting to save new metadata key for keyclass %d with actualKeyclass %d", keyclass, outKeyclass); + NSString* insertString = forceOverwriteBadKey ? @"INSERT OR REPLACE" : @"INSERT"; + sql = [NSString stringWithFormat:@"%@ into metadatakeys (keyclass, actualKeyclass, data) VALUES (?, ?, ?)", insertString]; + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt* stmt) { + ok &= SecDbBindInt(stmt, 1, keyclass, &cfError); + ok &= SecDbBindInt(stmt, 2, outKeyclass, &cfError); + ok &= SecDbBindBlob(stmt, 3, wrappedKey.bytes, wrappedKey.length, SQLITE_TRANSIENT, NULL); + ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) { + // woohoo + }); + }); + + if (ok) { + secnotice("SecDbKeychainItemV7", "successfully saved new metadata key for keyclass %d", keyclass); + } + else { + secerror("SecDbKeychainItemV7: failed to save new metadata key for keyclass %d - probably there is already one in the database: %@", keyclass, cfError); + } + } else { + secerror("SecDbKeychainItemV7: unable to encrypt new metadata key(%d) with keybag(%d): %@", keyclass, keybag, nsErrorLocal); + } + } + else { + ok = false; + } + } else if(!key) { + // No key, but we're not supposed to make one. Make an error if one doesn't yet exist. + ok = false; + if(!nsErrorLocal) { + nsErrorLocal = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Unable to find or create a suitable metadata key"}]; + } + } + + return ok; + }); + + if (ok && key) { + // We can't cache a newly-created key, just in case this db transaction is rolled back and we lose the persisted key. + // Don't worry, we'll cache it as soon as it's used again. + if (allowKeyCaching && !keyIsNewlyCreated) { + self->_keysDict[@(keyclass)] = key; + __weak __typeof(self) weakSelf = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * 5 * NSEC_PER_SEC)), self->_queue, ^{ + [weakSelf _onQueueDropClassAKeys]; + }); + } + } + else { + key = nil; + } + } + }); + + reentrant = NO; + + if (error && nsErrorLocal) { + *error = nsErrorLocal; + CFReleaseNull(cfError); + } + else { + BridgeCFErrorToNSErrorOut(error, cfError); + } + + return key; +} + +@end diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto new file mode 100644 index 00000000..4c6db5da --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message SecDbKeychainSerializedAKSWrappedKey { + required bytes wrappedKey = 1; + optional bytes refKeyBlob = 2; + required uint32 type = 3; +} diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto new file mode 100644 index 00000000..4138447d --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto @@ -0,0 +1,17 @@ +syntax = "proto2"; + +message SecDbKeychainSerializedItemV7 { + required bytes encryptedSecretData = 1; + required bytes encryptedMetadata = 2; + + enum Keyclass { + KEYCLASS_AK = 6; + KEYCLASS_CK = 7; + KEYCLASS_DK = 8; + KEYCLASS_AKU = 9; + KEYCLASS_CKU = 10; + KEYCLASS_DKU = 11; + KEYCLASS_AKPU = 12; + } + required Keyclass keyclass = 3 [default = KEYCLASS_AKPU]; +} diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto new file mode 100644 index 00000000..f21796c2 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message SecDbKeychainSerializedMetadata { + required bytes ciphertext = 1; + required bytes wrappedKey = 2; + required string tamperCheck = 3; +} diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto new file mode 100644 index 00000000..55353e16 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto @@ -0,0 +1,8 @@ +syntax = "proto2"; + +message SecDbKeychainSerializedSecretData { + required bytes ciphertext = 1; + required bytes wrappedKey = 2; + required string tamperCheck = 3; + optional bytes SecDbBackupWrappedItemKey = 4; +} diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h new file mode 100644 index 00000000..154cc192 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h @@ -0,0 +1,41 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedAKSWrappedKey.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION extern "C" +#else +#define SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION extern +#endif + +@interface SecDbKeychainSerializedAKSWrappedKey : PBCodable +{ + NSData *_refKeyBlob; + uint32_t _type; + NSData *_wrappedKey; +} + + +@property (nonatomic, retain) NSData *wrappedKey; + +@property (nonatomic, readonly) BOOL hasRefKeyBlob; +@property (nonatomic, retain) NSData *refKeyBlob; + +@property (nonatomic) uint32_t type; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbKeychainSerializedAKSWrappedKey *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbKeychainSerializedAKSWrappedKey *)other; + +SECDBKEYCHAINSERIALIZEDAKSWRAPPEDKEY_FUNCTION BOOL SecDbKeychainSerializedAKSWrappedKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedAKSWrappedKey *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m new file mode 100644 index 00000000..5a4b4465 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m @@ -0,0 +1,168 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedAKSWrappedKey.proto + +#import "SecDbKeychainSerializedAKSWrappedKey.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbKeychainSerializedAKSWrappedKey + +@synthesize wrappedKey = _wrappedKey; +- (BOOL)hasRefKeyBlob +{ + return _refKeyBlob != nil; +} +@synthesize refKeyBlob = _refKeyBlob; +@synthesize type = _type; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_wrappedKey) + { + [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; + } + if (self->_refKeyBlob) + { + [dict setObject:self->_refKeyBlob forKey:@"refKeyBlob"]; + } + [dict setObject:[NSNumber numberWithUnsignedInt:self->_type] forKey:@"type"]; + return dict; +} + +BOOL SecDbKeychainSerializedAKSWrappedKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedAKSWrappedKey *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* wrappedKey */: + { + NSData *new_wrappedKey = PBReaderReadData(reader); + self->_wrappedKey = new_wrappedKey; + } + break; + case 2 /* refKeyBlob */: + { + NSData *new_refKeyBlob = PBReaderReadData(reader); + self->_refKeyBlob = new_refKeyBlob; + } + break; + case 3 /* type */: + { + self->_type = PBReaderReadUint32(reader); + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbKeychainSerializedAKSWrappedKeyReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* wrappedKey */ + { + assert(nil != self->_wrappedKey); + PBDataWriterWriteDataField(writer, self->_wrappedKey, 1); + } + /* refKeyBlob */ + { + if (self->_refKeyBlob) + { + PBDataWriterWriteDataField(writer, self->_refKeyBlob, 2); + } + } + /* type */ + { + PBDataWriterWriteUint32Field(writer, self->_type, 3); + } +} + +- (void)copyTo:(SecDbKeychainSerializedAKSWrappedKey *)other +{ + other.wrappedKey = _wrappedKey; + if (_refKeyBlob) + { + other.refKeyBlob = _refKeyBlob; + } + other->_type = _type; +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbKeychainSerializedAKSWrappedKey *copy = [[[self class] allocWithZone:zone] init]; + copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; + copy->_refKeyBlob = [_refKeyBlob copyWithZone:zone]; + copy->_type = _type; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbKeychainSerializedAKSWrappedKey *other = (SecDbKeychainSerializedAKSWrappedKey *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) + && + ((!self->_refKeyBlob && !other->_refKeyBlob) || [self->_refKeyBlob isEqual:other->_refKeyBlob]) + && + self->_type == other->_type + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_wrappedKey hash] + ^ + [self->_refKeyBlob hash] + ^ + PBHashInt((NSUInteger)_type) + ; +} + +- (void)mergeFrom:(SecDbKeychainSerializedAKSWrappedKey *)other +{ + if (other->_wrappedKey) + { + [self setWrappedKey:other->_wrappedKey]; + } + if (other->_refKeyBlob) + { + [self setRefKeyBlob:other->_refKeyBlob]; + } + self->_type = other->_type; +} + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h new file mode 100644 index 00000000..630bd070 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h @@ -0,0 +1,81 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedItemV7.proto + +#import +#import + +typedef NS_ENUM(int32_t, SecDbKeychainSerializedItemV7_Keyclass) { + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK = 6, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK = 7, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK = 8, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU = 9, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU = 10, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU = 11, + SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU = 12, +}; +#ifdef __OBJC__ +NS_INLINE NSString *SecDbKeychainSerializedItemV7_KeyclassAsString(SecDbKeychainSerializedItemV7_Keyclass value) +{ + switch (value) + { + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK: return @"KEYCLASS_AK"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK: return @"KEYCLASS_CK"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK: return @"KEYCLASS_DK"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU: return @"KEYCLASS_AKU"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU: return @"KEYCLASS_CKU"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU: return @"KEYCLASS_DKU"; + case SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU: return @"KEYCLASS_AKPU"; + default: return [NSString stringWithFormat:@"(unknown: %i)", value]; + } +} +#endif /* __OBJC__ */ +#ifdef __OBJC__ +NS_INLINE SecDbKeychainSerializedItemV7_Keyclass StringAsSecDbKeychainSerializedItemV7_Keyclass(NSString *value) +{ + if ([value isEqualToString:@"KEYCLASS_AK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK; + if ([value isEqualToString:@"KEYCLASS_CK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CK; + if ([value isEqualToString:@"KEYCLASS_DK"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DK; + if ([value isEqualToString:@"KEYCLASS_AKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKU; + if ([value isEqualToString:@"KEYCLASS_CKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_CKU; + if ([value isEqualToString:@"KEYCLASS_DKU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_DKU; + if ([value isEqualToString:@"KEYCLASS_AKPU"]) return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AKPU; + return SecDbKeychainSerializedItemV7_Keyclass_KEYCLASS_AK; +} +#endif /* __OBJC__ */ + +#ifdef __cplusplus +#define SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION extern "C" +#else +#define SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION extern +#endif + +@interface SecDbKeychainSerializedItemV7 : PBCodable +{ + NSData *_encryptedMetadata; + NSData *_encryptedSecretData; + SecDbKeychainSerializedItemV7_Keyclass _keyclass; +} + + +@property (nonatomic, retain) NSData *encryptedSecretData; + +@property (nonatomic, retain) NSData *encryptedMetadata; + +@property (nonatomic) SecDbKeychainSerializedItemV7_Keyclass keyclass; +- (NSString *)keyclassAsString:(SecDbKeychainSerializedItemV7_Keyclass)value; +- (SecDbKeychainSerializedItemV7_Keyclass)StringAsKeyclass:(NSString *)str; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbKeychainSerializedItemV7 *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbKeychainSerializedItemV7 *)other; + +SECDBKEYCHAINSERIALIZEDITEMV7_FUNCTION BOOL SecDbKeychainSerializedItemV7ReadFrom(__unsafe_unretained SecDbKeychainSerializedItemV7 *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m new file mode 100644 index 00000000..3ccff9ec --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m @@ -0,0 +1,167 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedItemV7.proto + +#import "SecDbKeychainSerializedItemV7.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbKeychainSerializedItemV7 + +@synthesize encryptedSecretData = _encryptedSecretData; +@synthesize encryptedMetadata = _encryptedMetadata; +@synthesize keyclass = _keyclass; +- (NSString *)keyclassAsString:(SecDbKeychainSerializedItemV7_Keyclass)value +{ + return SecDbKeychainSerializedItemV7_KeyclassAsString(value); +} +- (SecDbKeychainSerializedItemV7_Keyclass)StringAsKeyclass:(NSString *)str +{ + return StringAsSecDbKeychainSerializedItemV7_Keyclass(str); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_encryptedSecretData) + { + [dict setObject:self->_encryptedSecretData forKey:@"encryptedSecretData"]; + } + if (self->_encryptedMetadata) + { + [dict setObject:self->_encryptedMetadata forKey:@"encryptedMetadata"]; + } + [dict setObject:SecDbKeychainSerializedItemV7_KeyclassAsString(self->_keyclass) forKey:@"keyclass"]; + return dict; +} + +BOOL SecDbKeychainSerializedItemV7ReadFrom(__unsafe_unretained SecDbKeychainSerializedItemV7 *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* encryptedSecretData */: + { + NSData *new_encryptedSecretData = PBReaderReadData(reader); + self->_encryptedSecretData = new_encryptedSecretData; + } + break; + case 2 /* encryptedMetadata */: + { + NSData *new_encryptedMetadata = PBReaderReadData(reader); + self->_encryptedMetadata = new_encryptedMetadata; + } + break; + case 3 /* keyclass */: + { + self->_keyclass = PBReaderReadInt32(reader); + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbKeychainSerializedItemV7ReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* encryptedSecretData */ + { + assert(nil != self->_encryptedSecretData); + PBDataWriterWriteDataField(writer, self->_encryptedSecretData, 1); + } + /* encryptedMetadata */ + { + assert(nil != self->_encryptedMetadata); + PBDataWriterWriteDataField(writer, self->_encryptedMetadata, 2); + } + /* keyclass */ + { + PBDataWriterWriteInt32Field(writer, self->_keyclass, 3); + } +} + +- (void)copyTo:(SecDbKeychainSerializedItemV7 *)other +{ + other.encryptedSecretData = _encryptedSecretData; + other.encryptedMetadata = _encryptedMetadata; + other->_keyclass = _keyclass; +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbKeychainSerializedItemV7 *copy = [[[self class] allocWithZone:zone] init]; + copy->_encryptedSecretData = [_encryptedSecretData copyWithZone:zone]; + copy->_encryptedMetadata = [_encryptedMetadata copyWithZone:zone]; + copy->_keyclass = _keyclass; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbKeychainSerializedItemV7 *other = (SecDbKeychainSerializedItemV7 *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_encryptedSecretData && !other->_encryptedSecretData) || [self->_encryptedSecretData isEqual:other->_encryptedSecretData]) + && + ((!self->_encryptedMetadata && !other->_encryptedMetadata) || [self->_encryptedMetadata isEqual:other->_encryptedMetadata]) + && + self->_keyclass == other->_keyclass + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_encryptedSecretData hash] + ^ + [self->_encryptedMetadata hash] + ^ + PBHashInt((NSUInteger)_keyclass) + ; +} + +- (void)mergeFrom:(SecDbKeychainSerializedItemV7 *)other +{ + if (other->_encryptedSecretData) + { + [self setEncryptedSecretData:other->_encryptedSecretData]; + } + if (other->_encryptedMetadata) + { + [self setEncryptedMetadata:other->_encryptedMetadata]; + } + self->_keyclass = other->_keyclass; +} + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h new file mode 100644 index 00000000..a2855be0 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h @@ -0,0 +1,40 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedMetadata.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION extern "C" +#else +#define SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION extern +#endif + +@interface SecDbKeychainSerializedMetadata : PBCodable +{ + NSData *_ciphertext; + NSString *_tamperCheck; + NSData *_wrappedKey; +} + + +@property (nonatomic, retain) NSData *ciphertext; + +@property (nonatomic, retain) NSData *wrappedKey; + +@property (nonatomic, retain) NSString *tamperCheck; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbKeychainSerializedMetadata *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbKeychainSerializedMetadata *)other; + +SECDBKEYCHAINSERIALIZEDMETADATA_FUNCTION BOOL SecDbKeychainSerializedMetadataReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadata *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m new file mode 100644 index 00000000..b32c5b2d --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m @@ -0,0 +1,167 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedMetadata.proto + +#import "SecDbKeychainSerializedMetadata.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbKeychainSerializedMetadata + +@synthesize ciphertext = _ciphertext; +@synthesize wrappedKey = _wrappedKey; +@synthesize tamperCheck = _tamperCheck; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_ciphertext) + { + [dict setObject:self->_ciphertext forKey:@"ciphertext"]; + } + if (self->_wrappedKey) + { + [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; + } + if (self->_tamperCheck) + { + [dict setObject:self->_tamperCheck forKey:@"tamperCheck"]; + } + return dict; +} + +BOOL SecDbKeychainSerializedMetadataReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadata *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* ciphertext */: + { + NSData *new_ciphertext = PBReaderReadData(reader); + self->_ciphertext = new_ciphertext; + } + break; + case 2 /* wrappedKey */: + { + NSData *new_wrappedKey = PBReaderReadData(reader); + self->_wrappedKey = new_wrappedKey; + } + break; + case 3 /* tamperCheck */: + { + NSString *new_tamperCheck = PBReaderReadString(reader); + self->_tamperCheck = new_tamperCheck; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbKeychainSerializedMetadataReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* ciphertext */ + { + assert(nil != self->_ciphertext); + PBDataWriterWriteDataField(writer, self->_ciphertext, 1); + } + /* wrappedKey */ + { + assert(nil != self->_wrappedKey); + PBDataWriterWriteDataField(writer, self->_wrappedKey, 2); + } + /* tamperCheck */ + { + assert(nil != self->_tamperCheck); + PBDataWriterWriteStringField(writer, self->_tamperCheck, 3); + } +} + +- (void)copyTo:(SecDbKeychainSerializedMetadata *)other +{ + other.ciphertext = _ciphertext; + other.wrappedKey = _wrappedKey; + other.tamperCheck = _tamperCheck; +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbKeychainSerializedMetadata *copy = [[[self class] allocWithZone:zone] init]; + copy->_ciphertext = [_ciphertext copyWithZone:zone]; + copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; + copy->_tamperCheck = [_tamperCheck copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbKeychainSerializedMetadata *other = (SecDbKeychainSerializedMetadata *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_ciphertext && !other->_ciphertext) || [self->_ciphertext isEqual:other->_ciphertext]) + && + ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) + && + ((!self->_tamperCheck && !other->_tamperCheck) || [self->_tamperCheck isEqual:other->_tamperCheck]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_ciphertext hash] + ^ + [self->_wrappedKey hash] + ^ + [self->_tamperCheck hash] + ; +} + +- (void)mergeFrom:(SecDbKeychainSerializedMetadata *)other +{ + if (other->_ciphertext) + { + [self setCiphertext:other->_ciphertext]; + } + if (other->_wrappedKey) + { + [self setWrappedKey:other->_wrappedKey]; + } + if (other->_tamperCheck) + { + [self setTamperCheck:other->_tamperCheck]; + } +} + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h new file mode 100644 index 00000000..9f74bff0 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h @@ -0,0 +1,44 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedSecretData.proto + +#import +#import + +#ifdef __cplusplus +#define SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION extern "C" +#else +#define SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION extern +#endif + +@interface SecDbKeychainSerializedSecretData : PBCodable +{ + NSData *_ciphertext; + NSData *_secDbBackupWrappedItemKey; + NSString *_tamperCheck; + NSData *_wrappedKey; +} + + +@property (nonatomic, retain) NSData *ciphertext; + +@property (nonatomic, retain) NSData *wrappedKey; + +@property (nonatomic, retain) NSString *tamperCheck; + +@property (nonatomic, readonly) BOOL hasSecDbBackupWrappedItemKey; +@property (nonatomic, retain) NSData *secDbBackupWrappedItemKey; + +// Performs a shallow copy into other +- (void)copyTo:(SecDbKeychainSerializedSecretData *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SecDbKeychainSerializedSecretData *)other; + +SECDBKEYCHAINSERIALIZEDSECRETDATA_FUNCTION BOOL SecDbKeychainSerializedSecretDataReadFrom(__unsafe_unretained SecDbKeychainSerializedSecretData *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m new file mode 100644 index 00000000..b073d483 --- /dev/null +++ b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m @@ -0,0 +1,202 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SecDbKeychainSerializedSecretData.proto + +#import "SecDbKeychainSerializedSecretData.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SecDbKeychainSerializedSecretData + +@synthesize ciphertext = _ciphertext; +@synthesize wrappedKey = _wrappedKey; +@synthesize tamperCheck = _tamperCheck; +- (BOOL)hasSecDbBackupWrappedItemKey +{ + return _secDbBackupWrappedItemKey != nil; +} +@synthesize secDbBackupWrappedItemKey = _secDbBackupWrappedItemKey; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_ciphertext) + { + [dict setObject:self->_ciphertext forKey:@"ciphertext"]; + } + if (self->_wrappedKey) + { + [dict setObject:self->_wrappedKey forKey:@"wrappedKey"]; + } + if (self->_tamperCheck) + { + [dict setObject:self->_tamperCheck forKey:@"tamperCheck"]; + } + if (self->_secDbBackupWrappedItemKey) + { + [dict setObject:self->_secDbBackupWrappedItemKey forKey:@"SecDbBackupWrappedItemKey"]; + } + return dict; +} + +BOOL SecDbKeychainSerializedSecretDataReadFrom(__unsafe_unretained SecDbKeychainSerializedSecretData *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* ciphertext */: + { + NSData *new_ciphertext = PBReaderReadData(reader); + self->_ciphertext = new_ciphertext; + } + break; + case 2 /* wrappedKey */: + { + NSData *new_wrappedKey = PBReaderReadData(reader); + self->_wrappedKey = new_wrappedKey; + } + break; + case 3 /* tamperCheck */: + { + NSString *new_tamperCheck = PBReaderReadString(reader); + self->_tamperCheck = new_tamperCheck; + } + break; + case 4 /* secDbBackupWrappedItemKey */: + { + NSData *new_secDbBackupWrappedItemKey = PBReaderReadData(reader); + self->_secDbBackupWrappedItemKey = new_secDbBackupWrappedItemKey; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SecDbKeychainSerializedSecretDataReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* ciphertext */ + { + assert(nil != self->_ciphertext); + PBDataWriterWriteDataField(writer, self->_ciphertext, 1); + } + /* wrappedKey */ + { + assert(nil != self->_wrappedKey); + PBDataWriterWriteDataField(writer, self->_wrappedKey, 2); + } + /* tamperCheck */ + { + assert(nil != self->_tamperCheck); + PBDataWriterWriteStringField(writer, self->_tamperCheck, 3); + } + /* secDbBackupWrappedItemKey */ + { + if (self->_secDbBackupWrappedItemKey) + { + PBDataWriterWriteDataField(writer, self->_secDbBackupWrappedItemKey, 4); + } + } +} + +- (void)copyTo:(SecDbKeychainSerializedSecretData *)other +{ + other.ciphertext = _ciphertext; + other.wrappedKey = _wrappedKey; + other.tamperCheck = _tamperCheck; + if (_secDbBackupWrappedItemKey) + { + other.secDbBackupWrappedItemKey = _secDbBackupWrappedItemKey; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SecDbKeychainSerializedSecretData *copy = [[[self class] allocWithZone:zone] init]; + copy->_ciphertext = [_ciphertext copyWithZone:zone]; + copy->_wrappedKey = [_wrappedKey copyWithZone:zone]; + copy->_tamperCheck = [_tamperCheck copyWithZone:zone]; + copy->_secDbBackupWrappedItemKey = [_secDbBackupWrappedItemKey copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SecDbKeychainSerializedSecretData *other = (SecDbKeychainSerializedSecretData *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_ciphertext && !other->_ciphertext) || [self->_ciphertext isEqual:other->_ciphertext]) + && + ((!self->_wrappedKey && !other->_wrappedKey) || [self->_wrappedKey isEqual:other->_wrappedKey]) + && + ((!self->_tamperCheck && !other->_tamperCheck) || [self->_tamperCheck isEqual:other->_tamperCheck]) + && + ((!self->_secDbBackupWrappedItemKey && !other->_secDbBackupWrappedItemKey) || [self->_secDbBackupWrappedItemKey isEqual:other->_secDbBackupWrappedItemKey]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_ciphertext hash] + ^ + [self->_wrappedKey hash] + ^ + [self->_tamperCheck hash] + ^ + [self->_secDbBackupWrappedItemKey hash] + ; +} + +- (void)mergeFrom:(SecDbKeychainSerializedSecretData *)other +{ + if (other->_ciphertext) + { + [self setCiphertext:other->_ciphertext]; + } + if (other->_wrappedKey) + { + [self setWrappedKey:other->_wrappedKey]; + } + if (other->_tamperCheck) + { + [self setTamperCheck:other->_tamperCheck]; + } + if (other->_secDbBackupWrappedItemKey) + { + [self setSecDbBackupWrappedItemKey:other->_secDbBackupWrappedItemKey]; + } +} + +@end + diff --git a/keychain/securityd/SecDbQuery.c b/keychain/securityd/SecDbQuery.c new file mode 100644 index 00000000..88d72177 --- /dev/null +++ b/keychain/securityd/SecDbQuery.c @@ -0,0 +1,987 @@ + +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecDbQuery.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#include "keychain/securityd/SecDbQuery.h" + +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/spi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_KEYSTORE +#include +#include +#include +#endif + +/* Upper limit for number of keys in a QUERY dictionary. */ +#define QUERY_KEY_LIMIT_BASE (128) +#ifdef NO_SERVER +#define QUERY_KEY_LIMIT (31 + QUERY_KEY_LIMIT_BASE) +#else +#define QUERY_KEY_LIMIT QUERY_KEY_LIMIT_BASE +#endif + + +static const uint8_t systemKeychainUUID[] = "\xF6\x23\xAE\x5C\xCC\x81\x4C\xAC\x8A\xD4\xF0\x01\x3F\x31\x35\x11"; + +CFDataRef +SecMUSRCopySystemKeychainUUID(void) +{ + return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull); +} + +CFDataRef +SecMUSRGetSystemKeychainUUID(void) +{ + static dispatch_once_t onceToken; + static CFDataRef systemKeychainData = NULL; + dispatch_once(&onceToken, ^{ + systemKeychainData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull); + }); + return systemKeychainData; +} + +CFDataRef +SecMUSRGetSingleUserKeychainUUID(void) +{ + static dispatch_once_t onceToken; + static CFDataRef singleUser = NULL; + dispatch_once(&onceToken, ^{ + singleUser = CFDataCreateWithBytesNoCopy(NULL, NULL, 0, kCFAllocatorNull); + }); + return singleUser; +} + +bool +SecMUSRIsSingleUserView(CFDataRef musr) +{ + return CFEqual(musr, SecMUSRGetSingleUserKeychainUUID()); +} + +static const uint8_t allKeychainViewsUUID[16] = "\xC8\x60\x07\xEC\x89\x62\x4D\xAF\x85\x65\x1F\xE6\x0F\x50\x5D\xB7"; + +CFDataRef +SecMUSRGetAllViews(void) +{ + static dispatch_once_t onceToken; + static CFDataRef allKeychainViewsData = NULL; + dispatch_once(&onceToken, ^{ + allKeychainViewsData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)allKeychainViewsUUID, 16, kCFAllocatorNull); + }); + return allKeychainViewsData; +} + +bool +SecMUSRIsViewAllViews(CFDataRef musr) +{ + return CFEqual(musr, SecMUSRGetAllViews()); +} + +#if TARGET_OS_IPHONE + +CFDataRef +SecMUSRCreateActiveUserUUID(uid_t uid) +{ + uint8_t uuid[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72"; + uint32_t num = htonl(uid); + memcpy(&uuid[12], &num, sizeof(num)); + return CFDataCreate(NULL, uuid, sizeof(uuid)); +} + +CFDataRef +SecMUSRCreateSyncBubbleUserUUID(uid_t uid) +{ + uint8_t uuid[16] = "\x82\x1A\xAB\x9F\xA3\xC8\x4E\x11\xAA\x90\x4C\xE8\x9E\xA6\xD7\xEC"; + uint32_t num = htonl(uid); + memcpy(&uuid[12], &num, sizeof(num)); + return CFDataCreate(NULL, uuid, sizeof(uuid)); +} + +static const uint8_t bothUserAndSystemUUID[12] = "\x36\xC4\xBE\x2E\x99\x0A\x46\x9A\xAC\x89\x09\xA4"; + + +CFDataRef +SecMUSRCreateBothUserAndSystemUUID(uid_t uid) +{ + uint8_t uuid[16]; + memcpy(uuid, bothUserAndSystemUUID, 12); + uint32_t num = htonl(uid); + memcpy(&uuid[12], &num, sizeof(num)); + return CFDataCreate(NULL, uuid, sizeof(uuid)); +} + +bool +SecMUSRGetBothUserAndSystemUUID(CFDataRef musr, uid_t *uid) +{ + if (CFDataGetLength(musr) != 16) + return false; + const uint8_t *uuid = CFDataGetBytePtr(musr); + if (memcmp(uuid, bothUserAndSystemUUID, 12) != 0) + return false; + if (uid) { + uint32_t num; + memcpy(&num, &uuid[12], sizeof(num)); + *uid = htonl(num); + } + return true; +} + +#endif + +/* Inline accessors to attr and match values in a query. */ +CFIndex query_attr_count(const Query *q) +{ + return q->q_attr_end; +} + +Pair query_attr_at(const Query *q, CFIndex ix) +{ + return q->q_pairs[ix]; +} + +CFIndex query_match_count(const Query *q) +{ + return q->q_match_end - q->q_match_begin; +} + +__unused static inline Pair query_match_at(const Query *q, CFIndex ix) +{ + return q->q_pairs[q->q_match_begin + ix]; +} + +/* Private routines used to parse a query. */ + +const SecDbClass *kc_class_with_name(CFStringRef name) { + if (isString(name)) { + if (CFEqual(name, kSecClassGenericPassword)) + return genp_class(); + else if (CFEqual(name, kSecClassInternetPassword)) + return inet_class(); + else if (CFEqual(name, kSecClassCertificate)) + return cert_class(); + else if (CFEqual(name, kSecClassKey)) + return keys_class(); + else if (CFEqual(name, kSecClassIdentity)) + return identity_class(); + } + return NULL; +} + +static void query_set_access_control(Query *q, SecAccessControlRef access_control) { + if (q->q_access_control) { + if (!CFEqual(q->q_access_control, access_control)) { + SecError(errSecItemIllegalQuery, &q->q_error, CFSTR("conflicting kSecAccess and kSecAccessControl attributes")); + } + } else { + /* Store access control virtual attribute. */ + q->q_access_control = (SecAccessControlRef)CFRetain(access_control); + + /* Also set legacy access attribute. */ + CFTypeRef protection = SecAccessControlGetProtection(q->q_access_control); + if (!protection) { + SecError(errSecParam, &q->q_error, CFSTR("kSecAccessControl missing protection")); + return; + } + CFDictionarySetValue(q->q_item, kSecAttrAccessible, protection); + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string or number of length 4. + value (ok) is a caller provided, non NULL CFTypeRef. + */ +void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) +{ + if (CFEqual(desc->name, kSecAttrSynchronizable)) { + q->q_sync = true; + if (CFEqual(value, kSecAttrSynchronizableAny)) + return; /* skip the attribute so it isn't part of the search */ + } + + CFTypeRef attr = NULL; + switch (desc->kind) { + case kSecDbDataAttr: + attr = copyData(value); + break; + case kSecDbBlobAttr: + case kSecDbAccessControlAttr: + attr = copyBlob(value); + break; + case kSecDbDateAttr: + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + attr = copyDate(value); + break; + case kSecDbNumberAttr: + case kSecDbSyncAttr: + case kSecDbTombAttr: + attr = copyNumber(value); + break; + case kSecDbAccessAttr: + case kSecDbStringAttr: + attr = copyString(value); + break; + case kSecDbSHA1Attr: + attr = copySHA1(value); + break; + case kSecDbRowIdAttr: + case kSecDbPrimaryKeyAttr: + case kSecDbEncryptedDataAttr: + case kSecDbUTombAttr: + break; + case kSecDbUUIDAttr: + attr = copyUUID(value); + break; + } + + if (!attr) { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value); + return; + } + + /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */ + if (q->q_item && desc->kind != kSecDbSHA1Attr) { + CFDictionarySetValue(q->q_item, desc->name, attr); + } + + /* Convert attr to (sha1) digest if requested. */ + if (desc->flags & kSecDbSHA1ValueInFlag) { + CFDataRef data = copyData(attr); + CFRelease(attr); + if (!data) { + SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name); + return; + } + + CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH); + CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH); + /* 64 bits cast: worst case is we generate the wrong hash */ + assert((unsigned long)CFDataGetLength(data)kind != kSecDbAccessControlAttr) { + /* Record the new attr key, value in q_pairs. */ + if (q->q_attr_end + 1 < q->q_pairs_count) { + q->q_pairs[q->q_attr_end].key = desc->name; + q->q_pairs[q->q_attr_end++].value = attr; + } else { + SecError(errSecInternal, &q->q_error, CFSTR("q_pairs overflow")); + CFReleaseSafe(attr); + } + } else { + CFReleaseSafe(attr); + } +} + +void query_add_attribute(const void *key, const void *value, Query *q) +{ + if (CFEqual(key, kSecAttrDeriveSyncIDFromItemAttributes)) { + q->q_uuid_from_primary_key = CFBooleanGetValue(value); + return; /* skip the attribute so it isn't part of the search */ + } + + const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); + if (desc) { + query_add_attribute_with_desc(desc, value, q); + + if (desc->kind == kSecDbAccessControlAttr) { + CFDataRef attr = (CFDataRef)CFDictionaryGetValue(q->q_item, desc->name); + if (attr) { + SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error); + if (access_control) { + query_set_access_control(q, access_control); + CFRelease(access_control); + } + } + } + + if (desc->kind == kSecDbAccessAttr) { + SecAccessControlRef access_control = SecAccessControlCreate(kCFAllocatorDefault, &q->q_error); + if (access_control) { + CFStringRef attr = (CFStringRef)CFDictionaryGetValue(q->q_item, desc->name); + if (attr) { + if (SecAccessControlSetProtection(access_control, attr, &q->q_error)) + query_set_access_control(q, access_control); + } + CFRelease(access_control); + } + } + } +} + +void query_add_or_attribute(const void *key, const void *value, Query *q) +{ + const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); + if (desc) { + CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name); + CFMutableArrayRef array = NULL; + if (oldValue) { + if (isArray(oldValue)) { + array = (CFMutableArrayRef)CFRetain(oldValue); + } else { + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(array, oldValue); + } + CFDictionaryRemoveValue(q->q_item, desc->name); + } else { + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + } + if (array) { + query_add_attribute_with_desc(desc, value, q); + CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name); + CFArrayAppendValue(array, newValue); + CFDictionarySetValue(q->q_item, desc->name, array); + CFRelease(array); + } + } +} + +void query_add_not_attribute(const void *key, const void *value, Query *q) +{ + const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); + if (desc) { + CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name); + CFMutableArrayRef array = NULL; + if (oldValue) { + if (isArray(oldValue)) { + array = (CFMutableArrayRef)CFRetain(oldValue); + } else { + // This should never run, as we shouldn't be turning a attr = value into a attr not in (value, value2) + secerror("negating %@ = %@ in query", desc->name, oldValue); + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(array, kCFNull); + CFArrayAppendValue(array, oldValue); + } + CFDictionaryRemoveValue(q->q_item, desc->name); + } else { + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(array, kCFNull); + } + if (array) { + query_add_attribute_with_desc(desc, value, q); + CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name); + CFArrayAppendValue(array, newValue); + CFDictionarySetValue(q->q_item, desc->name, array); + CFRelease(array); + } + } +} + + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string starting with 'm'. + value (ok) is a caller provided, non NULL CFTypeRef. + */ +static void query_add_match(const void *key, const void *value, Query *q) +{ + /* Record the match key, value in q_pairs. */ + --(q->q_match_begin); + q->q_pairs[q->q_match_begin].key = key; + q->q_pairs[q->q_match_begin].value = value; + + if (CFEqual(kSecMatchLimit, key)) { + /* Figure out what the value for kSecMatchLimit is if specified. */ + if (CFGetTypeID(value) == CFNumberGetTypeID()) { + if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit)) + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value); + } else if (CFEqual(kSecMatchLimitAll, value)) { + q->q_limit = kSecMatchUnlimited; + } else if (CFEqual(kSecMatchLimitOne, value)) { + q->q_limit = 1; + } else { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value); + } + } else if (CFEqual(kSecMatchIssuers, key) && + (CFGetTypeID(value) == CFArrayGetTypeID())) + { + CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if (canonical_issuers) { + CFIndex i, count = CFArrayGetCount(value); + for (i = 0; i < count; i++) { + CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i); + CFDataRef issuer_canonical = NULL; + if (CFDataGetTypeID() == CFGetTypeID(issuer_data)) + issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data); + if (issuer_canonical) { + CFArrayAppendValue(canonical_issuers, issuer_canonical); + CFRelease(issuer_canonical); + } + } + + if (CFArrayGetCount(canonical_issuers) > 0) { + q->q_match_issuer = canonical_issuers; + } else + CFRelease(canonical_issuers); + } + } else if (CFEqual(kSecMatchPolicy, key)) { + if (CFGetTypeID(value) != CFArrayGetTypeID()) { + SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute")); + return; + } + xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value); + if (!policiesArrayXPC) { + SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query")); + return; + } + + CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error); + xpc_release(policiesArrayXPC); + if (!policiesArray) + return; + + if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) { + CFRelease(policiesArray); + SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies")); + return; + } + + query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0)); + CFRelease(policiesArray); + } else if (CFEqual(kSecMatchValidOnDate, key)) { + if (CFGetTypeID(value) == CFNullGetTypeID()) { + CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); + query_set_valid_on_date(q, date); + CFRelease(date); + } else if (CFGetTypeID(value) == CFDateGetTypeID()) { + query_set_valid_on_date(q, value); + } else { + SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute")); + return; + } + } else if (CFEqual(kSecMatchTrustedOnly, key)) { + if ((CFGetTypeID(value) == CFBooleanGetTypeID())) { + query_set_trusted_only(q, value); + } else { + SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute")); + return; + } + } +} + +static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) { + const SecDbClass *value; + if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() && + (value = kc_class_with_name(c_name)) && + (q->q_class == 0 || q->q_class == value)) { + q->q_class = value; + return true; + } + + if (error && !*error) + SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name); + + + return false; +} + +static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) { + CFStringRef c_name = NULL; + const void *value = CFDictionaryGetValue(query, kSecClass); + if (isString(value)) { + c_name = value; + } else { + value = CFDictionaryGetValue(query, kSecValuePersistentRef); + if (isData(value)) { + CFDataRef pref = value; + _SecItemParsePersistentRef(pref, &c_name, NULL, NULL); + } + } + + if (c_name && (value = kc_class_with_name(c_name))) { + return value; + } else { + if (c_name) + SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name); + else + SecError(errSecItemClassMissing, error, CFSTR("query missing class name")); + return NULL; + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string starting with 'c'. + value (ok) is a caller provided, non NULL CFTypeRef. + */ +static void query_add_class(const void *key, const void *value, Query *q) +{ + if (CFEqual(key, kSecClass)) { + query_set_class(q, value, &q->q_error); + } else { + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass); + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string starting with 'r'. + value (ok) is a caller provided, non NULL CFTypeRef. + */ +static void query_add_return(const void *key, const void *value, Query *q) +{ + ReturnTypeMask mask; + if (CFGetTypeID(value) != CFBooleanGetTypeID()) { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value); + return; + } + + int set_it = CFEqual(value, kCFBooleanTrue); + + if (CFEqual(key, kSecReturnData)) + mask = kSecReturnDataMask; + else if (CFEqual(key, kSecReturnAttributes)) + mask = kSecReturnAttributesMask; + else if (CFEqual(key, kSecReturnRef)) + mask = kSecReturnRefMask; + else if (CFEqual(key, kSecReturnPersistentRef)) + mask = kSecReturnPersistentRefMask; + else { + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key); + return; + } + + if ((q->q_return_type & mask) && !set_it) { + /* Clear out this bit (it's set so xor with the mask will clear it). */ + q->q_return_type ^= mask; + } else if (!(q->q_return_type & mask) && set_it) { + /* Set this bit. */ + q->q_return_type |= mask; + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string starting with 'u'. + value (ok since q_use_item_list is unused) is a caller provided, non + NULL CFTypeRef. + */ +static void query_add_use(const void *key, const void *value, Query *q) +{ + // Gotta use a string literal because we just outlawed this symbol on iOS + if (CFEqual(key, CFSTR("u_ItemList"))) { + /* TODO: Add sanity checking when we start using this. */ + q->q_use_item_list = value; + } else if (CFEqual(key, kSecUseTombstones)) { + if (CFGetTypeID(value) == CFBooleanGetTypeID()) { + q->q_use_tomb = value; + } else if (CFGetTypeID(value) == CFNumberGetTypeID()) { + q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse; + } else if (CFGetTypeID(value) == CFStringGetTypeID()) { + q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse; + } else { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key); + return; + } + } else if (CFEqual(key, kSecUseCredentialReference)) { + if (isData(value)) { + CFRetainAssign(q->q_use_cred_handle, value); + } else { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key); + return; + } + } else if (CFEqual(key, kSecUseAuthenticationUI)) { + if (isString(value)) { + q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value); + } else { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key); + return; + } +#if TARGET_OS_IPHONE + } else if (CFEqual(key, kSecUseSystemKeychain)) { +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + q->q_keybag = KEYBAG_DEVICE; +#endif + q->q_system_keychain = true; + } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) { + if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) { +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + q->q_keybag = KEYBAG_DEVICE; +#endif + } else { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key); + return; + } +#endif + } else { + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key); + return; + } +} + +static void query_set_data(const void *value, Query *q) { + if (!isData(value)) { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value); + } else { + q->q_data = value; + if (q->q_item) + CFDictionarySetValue(q->q_item, kSecValueData, value); + } +} + +static void query_set_token_persistent_ref(Query *q, CFDictionaryRef token_persistent_ref) { + if (token_persistent_ref) { + query_add_attribute(kSecAttrTokenID, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenID), q); + CFRetainAssign(q->q_token_object_id, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenOID)); + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, string starting with 'u'. + value (ok) is a caller provided, non NULL CFTypeRef. + */ +static void query_add_value(const void *key, const void *value, Query *q) +{ + if (CFEqual(key, kSecValueData)) { + query_set_data(value, q); +#ifdef NO_SERVER + } else if (CFEqual(key, kSecValueRef)) { + q->q_ref = value; + /* TODO: Add value type sanity checking. */ +#endif + } else if (CFEqual(key, kSecValuePersistentRef)) { + CFStringRef c_name; + CFDictionaryRef token_persistent_ref = NULL; + if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id, &token_persistent_ref)) { + query_set_class(q, c_name, &q->q_error); + query_set_token_persistent_ref(q, token_persistent_ref); + CFReleaseNull(token_persistent_ref); + } else + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value); + } else { + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key); + return; + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, unchecked. + value (ok) is a caller provided, unchecked. + */ +static void query_update_applier(const void *key, const void *value, + void *context) +{ + Query *q = (Query *)context; + /* If something went wrong there is no point processing any more args. */ + if (q->q_error) + return; + + /* Make sure we have a string key. */ + if (!isString(key)) { + SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key); + return; + } + + if (!value) { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key); + return; + } + + if (CFEqual(key, CFSTR("musr"))) { + secnotice("item", "update_applier: refusing to update musr"); + return; + } + + if (CFEqual(key, kSecValueData)) { + query_set_data(value, q); + } else { + query_add_attribute(key, value, q); + } +} + +/* AUDIT[securityd](done): + key (ok) is a caller provided, unchecked. + value (ok) is a caller provided, unchecked. + */ +static void query_applier(const void *key, const void *value, void *context) +{ + Query *q = (Query *)context; + /* If something went wrong there is no point processing any more args. */ + if (q->q_error) + return; + + /* Make sure we have a key. */ + if (!key) { + SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key")); + return; + } + + /* Make sure we have a value. */ + if (!value) { + SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key); + return; + } + + /* Figure out what type of key we are dealing with. */ + CFTypeID key_id = CFGetTypeID(key); + if (key_id == CFStringGetTypeID()) { + CFIndex key_len = CFStringGetLength(key); + /* String keys can be different things. The subtype is determined by: + length 4 strings are all attributes. Otherwise the first char + determines the type: + c: class must be kSecClass + m: match like kSecMatchPolicy + r: return like kSecReturnData + u: use keys + v: value + f: callbacks (ignored by the query applier) + */ + if (key_len == 4) { + /* attributes */ + query_add_attribute(key, value, q); + } else if (key_len > 1) { + // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with + // these matching rules. skip it for now, since it isn't filled in anyway. + if(CFEqualSafe(key, CFSTR("persistref"))) { + return; + } + + UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0); + switch (k_first_char) + { + case 'c': /* class */ + query_add_class(key, value, q); + break; + case 'm': /* match */ + query_add_match(key, value, q); + break; + case 'r': /* return */ + query_add_return(key, value, q); + break; + case 'u': /* use */ + query_add_use(key, value, q); + break; + case 'v': /* value */ + query_add_value(key, value, q); + break; + case 'f': + break; + default: + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key); + break; + } + } else { + SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key); + } + } else if (key_id == CFNumberGetTypeID()) { + /* Numeric keys are always (extended) attributes. */ + /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */ + query_add_attribute(key, value, q); + } else { + /* We only support string and number type keys. */ + SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key); + } +} + +static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) { + /* apsd are always dku. */ + if (CFEqual(agrp, CFSTR("com.apple.apsd"))) { + return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate; + } + /* All other certs or in the apple agrp is dk. */ + if (q->q_class == cert_class()) { + /* third party certs are always dk. */ + return kSecAttrAccessibleAlwaysPrivate; + } + /* The rest defaults to ak. */ + return kSecAttrAccessibleWhenUnlocked; +} + +void query_ensure_access_control(Query *q, CFStringRef agrp) { + if (q->q_access_control == 0) { + CFStringRef accessible = query_infer_keyclass(q, agrp); + query_add_attribute(kSecAttrAccessible, accessible, q); + } +} + +bool query_error(Query *q, CFErrorRef *error) { + CFErrorRef tmp = q->q_error; + q->q_error = NULL; + return SecErrorPropagate(tmp, error); +} + +bool query_destroy(Query *q, CFErrorRef *error) { + bool ok = query_error(q, error); + CFIndex ix, attr_count = query_attr_count(q); + for (ix = 0; ix < attr_count; ++ix) { + CFReleaseSafe(query_attr_at(q, ix).value); + } + CFReleaseSafe(q->q_item); + CFReleaseSafe(q->q_musrView); + CFReleaseSafe(q->q_primary_key_digest); + CFReleaseSafe(q->q_match_issuer); + CFReleaseSafe(q->q_access_control); + CFReleaseSafe(q->q_use_cred_handle); + CFReleaseSafe(q->q_caller_access_groups); + CFReleaseSafe(q->q_match_policy); + CFReleaseSafe(q->q_match_valid_on_date); + CFReleaseSafe(q->q_match_trusted_only); + CFReleaseSafe(q->q_token_object_id); + + free(q); + return ok; +} + +bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) { + if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) { + SecKeychainChanged(); + } + return query_destroy(q, error) && ok; +} + +/* Allocate and initialize a Query object for query. */ +Query *query_create(const SecDbClass *qclass, + CFDataRef musr, + CFDictionaryRef query, + CFErrorRef *error) +{ + if (!qclass) { + if (error && !*error) + SecError(errSecItemClassMissing, error, CFSTR("Missing class")); + return NULL; + } + + if (musr == NULL) + musr = SecMUSRGetSingleUserKeychainUUID(); + + /* Number of pairs we need is the number of attributes in this class + plus the number of keys in the dictionary, minus one for each key in + the dictionary that is a regular attribute. */ + CFIndex key_count = SecDbClassAttrCount(qclass); + if (key_count == 0) { + // Identities claim to have 0 attributes, but they really support any keys or cert attribute. + key_count = SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class()); + } + + if (query) { + key_count += CFDictionaryGetCount(query); + SecDbForEachAttr(qclass, attr) { + if (CFDictionaryContainsKey(query, attr->name)) + --key_count; + } + } + + if (key_count > QUERY_KEY_LIMIT) { + if (error && !*error) + { + secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT); + SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit")); + } + return NULL; + } + + Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count); + if (q == NULL) { + if (error && !*error) + SecError(errSecAllocate, error, CFSTR("Out of memory")); + return NULL; + } + + q->q_pairs_count = key_count; + q->q_musrView = (CFDataRef)CFRetain(musr); + q->q_uuid_from_primary_key = false; + q->q_keybag = KEYBAG_DEVICE; + q->q_class = qclass; + q->q_match_begin = q->q_match_end = key_count; + q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + return q; +} + +/* Parse query for a Query object q. */ +static bool query_parse_with_applier(Query *q, CFDictionaryRef query, + CFDictionaryApplierFunction applier, + CFErrorRef *error) { + CFDictionaryApplyFunction(query, applier, q); + return query_error(q, error); +} + +/* Parse query for a Query object q. */ +static bool query_parse(Query *q, CFDictionaryRef query, + CFErrorRef *error) { + return query_parse_with_applier(q, query, query_applier, error); +} + +/* Parse query for a Query object q. */ +bool query_update_parse(Query *q, CFDictionaryRef update, + CFErrorRef *error) { + return query_parse_with_applier(q, update, query_update_applier, error); +} + +Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) { + Query *q; + q = query_create(query_get_class(query, error), musr, query, error); + if (q) { + q->q_limit = limit; + if (!query_parse(q, query, error)) { + query_destroy(q, error); + return NULL; + } + if (!q->q_sync && !q->q_row_id && !q->q_token_object_id) { + /* query did not specify a kSecAttrSynchronizable attribute, + * and did not contain a persistent reference. */ + query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q); + } + } + return q; +} + + +void +query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) { + CFRetainAssign(q->q_caller_access_groups, caller_access_groups); +} + +void +query_set_policy(Query *q, SecPolicyRef policy) { + CFRetainAssign(q->q_match_policy, policy); +} + +void query_set_valid_on_date(Query *q, CFDateRef date) { + CFRetainAssign(q->q_match_valid_on_date, date); +} + +void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) { + CFRetainAssign(q->q_match_trusted_only, trusted_only); +} diff --git a/keychain/securityd/SecDbQuery.h b/keychain/securityd/SecDbQuery.h new file mode 100644 index 00000000..820090bf --- /dev/null +++ b/keychain/securityd/SecDbQuery.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecDbQuery.h - The thing that does the stuff with the gibli. + */ + +#ifndef _SECURITYD_SECDBQUERY_H_ +#define _SECURITYD_SECDBQUERY_H_ + +#include "keychain/securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecDbItem.h" + +__BEGIN_DECLS + +typedef struct Pair *SecDbPairRef; +typedef struct Query *SecDbQueryRef; + +/* Return types. */ +typedef uint32_t ReturnTypeMask; +enum +{ + kSecReturnDataMask = 1 << 0, + kSecReturnAttributesMask = 1 << 1, + kSecReturnRefMask = 1 << 2, + kSecReturnPersistentRefMask = 1 << 3, +}; + +/* Constant indicating there is no limit to the number of results to return. */ +enum +{ + kSecMatchUnlimited = kCFNotFound +}; + +typedef struct Pair +{ + const void *key; + const void *value; +} Pair; + +/* Nothing in this struct is retained since all the + values below are extracted from the dictionary passed in by the + caller. */ +typedef struct Query +{ + /* Class of this query. */ + const SecDbClass *q_class; + + /* Dictionary with all attributes and values in clear (to be encrypted). */ + CFMutableDictionaryRef q_item; + + /* q_pairs is an array of Pair structs. Elements with indices + [0, q_attr_end) contain attribute key value pairs. Elements with + indices [q_match_begin, q_match_end) contain match key value pairs. + Thus q_attr_end is the number of attrs in q_pairs and + q_match_begin - q_match_end is the number of matches in q_pairs. */ + CFIndex q_match_begin; + CFIndex q_match_end; + CFIndex q_attr_end; + + CFErrorRef q_error; + ReturnTypeMask q_return_type; + + CFDataRef q_data; + CFTypeRef q_ref; + sqlite_int64 q_row_id; + + CFArrayRef q_use_item_list; + CFBooleanRef q_use_tomb; + + /* Value of kSecMatchLimit key if present. */ + CFIndex q_limit; + + /* True if query contained a kSecAttrSynchronizable attribute, + * regardless of its actual value. If this is false, then we + * will add an explicit sync=0 to the query. */ + bool q_sync; + + // Set to true if we modified any item as part of executing this query + bool q_changed; + + // Set to true if we modified any synchronizable item as part of executing this query + bool q_sync_changed; + + /* Keybag handle to use for this item. */ + keybag_handle_t q_keybag; + + /* musr view to use when modifying the database */ + CFDataRef q_musrView; + + /* ACL and credHandle passed to the query. q_cred_handle contain LA context object. */ + SecAccessControlRef q_access_control; + CFDataRef q_use_cred_handle; + + // Flag indicating that ui-protected items should be simply skipped + // instead of reporting them to the client as an error. + bool q_skip_acl_items; + + // Set to true if any UUIDs generated by this query should be generated from the SHA2 digest of the item in question + bool q_uuid_from_primary_key; + + // Set this to a callback that, on an add query, will get passed along with the CKKS subsystem and called when the item makes it off-device (or doesn't) + __unsafe_unretained SecBoolCFErrorCallback q_add_sync_callback; + + // SHA1 digest of DER encoded primary key + CFDataRef q_primary_key_digest; + + CFArrayRef q_match_issuer; + + /* Caller acces groups for AKS */ + CFArrayRef q_caller_access_groups; + bool q_system_keychain; + int32_t q_sync_bubble; + bool q_spindump_on_failure; + + //policy for filtering certs and identities + SecPolicyRef q_match_policy; + //date for filtering certs and identities + CFDateRef q_match_valid_on_date; + //trusted only certs and identities + CFBooleanRef q_match_trusted_only; + //token persistent reference for filtering items is represented by token ID (in attrs) and token object ID + CFDataRef q_token_object_id; + + CFIndex q_pairs_count; + Pair q_pairs[]; +} Query; + +Query *query_create(const SecDbClass *qclass, CFDataRef musr, CFDictionaryRef query, CFErrorRef *error); +bool query_destroy(Query *q, CFErrorRef *error); +bool query_error(Query *q, CFErrorRef *error); +Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error); +void query_add_attribute(const void *key, const void *value, Query *q); +void query_add_or_attribute(const void *key, const void *value, Query *q); +void query_add_not_attribute(const void *key, const void *value, Query *q); +void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q); +void query_ensure_access_control(Query *q, CFStringRef agrp); +void query_pre_add(Query *q, bool force_date); +bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error); +CFIndex query_match_count(const Query *q); +CFIndex query_attr_count(const Query *q); +Pair query_attr_at(const Query *q, CFIndex ix); +bool query_update_parse(Query *q, CFDictionaryRef update, CFErrorRef *error); +const SecDbClass *kc_class_with_name(CFStringRef name); +void query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups); +void query_set_policy(Query *q, SecPolicyRef policy); +void query_set_valid_on_date(Query *q, CFDateRef policy); +void query_set_trusted_only(Query *q, CFBooleanRef trusted_only); + +CFDataRef +SecMUSRCopySystemKeychainUUID(void); + +CFDataRef +SecMUSRGetSystemKeychainUUID(void); + +CFDataRef +SecMUSRGetSingleUserKeychainUUID(void); + +bool +SecMUSRIsSingleUserView(CFDataRef uuid); + +CFDataRef +SecMUSRGetAllViews(void); + +bool +SecMUSRIsViewAllViews(CFDataRef musr); + +#if TARGET_OS_IPHONE +CFDataRef +SecMUSRCreateActiveUserUUID(uid_t uid); + +CFDataRef +SecMUSRCreateSyncBubbleUserUUID(uid_t uid); + +CFDataRef +SecMUSRCreateBothUserAndSystemUUID(uid_t uid); + +bool +SecMUSRGetBothUserAndSystemUUID(CFDataRef musr, uid_t *uid); + +#endif + + +__END_DECLS + +#endif /* _SECURITYD_SECDBQUERY_H_ */ diff --git a/keychain/securityd/SecItemBackupServer.c b/keychain/securityd/SecItemBackupServer.c new file mode 100644 index 00000000..78591837 --- /dev/null +++ b/keychain/securityd/SecItemBackupServer.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/SecureObjectSync/SOSEnginePriv.h" +#include "keychain/SecureObjectSync/SOSPeer.h" +#include +#include +#include + +#include "keychain/securityd/SecDbItem.h" +#include + +static bool withDataSourceAndEngine(CFErrorRef *error, void (^action)(SOSDataSourceRef ds, SOSEngineRef engine)) { + bool ok = false; + SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); + if (ds) { + SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); + if (engine) { + action(ds, engine); + ok = true; + } + ok &= SOSDataSourceRelease(ds, error); + } + return ok; +} + +int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error) { + __block int fd = -1; + if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { + SOSEngineForPeerID(engine, backupName, error, ^(SOSTransactionRef txn, SOSPeerRef peer) { + fd = SOSPeerHandoffFD(peer, error); + }); + }) && fd >= 0) { + close(fd); + fd = -1; + } + return fd; +} + +bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifestData, CFErrorRef *error) { + __block bool ok = true; + ok &= withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { + ok = SOSEngineSetPeerConfirmedManifest(engine, backupName, keybagDigest, manifestData, error); + }); + return ok; +} + +CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error) { + __block CFArrayRef names = NULL; + if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { + names = SOSEngineCopyBackupPeerNames(engine, error); + })) { + CFReleaseNull(names); + } + return names; +} + +// TODO Move to datasource and remove dsRestoreObject +static bool SOSDataSourceWithBackup(SOSDataSourceRef ds, CFDataRef backup, keybag_handle_t bag_handle, CFErrorRef *error, void(^with)(SOSObjectRef item)) { + __block bool ok = true; + CFPropertyListRef plist = CFPropertyListCreateWithDERData(kCFAllocatorDefault, backup, kCFPropertyListImmutable, NULL, error); + CFDictionaryRef bdict = asDictionary(plist, error); + ok = (bdict != NULL); + if (ok) CFDictionaryForEach(bdict, ^(const void *key, const void *value) { + CFStringRef className = asString(key, error); + if (className) { + const SecDbClass *cls = kc_class_with_name(className); + if (cls) { + CFArrayRef items = asArray(value, error); + CFDataRef edata; + if (items) CFArrayForEachC(items, edata) { + SOSObjectRef item = (SOSObjectRef)SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, cls, edata, bag_handle, error); + if (item) { + with(item); + CFRelease(item); + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok &= SecError(errSecDecode, error, CFSTR("bad class %@ in backup"), className); + } + } else { + ok = false; + } + }); + CFReleaseSafe(plist); + return ok; +} + +bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error) { + // TODO: Decrypt and merge items in backup to dataSource + + __block bool ok = false; // return false if the bag_handle code fails. + CFDataRef aksKeybag = NULL; + CFMutableSetRef viewSet = NULL; + SOSBackupSliceKeyBagRef backupSliceKeyBag = NULL; + keybag_handle_t bag_handle = bad_keybag_handle; + + require(asData(secret, error), xit); + require(backupSliceKeyBag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, keybag, error), xit); + + if (peerID) { + bag_handle = SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, peerID, secret, error); + } else { + if (SOSBSKBIsDirect(backupSliceKeyBag)) { + bag_handle = SOSBSKBLoadAndUnlockWithDirectSecret(backupSliceKeyBag, secret, error); + } else { + bag_handle = SOSBSKBLoadAndUnlockWithWrappingSecret(backupSliceKeyBag, secret, error); + } + } + require(bag_handle != bad_keybag_handle, xit); + + // TODO: How do we know which views we are allow to restore + //viewSet = SOSAccountCopyRestorableViews(); + + ok = true; // Start from original code start point - otherwise begin in this nest of stuff + ok &= withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { + ok &= SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) { + ok &= SOSDataSourceWithBackup(ds, backup, bag_handle, error, ^(SOSObjectRef item) { + //if (SOSDataSourceIsInViewSet(item, viewSet)) { + SOSObjectRef mergedItem = NULL; + if (SOSDataSourceMergeObject(ds, txn, item, &mergedItem, error)) { + // if mergedItem == item then it was restored otherwise it was rejected by the conflict resolver. + CFReleaseSafe(mergedItem); + } + //} + }); + }); + }); + +xit: + if (bag_handle != bad_keybag_handle) + ok &= ks_close_keybag(bag_handle, error); + + CFReleaseSafe(backupSliceKeyBag); + CFReleaseSafe(aksKeybag); + CFReleaseSafe(viewSet); + + return ok; +} + + + + diff --git a/keychain/securityd/SecItemBackupServer.h b/keychain/securityd/SecItemBackupServer.h new file mode 100644 index 00000000..04607c60 --- /dev/null +++ b/keychain/securityd/SecItemBackupServer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemBackupServer.h + This file declares backup restore functionality for SecItems. + */ + +#ifndef _SECURITYD_SECITEMBACKUPSERVER_H_ +#define _SECURITYD_SECITEMBACKUPSERVER_H_ + +#include +#include + +__BEGIN_DECLS + +int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error); +bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifest, CFErrorRef *error); +CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error); +bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error); + +__END_DECLS + +#endif /* _SECURITYD_SECITEMBACKUPSERVER_H_ */ diff --git a/keychain/securityd/SecItemDataSource.c b/keychain/securityd/SecItemDataSource.c new file mode 100644 index 00000000..1845b5bb --- /dev/null +++ b/keychain/securityd/SecItemDataSource.c @@ -0,0 +1,955 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecItemDataSource.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#include "keychain/securityd/SecItemDataSource.h" + +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/SecureObjectSync/SOSDigestVector.h" +#include "keychain/SecureObjectSync/SOSEngine.h" +#include +#include +#include +#include +#include +#include +#include + +/* + * + * + * SecItemDataSource + * + * + */ +typedef struct SecItemDataSource *SecItemDataSourceRef; + +struct SecItemDataSource { + struct SOSDataSource ds; + SecDbRef db; // The database we operate on + CFStringRef name; // The name of the slice of the database we represent. +}; + + +static const SecDbClass *dsSyncedClassesV0Ptrs[] = { + NULL, + NULL, + NULL, +}; +static size_t dsSyncedClassesV0Size = (array_size(dsSyncedClassesV0Ptrs)); + +static const SecDbClass** dsSyncedClassesV0() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dsSyncedClassesV0Ptrs[0] = genp_class(); + dsSyncedClassesV0Ptrs[1] = inet_class(); + dsSyncedClassesV0Ptrs[2] = keys_class(); + }); + return dsSyncedClassesV0Ptrs; +} + + +static const SecDbClass *dsSyncedClassesPtrs[] = { + NULL, + NULL, + NULL, + NULL, +}; +static const size_t dsSyncedClassesSize = array_size(dsSyncedClassesPtrs); + +static const SecDbClass** dsSyncedClasses() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dsSyncedClassesPtrs[0] = genp_class(); // genp must be first! + dsSyncedClassesPtrs[1] = inet_class(); + dsSyncedClassesPtrs[2] = keys_class(); + dsSyncedClassesPtrs[3] = cert_class(); + }); + return dsSyncedClassesPtrs; +} + + +static bool SecDbItemSelectSHA1(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), + bool (^bind_added_where)(sqlite3_stmt *stmt, int col), + void (^row)(sqlite3_stmt *stmt, bool *stop)) { + __block bool ok = true; + bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { + return attr->kind == kSecDbSHA1Attr; + }; + CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql); + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) && + SecDbStep(dbconn, stmt, error, ^(bool *stop){ row(stmt, stop); })); + }); + CFRelease(sql); + } else { + ok = false; + } + return ok; +} + +static SOSManifestRef SecItemDataSourceCopyManifestWithQueries(SecItemDataSourceRef ds, CFArrayRef queries, CFErrorRef *error) { + __block SOSManifestRef manifest = NULL; + __block CFErrorRef localError = NULL; + if (!kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { + __block struct SOSDigestVector dv = SOSDigestVectorInit; + Query *q; + bool ok = true; + CFArrayForEachC(queries, q) { + if (!(ok &= SecDbItemSelectSHA1(q, dbconn, &localError, ^bool(const SecDbAttr *attr) { + return CFDictionaryContainsKey(q->q_item, attr->name); + }, NULL, NULL, ^(sqlite3_stmt *stmt, bool *stop) { + const uint8_t *digest = sqlite3_column_blob(stmt, 0); + size_t digestLen = sqlite3_column_bytes(stmt, 0); + if (digestLen != SOSDigestSize) { + secerror("digest %zu bytes", digestLen); + } else { + SOSDigestVectorAppend(&dv, digest); + } + }))) { + secerror("SecDbItemSelectSHA1 failed: %@", localError); + break; + } + } + if (ok) { + // TODO: This code assumes that the passed in queries do not overlap, otherwise we'd need something to eliminate dupes: + //SOSDigestVectorUniqueSorted(&dv); + manifest = SOSManifestCreateWithDigestVector(&dv, &localError); + } + SOSDigestVectorFree(&dv); + return ok; + })) { + CFReleaseSafe(manifest); + } + CFErrorPropagate(localError, error); + return manifest; +} + +static Query *SecItemDataSourceAppendQuery(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, CFErrorRef *error) { + Query *q = query_create(qclass, NULL, NULL, error); + if (q) { + q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; + q->q_limit = kSecMatchUnlimited; + q->q_keybag = KEYBAG_DEVICE; + query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, q); + query_add_or_attribute(kSecAttrAccessible, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, q); + + if (noTombstones) { + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + } + + CFArrayAppendValue(queries, q); + } + return q; +} + +static Query *SecItemDataSourceAppendQueryWithClassAndViewHint(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFStringRef viewHint, CFErrorRef *error) { + Query *q = SecItemDataSourceAppendQuery(queries, qclass, noTombstones, error); + if (q) { + // For each attribute in current schema but not in v6, look for the + // default value of those attributes in the query, since old items + // will all have that as their values for these new attributes. + SecDbForEachAttr(qclass, attr) { + if (attr == &v7tkid || attr == &v7vwht) { + // attr is a primary key attribute added in schema version 7 or later + if (!allowTkid || attr != &v7tkid) { + if (attr == &v7vwht && viewHint) { + query_add_attribute_with_desc(attr, viewHint, q); + } else { + CFTypeRef value = SecDbAttrCopyDefaultValue(attr, &q->q_error); + if (value) { + query_add_attribute_with_desc(attr, value, q); + CFRelease(value); + } + } + } + } + } + } + return q; +} + +static Query *SecItemDataSourceAppendQueryWithClass(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFErrorRef *error) { + return SecItemDataSourceAppendQueryWithClassAndViewHint(queries, qclass, noTombstones, allowTkid, NULL, error); +} + +static Query *SecItemDataSourceAppendQueryWithClassAndAgrp(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, bool allowTkid, CFStringRef agrp, CFErrorRef *error) { + Query *q = SecItemDataSourceAppendQueryWithClass(queries, qclass, noTombstones, allowTkid, error); + if (q && agrp) { + query_add_attribute(kSecAttrAccessGroup, agrp, q); + } + return q; +} + +static bool SecItemDataSourceAppendQueriesForViewName(SecItemDataSourceRef ds, CFMutableArrayRef queries, CFStringRef compositeViewName, CFErrorRef *error) { + bool ok = true; + CFStringRef viewName; + bool noTombstones = CFStringHasSuffix(compositeViewName, CFSTR("-tomb")); + if (noTombstones) { + viewName = CFStringCreateWithSubstring(kCFAllocatorDefault, compositeViewName, CFRangeMake(0, CFStringGetLength(compositeViewName) - 5)); + } else { + viewName = CFRetain(compositeViewName); + } + + // short-circuit for CKKS-handled views here + if(!SOSViewInSOSSystem(viewName)) { + CFReleaseSafe(viewName); + return ok; + } + + const bool noTKID = false; + const bool allowTKID = true; + if (CFEqual(viewName, kSOSViewKeychainV0)) { + for (size_t class_ix = 0; class_ix < dsSyncedClassesV0Size; ++class_ix) { + SecItemDataSourceAppendQueryWithClass(queries, dsSyncedClassesV0()[class_ix], noTombstones, noTKID, error); + } + } else if (CFEqual(viewName, kSOSViewWiFi)) { + Query *q = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); + if (q) { + query_add_attribute(kSecAttrService, CFSTR("AirPort"), q); + } + } else if (CFEqual(viewName, kSOSViewAutofillPasswords)) { + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, inet_class(), noTombstones, allowTKID, CFSTR("com.apple.cfnetwork"), error); + } else if (CFEqual(viewName, kSOSViewSafariCreditCards)) { + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.safari.credit-cards"), error); + } else if (CFEqual(viewName, kSOSViewiCloudIdentity)) { + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, keys_class(), noTombstones, allowTKID, CFSTR("com.apple.security.sos"), error); + } else if (CFEqual(viewName, kSOSViewBackupBagV0)) { + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.sbd"), error); + } else if (CFEqual(viewName, kSOSViewOtherSyncable)) { + SecItemDataSourceAppendQueryWithClass(queries, cert_class(), noTombstones, allowTKID, error); + + Query *q1_genp = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); + query_add_not_attribute(kSecAttrService, CFSTR("AirPort"), q1_genp); + + Query *q2_genp = SecItemDataSourceAppendQueryWithClass(queries, genp_class(), noTombstones, allowTKID, error); + query_add_not_attribute(kSecAttrAccessGroup, CFSTR("apple"), q2_genp); + query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.safari.credit-cards"), q2_genp); + query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.sbd"), q2_genp); + + Query *q_inet = SecItemDataSourceAppendQueryWithClass(queries, inet_class(), noTombstones, allowTKID, error); + query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.cfnetwork"), q_inet); + + Query *q_keys = SecItemDataSourceAppendQueryWithClass(queries, keys_class(), noTombstones, allowTKID, error); + query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), q_keys); + } else { + // All other viewNames should match on the ViewHint attribute. + for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { + SecItemDataSourceAppendQueryWithClassAndViewHint(queries, dsSyncedClasses()[class_ix], noTombstones, allowTKID, viewName, error); + } + } + + CFReleaseSafe(viewName); + return ok; +} + +static SOSManifestRef SecItemDataSourceCopyManifestWithViewNameSet(SecItemDataSourceRef ds, CFSetRef viewNames, CFErrorRef *error) { + CFMutableArrayRef queries = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + SOSManifestRef manifest = NULL; + __block bool ok = true; + CFSetForEach(viewNames, ^(const void *value) { + CFStringRef viewName = (CFStringRef)value; + ok &= SecItemDataSourceAppendQueriesForViewName(ds, queries, viewName, error); + }); + if (ok) + manifest = SecItemDataSourceCopyManifestWithQueries(ds, queries, error); + Query *q; + CFArrayForEachC(queries, q) { + CFErrorRef localError = NULL; + if (!query_destroy(q, &localError)) { + secerror("query_destroy failed: %@", localError); + CFErrorPropagate(localError, error); + CFReleaseNull(manifest); + } + } + CFReleaseSafe(queries); + return manifest; +} + +// Return the newest object (conflict resolver) +static SecDbItemRef SecItemDataSourceCopyMergedItem(SecDbItemRef item1, SecDbItemRef item2, CFErrorRef *error) { + CFErrorRef localError = NULL; + SecDbItemRef result = NULL; + CFDateRef m1, m2; + const SecDbAttr *desc = SecDbAttrWithKey(SecDbItemGetClass(item1), kSecAttrModificationDate, error); + m1 = SecDbItemGetValue(item1, desc, &localError); + m2 = SecDbItemGetValue(item2, desc, &localError); + if (m1 && m2) switch (CFDateCompare(m1, m2, NULL)) { + case kCFCompareGreaterThan: + result = item1; + break; + case kCFCompareLessThan: + result = item2; + break; + case kCFCompareEqualTo: + { + // Return the item with the smallest digest. + CFDataRef digest1 = SecDbItemGetSHA1(item1, &localError); + CFDataRef digest2 = SecDbItemGetSHA1(item2, &localError); + if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) { + case kCFCompareGreaterThan: + case kCFCompareEqualTo: + result = item2; + break; + case kCFCompareLessThan: + result = item1; + break; + } else if (SecErrorGetOSStatus(localError) == errSecDecode) { + if (digest1) result = item1; + if (digest2) result = item2; + } + break; + } + } else if (SecErrorGetOSStatus(localError) == errSecDecode) { + // If one of the two objects has an unparsable date, + // the object with the parsable date wins. + if (m1) result = item1; + if (m2) result = item2; + } + + if (localError) { + if (!result && error && !*error) + *error = localError; + else + CFRelease(localError); + } + return CFRetainSafe(result); +} + +// +// MARK: DataSource protocol implementation +// + +static CFStringRef dsGetName(SOSDataSourceRef data_source) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + return ds->name; +} + +static void dsAddNotifyPhaseBlock(SOSDataSourceRef data_source, SOSDataSourceNotifyBlock notifyBlock) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + SecDbAddNotifyPhaseBlock(ds->db, ^(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) + { + notifyBlock(&ds->ds, (SOSTransactionRef)dbconn, phase, source, changes); + }); +} + +static SOSManifestRef dsCopyManifestWithViewNameSet(SOSDataSourceRef data_source, CFSetRef viewNameSet, CFErrorRef *error) { + struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source; + return SecItemDataSourceCopyManifestWithViewNameSet(ds, viewNameSet, error); +} + +static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, SOSManifestRef manifest, CFErrorRef *error, void (^handle_object)(CFDataRef key, SOSObjectRef object, bool *stop)) { + struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source; + __block bool result = true; + const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(genp_class(), kSecDbSHA1Attr, error); + if (!sha1Attr) return false; + bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { + return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; + }; + bool (^use_attr_in_where)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { + return attr->kind == kSecDbSHA1Attr; + }; + Query *select_queries[dsSyncedClassesSize] = {}; + CFStringRef select_sql[dsSyncedClassesSize] = {}; + sqlite3_stmt *select_stmts[dsSyncedClassesSize] = {}; + + __block Query **queries = select_queries; + __block CFStringRef *sqls = select_sql; + __block sqlite3_stmt **stmts = select_stmts; + + bool (^readBlock)(SecDbConnectionRef dbconn) = ^bool(SecDbConnectionRef dbconn) + { + // Setup + for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { + result = (result + && (queries[class_ix] = query_create(dsSyncedClasses()[class_ix], NULL, NULL, error)) + && (sqls[class_ix] = SecDbItemCopySelectSQL(queries[class_ix], return_attr, use_attr_in_where, NULL)) + && (stmts[class_ix] = SecDbCopyStmt(dbconn, sqls[class_ix], NULL, error))); + } + + if (result) SOSManifestForEach(manifest, ^(CFDataRef key, bool *stop) { + __block SecDbItemRef item = NULL; + for (size_t class_ix = 0; result && !item && class_ix < dsSyncedClassesSize; ++class_ix) { + CFDictionarySetValue(queries[class_ix]->q_item, sha1Attr->name, key); + result = SecDbItemSelectBind(queries[class_ix], stmts[class_ix], error, use_attr_in_where, NULL); + if (result) { + result &= SecDbStep(dbconn, stmts[class_ix], error, ^(bool *unused_stop) { + item = SecDbItemCreateWithStatement(kCFAllocatorDefault, queries[class_ix]->q_class, stmts[class_ix], KEYBAG_DEVICE, error, return_attr); + }); + } + if (result) + result &= SecDbReset(stmts[class_ix], error); + } + handle_object(key, (SOSObjectRef)item, stop); + CFReleaseSafe(item); + }); + + // Cleanup + for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { + result &= SecDbReleaseCachedStmt(dbconn, sqls[class_ix], stmts[class_ix], error); + CFReleaseSafe(sqls[class_ix]); + if (queries[class_ix]) + result &= query_destroy(queries[class_ix], error); + } + + return true; + }; + + if (txn) { + readBlock((SecDbConnectionRef)txn); + } else { + result &= kc_with_custom_db(false, true, ds->db, error, readBlock); + } + + return result; +} + +static bool dsRelease(SOSDataSourceRef data_source, CFErrorRef *error) { + // We never release our dataSource since it's tracking changes + // to the keychain for the engine and its peers. + return true; +} + +static SOSObjectRef objectCreateWithPropertyList(CFDictionaryRef plist, CFErrorRef *error) { + SecDbItemRef item = NULL; + const SecDbClass *class = NULL; + CFTypeRef cname = CFDictionaryGetValue(plist, kSecClass); + if (cname) { + class = kc_class_with_name(cname); + if (class) { + item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, class, plist, KEYBAG_DEVICE, error); + } else { + SecError(errSecNoSuchClass, error, CFSTR("can find class named: %@"), cname); + } + } else { + SecError(errSecItemClassMissing, error, CFSTR("query missing %@ attribute"), kSecClass); + } + return (SOSObjectRef)item; +} + +static CFDataRef copyObjectDigest(SOSObjectRef object, CFErrorRef *error) { + SecDbItemRef item = (SecDbItemRef) object; + CFDataRef digest = SecDbItemGetSHA1(item, error); + CFRetainSafe(digest); + return digest; +} + +static CFDateRef copyObjectModDate(SOSObjectRef object, CFErrorRef *error) { + SecDbItemRef item = (SecDbItemRef) object; + CFDateRef modDate = SecDbItemGetValueKind(item, kSecDbModificationDateAttr, NULL); + CFRetainSafe(modDate); + return modDate; +} + +static CFDictionaryRef objectCopyPropertyList(SOSObjectRef object, CFErrorRef *error) { + SecDbItemRef item = (SecDbItemRef) object; + CFMutableDictionaryRef secretDataDict = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error); + CFMutableDictionaryRef cryptoDataDict = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error); + CFMutableDictionaryRef authDataDict = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error); + + if (cryptoDataDict) { + if (authDataDict) { + CFDictionaryForEach(authDataDict, ^(const void *key, const void *value) { + CFDictionarySetValue(cryptoDataDict, key, value); + }); + } + if (secretDataDict) { + CFDictionaryForEach(secretDataDict, ^(const void* key, const void* value) { + CFDictionarySetValue(cryptoDataDict, key, value); + }); + } + CFDictionaryAddValue(cryptoDataDict, kSecClass, SecDbItemGetClass(item)->name); + } + + CFReleaseNull(secretDataDict); + CFReleaseNull(authDataDict); + return cryptoDataDict; +} + +static bool dsWith(SOSDataSourceRef data_source, CFErrorRef *error, SOSDataSourceTransactionSource source, bool onCommitQueue, void(^transaction)(SOSTransactionRef txn, bool *commit)) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + __block bool ok = true; + ok &= kc_with_custom_db(true, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { + return SecDbTransaction(dbconn, + source == kSOSDataSourceAPITransaction ? kSecDbExclusiveTransactionType : kSecDbExclusiveRemoteSOSTransactionType, + error, ^(bool *commit) { + if (onCommitQueue) { + SecDbPerformOnCommitQueue(dbconn, false, ^{ + transaction((SOSTransactionRef)dbconn, commit); + }); + } else { + transaction((SOSTransactionRef)dbconn, commit); + } + }); + }); + return ok; +} + +static bool dsReadWith(SOSDataSourceRef data_source, CFErrorRef *error, SOSDataSourceTransactionSource source, void(^perform)(SOSTransactionRef txn)) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + __block bool ok = true; + ok &= kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { + SecDbPerformOnCommitQueue(dbconn, false, ^{ + perform((SOSTransactionRef)dbconn); + }); + return true; + }); + return ok; +} + +static SOSMergeResult dsMergeObject(SOSTransactionRef txn, SOSObjectRef peersObject, SOSObjectRef *mergedObject, CFErrorRef *error) { + SecDbConnectionRef dbconn = (SecDbConnectionRef)txn; + SecDbItemRef peersItem = (SecDbItemRef)peersObject; + __block SOSMergeResult mr = kSOSMergeFailure; + __block SecDbItemRef mergedItem = NULL; + __block SecDbItemRef replacedItem = NULL; + __block CFErrorRef localError = NULL; + __block bool attemptedMerge = false; + + if (!peersItem || !dbconn) + return kSOSMergeFailure; + if (!SecDbItemSetKeybag(peersItem, KEYBAG_DEVICE, &localError)) { + secnotice("ds", "kSOSMergeFailure => SecDbItemSetKeybag: %@", localError); + CFErrorPropagate(localError, error); + return kSOSMergeFailure; + } + + bool insertedOrReplaced = SecDbItemInsertOrReplace(peersItem, dbconn, &localError, ^(SecDbItemRef myItem, SecDbItemRef *replace) { + // An item with the same primary key as dbItem already exists in the the database. That item is old_item. + // Let the conflict resolver choose which item to keep. + attemptedMerge = true; + mergedItem = SecItemDataSourceCopyMergedItem(peersItem, myItem, &localError); + if (!mergedItem) { + mr = kSOSMergeFailure; + return; // from block + } + if (mergedObject) + *mergedObject = (SOSObjectRef)CFRetain(mergedItem); + if (CFEqual(mergedItem, myItem)) { + // Conflict resolver choose my (local) item + if (SecDbItemIsEngineInternalState(myItem)) + secdebug ("ds", "Conflict resolver chose my (local) item: %@", myItem); + else + secnotice("ds", "Conflict resolver chose my (local) item: %@", myItem); + mr = kSOSMergeLocalObject; + } else { + CFRetainAssign(replacedItem, myItem); + *replace = CFRetainSafe(mergedItem); + if (CFEqual(mergedItem, peersItem)) { + // Conflict resolver chose peer's item + if (SecDbItemIsEngineInternalState(peersItem)) + secdebug ("ds", "Conflict resolver chose peers item: %@", peersItem); + else + secnotice("ds", "Conflict resolver chose peers item: %@", peersItem); + mr = kSOSMergePeersObject; + } else { + // Conflict resolver created a new item; return it to our caller + if (SecDbItemIsEngineInternalState(mergedItem)) + secdebug ("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); + else + secnotice("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); + mr = kSOSMergeCreatedObject; + } + } + }); + + if (insertedOrReplaced && !attemptedMerge) { + // SecDbItemInsertOrReplace succeeded and conflict block was never called -> insert succeeded. + // We have peersItem in the database so we need to report that + secnotice("ds", "Insert succeeded for: %@", peersItem); + mr = kSOSMergePeersObject; + + // Report only if we had an error, too. Shouldn't happen in practice. + if (localError) { + secnotice("ds", "kSOSMergeFailure => kSOSMergePeersObject, %@", localError); + CFReleaseSafe(localError); + } + } + + if (localError && !SecErrorIsSqliteDuplicateItemError(localError)) { + secnotice("ds", "dsMergeObject failed: mr=%ld, %@", mr, localError); + // We should probably always propogate this, but for now we are only logging + // See rdar://problem/26451072 for case where we might need to propogate + if (mr == kSOSMergeFailure) { + CFErrorPropagate(localError, error); + localError = NULL; + } + } + + CFReleaseSafe(mergedItem); + CFReleaseSafe(replacedItem); + CFReleaseSafe(localError); + return mr; +} + + /* + Truthy backup format is a dictionary from sha1 => item. + Each item has class, hash and item data. + + TODO: sha1 is included as binary blob to avoid parsing key. + */ +enum { + kSecBackupIndexHash = 0, + kSecBackupIndexClass, + kSecBackupIndexData, +}; + +static const void *kSecBackupKeys[] = { + [kSecBackupIndexHash] = kSecItemBackupHashKey, + [kSecBackupIndexClass] = kSecItemBackupClassKey, + [kSecBackupIndexData] = kSecItemBackupDataKey +}; + +static CFDictionaryRef objectCopyBackup(SOSObjectRef object, uint64_t handle, CFErrorRef *error) { + const void *values[array_size(kSecBackupKeys)]; + SecDbItemRef item = (SecDbItemRef)object; + CFDictionaryRef backup_item = NULL; + + if ((values[kSecBackupIndexHash] = SecDbItemGetSHA1(item, error))) { + if ((values[kSecBackupIndexData] = SecDbItemCopyEncryptedDataToBackup(item, handle, error))) { + values[kSecBackupIndexClass] = SecDbItemGetClass(item)->name; + backup_item = CFDictionaryCreate(kCFAllocatorDefault, kSecBackupKeys, values, array_size(kSecBackupKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFRelease(values[kSecBackupIndexData]); + } + } + + return backup_item; +} + +static CFDataRef dsCopyStateWithKey(SOSDataSourceRef data_source, CFStringRef key, CFStringRef pdmn, SOSTransactionRef txn, CFErrorRef *error) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrAccessGroup, kSOSInternalAccessGroup, + kSecAttrAccount, key, + kSecAttrService, dataSourceID, + kSecAttrAccessible, pdmn, + kSecAttrSynchronizable, kCFBooleanFalse, + NULL); + CFReleaseSafe(dataSourceID); + __block CFDataRef data = NULL; + SecDbQueryRef query = query_create(genp_class(), NULL, dict, error); + if (query) { + if (query->q_item) CFReleaseSafe(query->q_item); + query->q_item = dict; + bool (^read_it)(SecDbConnectionRef dbconn) = ^(SecDbConnectionRef dbconn) { + return SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { + return CFDictionaryContainsKey(dict, attr->name); + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + secnotice("ds", "found item for key %@@%@", key, pdmn); + data = CFRetainSafe(SecDbItemGetValue(item, &v6v_Data, error)); + }); + }; + if (txn) { + read_it((SecDbConnectionRef) txn); + } else { + kc_with_custom_db(false, true, ds->db, error, read_it); + } + query_destroy(query, error); + } else { + CFReleaseSafe(dict); + } + if (!data) secnotice("ds", "failed to load %@@%@ state: %@", key, pdmn, error ? *error : NULL); + return data; +} + +static CFDataRef dsCopyItemDataWithKeys(SOSDataSourceRef data_source, CFDictionaryRef keys, CFErrorRef *error) { + /* + Values for V0 are: + kSecAttrAccessGroup ==> CFSTR("com.apple.sbd") + kSecAttrAccessible ==> kSecAttrAccessibleWhenUnlocked + kSecAttrAccount ==> CFSTR("SecureBackupPublicKeybag") + kSecAttrService ==> CFSTR("SecureBackupService") + + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrAccessGroup, CFSTR("com.apple.sbd"), + kSecAttrAccount, account, + kSecAttrService, service, + kSecAttrAccessible, pdmn, + kSecAttrSynchronizable, kCFBooleanTrue, + NULL); + */ + + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, keys); + __block CFDataRef data = NULL; + SecDbQueryRef query = query_create(genp_class(), NULL, dict, error); + if (query) { + if (query->q_item) CFReleaseSafe(query->q_item); + query->q_item = dict; + kc_with_custom_db(false, true, ds->db, error, ^bool(SecDbConnectionRef dbconn) { + return SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) { + return CFDictionaryContainsKey(dict, attr->name); + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + secnotice("ds", "found item for keys %@", keys); + data = CFRetainSafe(SecDbItemGetValue(item, &v6v_Data, error)); + }); + }); + query_destroy(query, error); + } else { + CFReleaseSafe(dict); + } + if (!data) secnotice("ds", "failed to load item %@: %@", keys, error ? *error : NULL); + return data; +} + +static bool dsSetStateWithKey(SOSDataSourceRef data_source, SOSTransactionRef txn, CFStringRef key, CFStringRef pdmn, CFDataRef state, CFErrorRef *error) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrAccessGroup, kSOSInternalAccessGroup, + kSecAttrAccount, key, + kSecAttrService, dataSourceID, + kSecAttrAccessible, pdmn, + kSecAttrSynchronizable, kCFBooleanFalse, + kSecValueData, state, + NULL); + CFReleaseSafe(dataSourceID); + SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); + SOSMergeResult mr = dsMergeObject(txn, (SOSObjectRef)item, NULL, error); + if (mr == kSOSMergeFailure) secerror("failed to save %@@%@ state: %@", key, pdmn, error ? *error : NULL); + CFReleaseSafe(item); + CFReleaseSafe(dict); + return mr != kSOSMergeFailure; +} + +static bool dsDeleteStateWithKey(SOSDataSourceRef data_source, CFStringRef key, CFStringRef pdmn, SOSTransactionRef txn, CFErrorRef *error) { + SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source; + CFStringRef dataSourceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SOSDataSource-%@"), ds->name); + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, + kSecAttrAccessGroup, kSOSInternalAccessGroup, + kSecAttrAccount, key, + kSecAttrService, dataSourceID, + kSecAttrAccessible, pdmn, + kSecAttrSynchronizable, kCFBooleanFalse, + NULL); + CFReleaseSafe(dataSourceID); + SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); + bool ok = SecDbItemDoDeleteSilently(item, (SecDbConnectionRef)txn, error); + CFReleaseNull(dict); + CFReleaseSafe(item); + return ok; +} + +static bool dsRestoreObject(SOSTransactionRef txn, uint64_t handle, CFDictionaryRef item, CFErrorRef *error) { + CFStringRef item_class = CFDictionaryGetValue(item, kSecItemBackupClassKey); + CFDataRef data = CFDictionaryGetValue(item, kSecItemBackupDataKey); + const SecDbClass *dbclass = NULL; + + if (!item_class || !data) + return SecError(errSecDecode, error, CFSTR("no class or data in object")); + + dbclass = kc_class_with_name(item_class); + if (!dbclass) + return SecError(errSecDecode, error, CFSTR("no such class %@; update kc_class_with_name "), item_class); + + SecDbItemRef dbitem = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, data, (keybag_handle_t)handle, error); + bool ok = dbitem && (dsMergeObject(txn, (SOSObjectRef)dbitem, NULL, error) != kSOSMergeFailure); + CFReleaseSafe(dbitem); + return ok; +} + +SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, CFStringRef name, CFErrorRef *error) { + SecItemDataSourceRef ds = calloc(1, sizeof(struct SecItemDataSource)); + ds->ds.dsGetName = dsGetName; + ds->ds.dsAddNotifyPhaseBlock = dsAddNotifyPhaseBlock; + ds->ds.dsCopyManifestWithViewNameSet = dsCopyManifestWithViewNameSet; + ds->ds.dsCopyStateWithKey = dsCopyStateWithKey; + ds->ds.dsCopyItemDataWithKeys = dsCopyItemDataWithKeys; + + ds->ds.dsForEachObject = dsForEachObject; + ds->ds.dsWith = dsWith; + ds->ds.dsReadWith = dsReadWith; + ds->ds.dsRelease = dsRelease; + + ds->ds.dsMergeObject = dsMergeObject; + ds->ds.dsSetStateWithKey = dsSetStateWithKey; + ds->ds.dsDeleteStateWithKey = dsDeleteStateWithKey; + ds->ds.dsRestoreObject = dsRestoreObject; + + // Object field accessors + ds->ds.objectCopyDigest = copyObjectDigest; + ds->ds.objectCopyModDate = copyObjectModDate; + + // Object encode and decode. + ds->ds.objectCreateWithPropertyList = objectCreateWithPropertyList; + ds->ds.objectCopyPropertyList = objectCopyPropertyList; + ds->ds.objectCopyBackup = objectCopyBackup; + + ds->db = CFRetainSafe(db); + ds->name = CFRetainSafe(name); + + // Do this after the ds is fully setup so the engine can query us right away. + ds->ds.engine = SOSEngineCreate(&ds->ds, error); + if (!ds->ds.engine) { + free(ds); + ds = NULL; + } + return &ds->ds; +} + +static CFStringRef SecItemDataSourceFactoryCopyName(SOSDataSourceFactoryRef factory) +{ + // This is the name of the v0 datasource, a.k.a. "ak" + return kSecAttrAccessibleWhenUnlocked; +} + +struct SecItemDataSourceFactory { + struct SOSDataSourceFactory factory; + CFMutableDictionaryRef dsCache; + dispatch_queue_t queue; + SecDbRef db; +}; + +static SOSDataSourceRef SecItemDataSourceFactoryCopyDataSource(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, CFErrorRef *error) +{ + struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory; + __block SOSDataSourceRef dataSource = NULL; + dispatch_sync(f->queue, ^{ + dataSource = (SOSDataSourceRef)CFDictionaryGetValue(f->dsCache, dataSourceName); + if (!dataSource && f->db) { + dataSource = (SOSDataSourceRef)SecItemDataSourceCreate(f->db, dataSourceName, error); + CFDictionarySetValue(f->dsCache, dataSourceName, dataSource); + } + }); + return dataSource; +} + +static void SecItemDataSourceFactoryDispose(SOSDataSourceFactoryRef factory) +{ + // Nothing to do here. +} + +// Fire up the SOSEngines so they can +static bool SOSDataSourceFactoryStartYourEngines(SOSDataSourceFactoryRef factory) { +#if OCTAGON + if(!SecCKKSTestDisableSOS() && !SecCKKSTestsEnabled()) { +#endif // OCTAGON + bool ok = true; + CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); + CFErrorRef localError = NULL; + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(factory, dsName, &localError); + if (!ds) + secerror("create_datasource %@ failed %@", dsName, localError); + CFReleaseNull(localError); + SOSDataSourceRelease(ds, &localError); + CFReleaseNull(localError); + CFReleaseNull(dsName); + return ok; +#if OCTAGON + } else { + return false; + } +#endif // OCTAGON +} + +static SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) { + struct SecItemDataSourceFactory *dsf = calloc(1, sizeof(struct SecItemDataSourceFactory)); + dsf->factory.copy_name = SecItemDataSourceFactoryCopyName; + dsf->factory.create_datasource = SecItemDataSourceFactoryCopyDataSource; + dsf->factory.release = SecItemDataSourceFactoryDispose; + + dsf->dsCache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); + dsf->queue = dispatch_queue_create("dsf queue", DISPATCH_QUEUE_SERIAL); + dsf->db = CFRetainSafe(db); + if (!SOSDataSourceFactoryStartYourEngines(&dsf->factory)) + secerror("Failed to start engines, gonna lose the race."); + return &dsf->factory; +} + +SOSDataSourceFactoryRef SecItemDataSourceFactoryGetShared(SecDbRef db) { + static dispatch_once_t sDSFQueueOnce; + static dispatch_queue_t sDSFQueue; + static CFMutableDictionaryRef sDSTable = NULL; + + dispatch_once(&sDSFQueueOnce, ^{ + sDSFQueue = dispatch_queue_create("dataSourceFactory queue", DISPATCH_QUEUE_SERIAL); + sDSTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); + }); + + __block SOSDataSourceFactoryRef result = NULL; + dispatch_sync(sDSFQueue, ^{ + if(db) { + CFStringRef dbPath = SecDbGetPath(db); + if(dbPath) { + result = (SOSDataSourceFactoryRef) CFDictionaryGetValue(sDSTable, dbPath); + + if(!result) { + result = SecItemDataSourceFactoryCreate(db); + CFDictionaryAddValue(sDSTable, dbPath, result); + } + } + } + }); + + return result; +} + +// TODO: These should move to SecItemServer.c + +void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object) { + SOSObjectRef item = objectCreateWithPropertyList(object, NULL); + if (item) { + CFStringRef itemDesc = CFCopyDescription(item); + if (itemDesc) { + CFStringAppend(desc, itemDesc); + CFReleaseSafe(itemDesc); + } + CFRelease(item); + } +} + +SOSManifestRef SOSCreateManifestWithBackup(CFDictionaryRef backup, CFErrorRef *error) +{ + __block struct SOSDigestVector dv = SOSDigestVectorInit; + if (backup) { + CFDictionaryForEach(backup, ^void (const void * key, const void * value) { + if (isDictionary(value)) { + /* converting key back to binary blob is horrible */ + CFDataRef sha1 = CFDictionaryGetValue(value, kSecItemBackupHashKey); + if (isData(sha1) && CFDataGetLength(sha1) == CCSHA1_OUTPUT_SIZE) + SOSDigestVectorAppend(&dv, CFDataGetBytePtr(sha1)); + } + }); + } + SOSManifestRef manifest = SOSManifestCreateWithDigestVector(&dv, error); + SOSDigestVectorFree(&dv); + return manifest; +} diff --git a/keychain/securityd/SecItemDataSource.h b/keychain/securityd/SecItemDataSource.h new file mode 100644 index 00000000..fab2678e --- /dev/null +++ b/keychain/securityd/SecItemDataSource.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemDataSource.h + The functions provided in SecDbItem provide an implementation of a + SOSDataSource required by the Secure Object Syncing code. + */ + +#ifndef _SECURITYD_SECITEMDATASOURCE_H_ +#define _SECURITYD_SECITEMDATASOURCE_H_ + +#include "keychain/SecureObjectSync/SOSDataSource.h" +#include + +__BEGIN_DECLS + +SOSDataSourceFactoryRef SecItemDataSourceFactoryGetShared(SecDbRef db); + +SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, CFStringRef name, CFErrorRef *error); + +SOSManifestRef SOSCreateManifestWithBackup(CFDictionaryRef backup, CFErrorRef *error); + +// Hack to log objects from inside SOS code +void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object); + + +__END_DECLS + +#endif /* _SECURITYD_SECITEMDATASOURCE_H_ */ diff --git a/keychain/securityd/SecItemDb.c b/keychain/securityd/SecItemDb.c new file mode 100644 index 00000000..c5258625 --- /dev/null +++ b/keychain/securityd/SecItemDb.c @@ -0,0 +1,2220 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecItemDb.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#if TARGET_DARWINOS +#undef OCTAGON +#undef SECUREOBJECTSYNC +#undef SHAREDWEBCREDENTIALS +#endif + +#include "keychain/securityd/SecItemDb.h" +#include + +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include +#include +#include +#include +#include +#include +#include "keychain/securityd/SOSCloudCircleServer.h" +#include +#include +#include +#include + +#include "utilities/SecABC.h" +#include "utilities/sec_action.h" + +#include "keychain/ckks/CKKS.h" + +#define kSecBackupKeybagUUIDKey CFSTR("keybag-uuid") + +const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, + CFTypeRef key, + CFErrorRef *error) { + /* Special case: identites can have all attributes of either cert + or keys. */ + if (c == identity_class()) { + const SecDbAttr *desc; + if (!(desc = SecDbAttrWithKey(cert_class(), key, 0))) + desc = SecDbAttrWithKey(keys_class(), key, error); + return desc; + } + + if (isString(key)) { + SecDbForEachAttr(c, a) { + if (CFEqual(a->name, key)) + return a; + } + if (CFEqual(kSecUseDataProtectionKeychain, key)) { + return NULL; /* results in no ops for this attribute */ + } + } + + SecError(errSecNoSuchAttr, error, CFSTR("attribute %@ not found in class %@"), key, c->name); + + return NULL; +} + +bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)(void)) { + return kc_transaction_type(dbt, kSecDbExclusiveTransactionType, error, perform); +} + +bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)(void)) { + __block bool ok = true; + return ok && SecDbTransaction(dbt, type, error, ^(bool *commit) { + ok = *commit = perform(); + }); +} + +static CFStringRef SecDbGetKindSQL(SecDbAttrKind kind) { + switch (kind) { + case kSecDbBlobAttr: + case kSecDbDataAttr: + case kSecDbUUIDAttr: + case kSecDbSHA1Attr: + case kSecDbPrimaryKeyAttr: + case kSecDbEncryptedDataAttr: + return CFSTR("BLOB"); + case kSecDbAccessAttr: + case kSecDbStringAttr: + return CFSTR("TEXT"); + case kSecDbNumberAttr: + case kSecDbSyncAttr: + case kSecDbTombAttr: + return CFSTR("INTEGER"); + case kSecDbDateAttr: + case kSecDbCreationDateAttr: + case kSecDbModificationDateAttr: + return CFSTR("REAL"); + case kSecDbRowIdAttr: + return CFSTR("INTEGER PRIMARY KEY AUTOINCREMENT"); + case kSecDbAccessControlAttr: + case kSecDbUTombAttr: + /* This attribute does not exist in the DB. */ + return NULL; + } +} + +static void SecDbAppendUnique(CFMutableStringRef sql, CFStringRef value, bool *haveUnique) { + assert(haveUnique); + if (!*haveUnique) + CFStringAppend(sql, CFSTR("UNIQUE(")); + + SecDbAppendElement(sql, value, haveUnique); +} + +static void SecDbAppendCreateTableWithClass(CFMutableStringRef sql, const SecDbClass *c) { + CFStringAppendFormat(sql, 0, CFSTR("CREATE TABLE %@("), c->name); + SecDbForEachAttrWithMask(c,desc,kSecDbInFlag) { + CFStringAppendFormat(sql, 0, CFSTR("%@ %@"), desc->name, SecDbGetKindSQL(desc->kind)); + if (desc->flags & kSecDbNotNullFlag) + CFStringAppend(sql, CFSTR(" NOT NULL")); + if (desc->flags & kSecDbDefault0Flag) + CFStringAppend(sql, CFSTR(" DEFAULT 0")); + if (desc->flags & kSecDbDefaultEmptyFlag) + CFStringAppend(sql, CFSTR(" DEFAULT ''")); + CFStringAppend(sql, CFSTR(",")); + } + + bool haveUnique = false; + SecDbForEachAttrWithMask(c,desc,kSecDbPrimaryKeyFlag | kSecDbInFlag) { + SecDbAppendUnique(sql, desc->name, &haveUnique); + } + if (haveUnique) + CFStringAppend(sql, CFSTR(")")); + + CFStringAppend(sql, CFSTR(");")); + + // Create indices + SecDbForEachAttrWithMask(c,desc, kSecDbIndexFlag | kSecDbInFlag) { + if (desc->kind == kSecDbSyncAttr) { + CFStringAppendFormat(sql, 0, CFSTR("CREATE INDEX %@%@0 ON %@(%@) WHERE %@=0;"), c->name, desc->name, c->name, desc->name, desc->name); + } else { + CFStringAppendFormat(sql, 0, CFSTR("CREATE INDEX %@%@ ON %@(%@);"), c->name, desc->name, c->name, desc->name); + } + } +} + +static void SecDbAppendDropTableWithClass(CFMutableStringRef sql, const SecDbClass *c) { + CFStringAppendFormat(sql, 0, CFSTR("DROP TABLE %@;"), c->name); +} + +static CFDataRef SecPersistentRefCreateWithItem(SecDbItemRef item, CFErrorRef *error) { + sqlite3_int64 row_id = SecDbItemGetRowId(item, error); + if (row_id) + return _SecItemCreatePersistentRef(SecDbItemGetClass(item)->name, row_id, item->attributes); + return NULL; +} + +bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error) +{ + __block bool ok = true; + CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); + + if (classIndexesForNewTables) { + CFArrayForEach(classIndexesForNewTables, ^(const void* index) { + const SecDbClass* class = schema->classes[(int)index]; + SecDbAppendCreateTableWithClass(sql, class); + }); + } + else { + for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { + SecDbAppendCreateTableWithClass(sql, *pclass); + } + } + + if (includeVersion) { + CFStringAppendFormat(sql, NULL, CFSTR("INSERT INTO tversion(version,minor) VALUES(%d, %d);"), + schema->majorVersion, schema->minorVersion); + } + CFStringPerformWithCString(sql, ^(const char *sql_string) { + ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL), + SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string); + }); + CFReleaseSafe(sql); + return ok; +} + +bool SecItemDbDeleteSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFErrorRef *error) +{ + __block bool ok = true; + CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); + for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { + SecDbAppendDropTableWithClass(sql, *pclass); + } + CFStringPerformWithCString(sql, ^(const char *sql_string) { + ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL), + SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string); + }); + CFReleaseSafe(sql); + return ok; +} + +CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error) { + CFTypeRef a_result; + + if (return_type == 0) { + /* Caller isn't interested in any results at all. */ + a_result = kCFNull; + } else if (return_type == kSecReturnDataMask) { + a_result = SecDbItemGetCachedValueWithName(item, kSecValueData); + if (a_result) { + CFRetainSafe(a_result); + } else { + a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0); + } + } else if (return_type == kSecReturnPersistentRefMask) { + a_result = SecPersistentRefCreateWithItem(item, error); + } else { + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(item)); + /* We need to return more than one value. */ + if (return_type & kSecReturnRefMask) { + CFDictionarySetValue(dict, kSecClass, SecDbItemGetClass(item)->name); + } + CFOptionFlags mask = (((return_type & kSecReturnDataMask || return_type & kSecReturnRefMask) ? kSecDbReturnDataFlag : 0) | + ((return_type & kSecReturnAttributesMask || return_type & kSecReturnRefMask) ? kSecDbReturnAttrFlag : 0)); + SecDbForEachAttr(SecDbItemGetClass(item), desc) { + if ((desc->flags & mask) != 0) { + CFTypeRef value = SecDbItemGetValue(item, desc, error); + if (value && !CFEqual(kCFNull, value)) { + CFDictionarySetValue(dict, desc->name, value); + } else if (value == NULL) { + CFReleaseNull(dict); + break; + } + } + } + CFDictionaryRemoveValue(dict, kSecAttrUUID); + + if (return_type & kSecReturnPersistentRefMask) { + CFDataRef pref = SecPersistentRefCreateWithItem(item, error); + CFDictionarySetValue(dict, kSecValuePersistentRef, pref); + CFReleaseSafe(pref); + } + + a_result = dict; + } + + return a_result; +} + +/* AUDIT[securityd](done): + attributes (ok) is a caller provided dictionary, only its cf type has + been checked. + */ +bool +s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error) +{ + if (query_match_count(q) != 0) + return errSecItemMatchUnsupported; + + /* Add requires a class to be specified unless we are adding a ref. */ + if (q->q_use_item_list) + return errSecUseItemListUnsupported; + + /* Actual work here. */ + SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, q->q_class, q->q_item, KEYBAG_DEVICE, error); + if (!item) + return false; + if (SecDbItemIsTombstone(item)) + SecDbItemSetValue(item, &v7utomb, q->q_use_tomb ? q->q_use_tomb : kCFBooleanTrue, NULL); + + bool ok = true; + if (q->q_data) + ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), q->q_data, error); + if (q->q_row_id) + ok = SecDbItemSetRowId(item, q->q_row_id, error); + if (q->q_musrView) + ok = SecDbItemSetValueWithName(item, CFSTR("musr"), q->q_musrView, error); + SecDbItemSetCredHandle(item, q->q_use_cred_handle); + +#if OCTAGON + if(SecCKKSIsEnabled() && !SecCKKSTestDisableAutomaticUUID()) { + s3dl_item_make_new_uuid(item, q->q_uuid_from_primary_key, error); + + if(q->q_add_sync_callback) { + CFTypeRef uuid = SecDbItemGetValue(item, &v10itemuuid, error); + if(uuid) { + CKKSRegisterSyncStatusCallback(uuid, q->q_add_sync_callback); + } else { + secerror("Couldn't fetch UUID from item; can't call callback"); + } + } + } +#endif + + if (ok) + ok = SecDbItemInsert(item, dbt, error); + + if (ok) { + if (result && q->q_return_type) { + *result = SecDbItemCopyResult(item, q->q_return_type, error); + } + } + if (!ok && error && *error) { + if (CFEqual(CFErrorGetDomain(*error), kSecDbErrorDomain) && CFErrorGetCode(*error) == SQLITE_CONSTRAINT) { + CFReleaseNull(*error); + SecError(errSecDuplicateItem, error, CFSTR("duplicate item %@"), item); + } else if (CFEqual(CFErrorGetDomain(*error), kSecErrorDomain) && CFErrorGetCode(*error) == errSecDecode) { //handle situation when item have pdmn=akpu but passcode is not set + CFTypeRef value = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error); + if (value && CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { + CFReleaseNull(*error); + SecError(errSecAuthFailed, error, CFSTR("authentication failed")); + } + } + } + + if (ok) { + q->q_changed = true; + if (SecDbItemIsSyncable(item)) + q->q_sync_changed = true; + } + + secdebug("dbitem", "inserting item %@%s%@", item, ok ? "" : "failed: ", ok || error == NULL ? (CFErrorRef)CFSTR("") : *error); + + CFRelease(item); + + return ok; +} + +bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error) { + if(!item) { + return false; + } + + // Set the item UUID. + CFUUIDRef uuid = NULL; + // Were we asked to make the UUID static? + if (uuid_from_primary_key) { + // This UUID isn't used in any security mechanism, so we can + // just use the first bits of the SHA256 hash. + CFDataRef pkhash = SecDbKeychainItemCopySHA256PrimaryKey(item, error); + if(CFDataGetLength(pkhash) >= 16) { + UInt8 uuidBytes[16]; + CFRange range = CFRangeMake(0, 16); + CFDataGetBytes(pkhash, range, uuidBytes); + + uuid = CFUUIDCreateWithBytes(NULL, + uuidBytes[ 0], + uuidBytes[ 1], + uuidBytes[ 2], + uuidBytes[ 3], + uuidBytes[ 4], + uuidBytes[ 5], + uuidBytes[ 6], + uuidBytes[ 7], + uuidBytes[ 8], + uuidBytes[ 9], + uuidBytes[10], + uuidBytes[11], + uuidBytes[12], + uuidBytes[13], + uuidBytes[14], + uuidBytes[15]); + } + CFReleaseNull(pkhash); + } + if(uuid == NULL) { + uuid = CFUUIDCreate(NULL); + } + SecDbItemSetValueWithName(item, kSecAttrUUID, uuid, error); + CFReleaseNull(uuid); + return true; +} + +typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context); + +static CFDataRef +s3dl_copy_data_from_col(sqlite3_stmt *stmt, int col, CFErrorRef *error) { + return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col), + sqlite3_column_bytes(stmt, col), + kCFAllocatorNull); +} + +static bool +s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col, CFArrayRef accessGroups, + CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error) { + CFDataRef edata = NULL; + bool ok = false; + require(edata = s3dl_copy_data_from_col(stmt, col, error), out); + ok = s3dl_item_from_data(edata, q, accessGroups, item, access_control, keyclass, error); + +out: + CFReleaseSafe(edata); + return ok; +} + +struct s3dl_query_ctx { + Query *q; + CFArrayRef accessGroups; + SecDbConnectionRef dbt; + CFTypeRef result; + int found; +}; + +/* Return whatever the caller requested based on the value of q->q_return_type. + keys and values must be 3 larger than attr_count in size to accomadate the + optional data, class and persistent ref results. This is so we can use + the CFDictionaryCreate() api here rather than appending to a + mutable dictionary. */ +static CF_RETURNS_RETAINED CFTypeRef +handle_result(Query *q, + CFMutableDictionaryRef item, + sqlite_int64 rowid) +{ + CFTypeRef a_result; + CFDataRef data; + data = CFDictionaryGetValue(item, kSecValueData); + CFDataRef pref = NULL; + if (q->q_return_type & kSecReturnPersistentRefMask) { + pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); + } + if (q->q_return_type == 0) { + /* Caller isn't interested in any results at all. */ + a_result = kCFNull; + } else if (q->q_return_type == kSecReturnDataMask) { + if (data) { + a_result = data; + CFRetain(a_result); + } else { + a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0); + } + } else if (q->q_return_type == kSecReturnPersistentRefMask) { + a_result = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); + } else { + /* We need to return more than one value. */ + if (q->q_return_type & kSecReturnRefMask) { + CFDictionarySetValue(item, kSecClass, q->q_class->name); + } else if ((q->q_return_type & kSecReturnAttributesMask)) { + if (!(q->q_return_type & kSecReturnDataMask)) { + CFDictionaryRemoveValue(item, kSecValueData); + } + + // Add any attributes which are supposed to be returned, are not present in the decrypted blob, + // and have a way to generate themselves. + SecDbItemRef itemRef = NULL; + SecDbForEachAttrWithMask(q->q_class, attr, kSecDbReturnAttrFlag) { + if(!CFDictionaryGetValue(item, attr->name) && attr->copyValue) { + CFErrorRef cferror = NULL; + if(!itemRef) { + itemRef = SecDbItemCreateWithAttributes(NULL, q->q_class, item, KEYBAG_DEVICE, &cferror); + } + if(!cferror && itemRef) { + if (attr->kind != kSecDbSHA1Attr || (q->q_return_type & kSecReturnDataMask)) { // we'll skip returning the sha1 attribute unless the client has also asked us to return data, because without data our sha1 could be invalid + CFTypeRef attrValue = attr->copyValue(itemRef, attr, &cferror); + if (!cferror && attrValue) { + CFDictionarySetValue(item, attr->name, attrValue); + } + CFReleaseNull(attrValue); + } + } + CFReleaseNull(cferror); + } + } + CFReleaseNull(itemRef); + + CFDictionaryRemoveValue(item, kSecAttrUUID); + } else { + CFRetainSafe(data); + CFDictionaryRemoveAllValues(item); + if ((q->q_return_type & kSecReturnDataMask) && data) { + CFDictionarySetValue(item, kSecValueData, data); + } + CFReleaseSafe(data); + } + if (q->q_return_type & kSecReturnPersistentRefMask && pref != NULL) { + CFDictionarySetValue(item, kSecValuePersistentRef, pref); + } + + a_result = item; + CFRetain(item); + } + CFReleaseSafe(pref); + return a_result; +} + +static void s3dl_merge_into_dict(const void *key, const void *value, void *context) { + CFDictionarySetValue(context, key, value); +} + +static bool checkTokenObjectID(CFDataRef token_object_id, CFDataRef value_data) { + bool equalOID = false; + require_quiet(value_data, out); + CFDictionaryRef itemValue = SecTokenItemValueCopy(value_data, NULL); + require_quiet(itemValue, out); + CFDataRef oID = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey); + equalOID = CFEqualSafe(token_object_id, oID); + CFRelease(itemValue); +out: + return equalOID; +} + +static void s3dl_query_row(sqlite3_stmt *stmt, void *context) { + struct s3dl_query_ctx *c = context; + Query *q = c->q; + ReturnTypeMask saved_mask = q->q_return_type; + + sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); + CFMutableDictionaryRef item = NULL; + bool ok; + +decode: + ok = s3dl_item_from_col(stmt, q, 1, c->accessGroups, &item, NULL, NULL, &q->q_error); + if (!ok) { + OSStatus status = SecErrorGetOSStatus(q->q_error); + // errSecDecode means the item is corrupted, stash it for delete. + if (status == errSecDecode) { + secwarning("ignoring corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, rowid, q->q_error); + { + CFStringRef tablename = CFStringCreateCopy(kCFAllocatorDefault, q->q_class->name); + // Can't get rid of this item on the read path. Let's come back from elsewhere. + dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + __block CFErrorRef localErr = NULL; + __block bool ok = true; + ok &= kc_with_dbt(true, &localErr, ^bool(SecDbConnectionRef dbt) { + CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DELETE FROM %@ WHERE rowid=%lli"), tablename, rowid); + ok &= SecDbPrepare(dbt, sql, &localErr, ^(sqlite3_stmt *stmt) { + ok &= SecDbStep(dbt, stmt, &localErr, NULL); + }); + + if (!ok || localErr) { + secerror("Failed to delete corrupt item, %@ row %lli: %@", tablename, rowid, localErr); + } else { + secnotice("item", "Deleted corrupt rowid %lli from table %@", rowid, tablename); + } + CFReleaseNull(localErr); + CFReleaseNull(sql); + CFReleaseSafe(tablename); + return ok; + }); + }); + + CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL); + CFMutableStringRef edatastring = CFStringCreateMutable(kCFAllocatorDefault, 0); + if(edatastring) { + CFStringAppendEncryptedData(edatastring, edata); + secnotice("item", "corrupted edata=%@", edatastring); + } + CFReleaseSafe(edata); + CFReleaseSafe(edatastring); + } + CFReleaseNull(q->q_error); // This item was never here, keep going + } else if (status == errSecAuthNeeded) { + secwarning("Authentication is needed for %@,rowid=%" PRId64 " (%" PRIdOSStatus "): %@", q->q_class->name, rowid, status, q->q_error); + } else if (status == errSecInteractionNotAllowed) { + static dispatch_once_t kclockedtoken; + static sec_action_t kclockedaction; + dispatch_once(&kclockedtoken, ^{ + kclockedaction = sec_action_create("ratelimiterdisabledlogevent", 1); + sec_action_set_handler(kclockedaction, ^{ + secerror("decode item failed, keychain is locked (%d)", (int)errSecInteractionNotAllowed); + }); + }); + sec_action_perform(kclockedaction); + } else if (status == errSecMissingEntitlement) { + // That's fine, let's pretend the item never existed for this query. + // We may find other, better items for the caller! + CFReleaseNull(q->q_error); + } else { + secerror("decode %@,rowid=%" PRId64 " failed (%" PRIdOSStatus "): %@", q->q_class->name, rowid, status, q->q_error); + } + // q->q_error will be released appropriately by a call to query_error + return; + } + + if (!item) + goto out; + + if (CFDictionaryContainsKey(item, kSecAttrTokenID) && (q->q_return_type & kSecReturnDataMask) == 0) { + // For token-based items, to get really meaningful set of attributes we must provide also data field, so augment mask + // and restart item decoding cycle. + q->q_return_type |= kSecReturnDataMask; + CFReleaseNull(item); + goto decode; + } + + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, CFDictionaryGetValue(item, kSecValueData))) + goto out; + + if (q->q_class == identity_class()) { + // TODO: Use col 2 for key rowid and use both rowids in persistent ref. + + CFMutableDictionaryRef key; + /* TODO : if there is a errSecDecode error here, we should cleanup */ + if (!s3dl_item_from_col(stmt, q, 3, c->accessGroups, &key, NULL, NULL, &q->q_error) || !key) + goto out; + + CFDataRef certData = CFDictionaryGetValue(item, kSecValueData); + if (certData) { + CFDictionarySetValue(key, kSecAttrIdentityCertificateData, certData); + CFDictionaryRemoveValue(item, kSecValueData); + } + + CFDataRef certTokenID = CFDictionaryGetValue(item, kSecAttrTokenID); + if (certTokenID) { + CFDictionarySetValue(key, kSecAttrIdentityCertificateTokenID, certTokenID); + CFDictionaryRemoveValue(item, kSecAttrTokenID); + } + CFDictionaryApplyFunction(item, s3dl_merge_into_dict, key); + CFRelease(item); + item = key; + } + + if (!match_item(c->dbt, q, c->accessGroups, item)) + goto out; + + CFTypeRef a_result = handle_result(q, item, rowid); + if (a_result) { + if (a_result == kCFNull) { + /* Caller wasn't interested in a result, but we still + count this row as found. */ + CFRelease(a_result); // Help shut up clang + } else if (q->q_limit == 1) { + c->result = a_result; + } else { + CFArrayAppendValue((CFMutableArrayRef)c->result, a_result); + CFRelease(a_result); + } + c->found++; + } + +out: + q->q_return_type = saved_mask; + CFReleaseSafe(item); +} + +static void +SecDbAppendWhereROWID(CFMutableStringRef sql, + CFStringRef col, sqlite_int64 row_id, + bool *needWhere) { + if (row_id > 0) { + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppendFormat(sql, NULL, CFSTR("%@=%lld"), col, row_id); + } +} + +static void +SecDbAppendWhereAttrs(CFMutableStringRef sql, const Query *q, bool *needWhere) { + CFIndex ix, attr_count = query_attr_count(q); + for (ix = 0; ix < attr_count; ++ix) { + SecDbAppendWhereOrAndEquals(sql, query_attr_at(q, ix).key, needWhere); + } +} + +static void +SecDbAppendWhereAccessGroups(CFMutableStringRef sql, + CFStringRef col, + CFArrayRef accessGroups, + bool *needWhere) { + CFIndex ix, ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + return; + } + + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppend(sql, col); + CFStringAppend(sql, CFSTR(" IN (?")); + for (ix = 1; ix < ag_count; ++ix) { + CFStringAppend(sql, CFSTR(",?")); + } + CFStringAppend(sql, CFSTR(")")); +} + +static bool +isQueryOverAllMUSRViews(CFTypeRef musrView) +{ + return SecMUSRIsViewAllViews(musrView); +} + +static bool +isQueryOverSingleUserView(CFTypeRef musrView) +{ + return isNull(musrView); +} + +#if TARGET_OS_IPHONE +static bool +isQueryOverBothUserAndSystem(CFTypeRef musrView, uid_t *uid) +{ + return SecMUSRGetBothUserAndSystemUUID(musrView, uid); +} +#endif + +static void +SecDbAppendWhereMusr(CFMutableStringRef sql, + const Query *q, + bool *needWhere) +{ + SecDbAppendWhereOrAnd(sql, needWhere); + +#if TARGET_OS_IPHONE + if (isQueryOverBothUserAndSystem(q->q_musrView, NULL)) { + CFStringAppend(sql, CFSTR("(musr = ? OR musr = ?)")); + } else +#endif + if (isQueryOverAllMUSRViews(q->q_musrView)) { + /* query over all items, regardless of view */ + } else if (isQueryOverSingleUserView(q->q_musrView)) { + CFStringAppend(sql, CFSTR("musr = ?")); + } else { + CFStringAppend(sql, CFSTR("musr = ?")); + } +} + +static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q, + CFArrayRef accessGroups) { + bool needWhere = true; + SecDbAppendWhereROWID(sql, CFSTR("ROWID"), q->q_row_id, &needWhere); + SecDbAppendWhereAttrs(sql, q, &needWhere); + SecDbAppendWhereMusr(sql, q, &needWhere); + SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere); +} + +static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) { + if (limit != kSecMatchUnlimited) + CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %" PRIdCFIndex), limit); +} + +static CFStringRef s3dl_create_select_sql(Query *q, CFArrayRef accessGroups) { + CFMutableStringRef sql = CFStringCreateMutable(NULL, 0); + if (q->q_class == identity_class()) { + CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, %@" + ", rowid,data FROM " + "(SELECT cert.rowid AS crowid, cert.labl AS labl," + " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid," + " keys.*,cert.data AS %@" + " FROM keys, cert" + " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"), + kSecAttrIdentityCertificateData, kSecAttrIdentityCertificateData); + SecDbAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0); + /* The next 3 SecDbAppendWhere calls are in the same order as in + SecDbAppendWhereClause(). This makes sqlBindWhereClause() work, + as long as we do an extra sqlBindAccessGroups first. */ + SecDbAppendWhereROWID(sql, CFSTR("crowid"), q->q_row_id, 0); + CFStringAppend(sql, CFSTR(")")); + bool needWhere = true; + SecDbAppendWhereAttrs(sql, q, &needWhere); + SecDbAppendWhereMusr(sql, q, &needWhere); + SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere); + } else { + CFStringAppend(sql, CFSTR("SELECT rowid, data FROM ")); + CFStringAppend(sql, q->q_class->name); + SecDbAppendWhereClause(sql, q, accessGroups); + } + //do not append limit for all queries which needs filtering + if (q->q_match_issuer == NULL && q->q_match_policy == NULL && q->q_match_valid_on_date == NULL && q->q_match_trusted_only == NULL && q->q_token_object_id == NULL) { + SecDbAppendLimit(sql, q->q_limit); + } + + return sql; +} + +static bool sqlBindMusr(sqlite3_stmt *stmt, const Query *q, int *pParam, CFErrorRef *error) { + int param = *pParam; + bool result = true; +#if TARGET_OS_IPHONE + uid_t uid; + + if (isQueryOverBothUserAndSystem(q->q_musrView, &uid)) { + /* network extensions are special and get to query both user and system views */ + CFDataRef systemUUID = SecMUSRGetSystemKeychainUUID(); + result = SecDbBindObject(stmt, param++, systemUUID, error); + if (result) { + CFDataRef activeUser = SecMUSRCreateActiveUserUUID(uid); + result = SecDbBindObject(stmt, param++, activeUser, error); + CFReleaseNull(activeUser); + } + } else +#endif + if (isQueryOverAllMUSRViews(q->q_musrView)) { + /* query over all items, regardless of view */ + } else if (isQueryOverSingleUserView(q->q_musrView)) { + CFDataRef singleUUID = SecMUSRGetSingleUserKeychainUUID(); + result = SecDbBindObject(stmt, param++, singleUUID, error); + } else { + result = SecDbBindObject(stmt, param++, q->q_musrView, error); + } + + *pParam = param; + return result; +} + + +static bool sqlBindAccessGroups(sqlite3_stmt *stmt, CFArrayRef accessGroups, + int *pParam, CFErrorRef *error) { + bool result = true; + int param = *pParam; + CFIndex ix, count = accessGroups ? CFArrayGetCount(accessGroups) : 0; + for (ix = 0; ix < count; ++ix) { + result = SecDbBindObject(stmt, param++, + CFArrayGetValueAtIndex(accessGroups, ix), + error); + if (!result) + break; + } + *pParam = param; + return result; +} + +static bool sqlBindWhereClause(sqlite3_stmt *stmt, const Query *q, + CFArrayRef accessGroups, int *pParam, CFErrorRef *error) { + bool result = true; + int param = *pParam; + CFIndex ix, attr_count = query_attr_count(q); + for (ix = 0; ix < attr_count; ++ix) { + result = SecDbBindObject(stmt, param++, query_attr_at(q, ix).value, error); + if (!result) + break; + } + + if (result) { + result = sqlBindMusr(stmt, q, ¶m, error); + } + + /* Bind the access group to the sql. */ + if (result) { + result = sqlBindAccessGroups(stmt, accessGroups, ¶m, error); + } + + *pParam = param; + return result; +} + +bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error, + void (^handle_row)(SecDbItemRef item, bool *stop)) { + __block bool ok = true; + /* Sanity check the query. */ + if (query->q_ref) + return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries")); + + bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { + // The attributes here must match field list hardcoded in s3dl_select_sql used below, which is + // "rowid, data" + return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; + }; + + CFStringRef sql = s3dl_create_select_sql(query, accessGroups); + ok = sql; + if (sql) { + ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { + /* Bind the values being searched for to the SELECT statement. */ + int param = 1; + if (query->q_class == identity_class()) { + /* Bind the access groups to cert.agrp. */ + ok &= sqlBindAccessGroups(stmt, accessGroups, ¶m, error); + } + if (ok) + ok &= sqlBindWhereClause(stmt, query, accessGroups, ¶m, error); + if (ok) { + SecDbStep(dbconn, stmt, error, ^(bool *stop) { + SecDbItemRef itemFromStatement = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr); + if (itemFromStatement) { + CFTransferRetained(itemFromStatement->credHandle, query->q_use_cred_handle); + if (match_item(dbconn, query, accessGroups, itemFromStatement->attributes)) + handle_row(itemFromStatement, stop); + CFReleaseNull(itemFromStatement); + } else { + secerror("failed to create item from stmt: %@", error ? *error : (CFErrorRef)"no error"); + if (error) { + CFReleaseNull(*error); + } + //*stop = true; + //ok = false; + } + }); + } + }); + CFRelease(sql); + } + + return ok; +} + +static bool +s3dl_query(s3dl_handle_row handle_row, + void *context, CFErrorRef *error) +{ + struct s3dl_query_ctx *c = context; + SecDbConnectionRef dbt = c->dbt; + Query *q = c->q; + CFArrayRef accessGroups = c->accessGroups; + + /* Sanity check the query. */ + if (q->q_ref) + return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries")); + + /* Actual work here. */ + if (q->q_limit == 1) { + c->result = NULL; + } else { + c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFStringRef sql = s3dl_create_select_sql(q, accessGroups); + bool ok = SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) { + bool sql_ok = true; + /* Bind the values being searched for to the SELECT statement. */ + int param = 1; + if (q->q_class == identity_class()) { + /* Bind the access groups to cert.agrp. */ + sql_ok = sqlBindAccessGroups(stmt, accessGroups, ¶m, error); + } + if (sql_ok) + sql_ok = sqlBindWhereClause(stmt, q, accessGroups, ¶m, error); + if (sql_ok) { + SecDbForEach(dbt, stmt, error, ^bool (int row_index) { + handle_row(stmt, context); + + bool needs_auth = q->q_error && CFErrorGetCode(q->q_error) == errSecAuthNeeded; + if (q->q_skip_acl_items && needs_auth) + // Skip items needing authentication if we are told to do so. + CFReleaseNull(q->q_error); + + bool stop = q->q_limit != kSecMatchUnlimited && c->found >= q->q_limit; + stop = stop || (q->q_error && !needs_auth); + return !stop; + }); + } + return sql_ok; + }); + + CFRelease(sql); + + // First get the error from the query, since errSecDuplicateItem from an + // update query should superceed the errSecItemNotFound below. + if (!query_error(q, error)) + ok = false; + if (ok && c->found == 0) { + ok = SecError(errSecItemNotFound, error, CFSTR("no matching items found")); + if (q->q_spindump_on_failure) { + __security_stackshotreport(CFSTR("ItemNotFound"), __sec_exception_code_LostInMist); + } + } + + return ok; +} + +bool +s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, + CFArrayRef accessGroups, CFErrorRef *error) +{ + struct s3dl_query_ctx ctx = { + .q = q, .accessGroups = accessGroups, .dbt = dbt, + }; + if (q->q_row_id && query_attr_count(q)) + return SecError(errSecItemIllegalQuery, error, + CFSTR("attributes to query illegal; both row_id and other attributes can't be searched at the same time")); + if (q->q_token_object_id && query_attr_count(q) != 1) + return SecError(errSecItemIllegalQuery, error, + CFSTR("attributes to query illegal; both token persitent ref and other attributes can't be searched at the same time")); + + // Only copy things that aren't tombstones unless the client explicitly asks otherwise. + if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + bool ok = s3dl_query(s3dl_query_row, &ctx, error); + if (ok && result) + *result = ctx.result; + else + CFReleaseSafe(ctx.result); + + return ok; +} + +typedef void (^s3dl_item_digest_callback)(CFDataRef persistantReference, CFDataRef encryptedData); + +struct s3dl_digest_ctx { + Query *q; + SecDbConnectionRef dbt; + s3dl_item_digest_callback item_callback; +}; + +static void s3dl_query_row_digest(sqlite3_stmt *stmt, void *context) { + struct s3dl_query_ctx *c = context; + Query *q = c->q; + + sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); + CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL); + CFDataRef persistant_reference = _SecItemCreatePersistentRef(q->q_class->name, rowid, NULL); + CFDataRef digest = NULL; + + if (edata) { + digest = CFDataCopySHA256Digest(edata, NULL); + } + + if (digest && persistant_reference) { + CFDictionaryRef item = CFDictionaryCreateForCFTypes(NULL, + kSecValuePersistentRef, persistant_reference, + kSecValueData, digest, + NULL); + if (item) + CFArrayAppendValue((CFMutableArrayRef)c->result, item); + CFReleaseNull(item); + c->found++; + } else { + secinfo("item", "rowid %lu in %@ failed to create pref/digest", (unsigned long)rowid, q->q_class->name); + } + CFReleaseNull(digest); + CFReleaseNull(edata); + CFReleaseNull(persistant_reference); +} + + +bool +s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error) +{ + struct s3dl_query_ctx ctx = { + .q = q, .dbt = dbt, .accessGroups = accessGroups, + }; + // Force to always return an array + q->q_limit = kSecMatchUnlimited; + // This interface only queries live data + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + bool ok = s3dl_query(s3dl_query_row_digest, &ctx, error); + if (ok && result) + *result = (CFArrayRef)ctx.result; + else + CFReleaseSafe(ctx.result); + + return ok; +} + +/* First remove key from q->q_pairs if it's present, then add the attribute again. */ +static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) { + if (CFDictionaryContainsKey(q->q_item, desc->name)) { + CFIndex ix; + for (ix = 0; ix < q->q_attr_end; ++ix) { + if (CFEqual(desc->name, q->q_pairs[ix].key)) { + CFReleaseSafe(q->q_pairs[ix].value); + --q->q_attr_end; + for (; ix < q->q_attr_end; ++ix) { + q->q_pairs[ix] = q->q_pairs[ix + 1]; + } + CFDictionaryRemoveValue(q->q_item, desc->name); + break; + } + } + } + query_add_attribute_with_desc(desc, value, q); +} + +/* Update modification_date if needed. */ +static void query_pre_update(Query *q) { + SecDbForEachAttr(q->q_class, desc) { + if (desc->kind == kSecDbModificationDateAttr) { + CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); + query_set_attribute_with_desc(desc, now, q); + CFReleaseSafe(now); + } + } +} + +/* Make sure all attributes that are marked as not_null have a value. If + force_date is false, only set mdat and cdat if they aren't already set. */ +void query_pre_add(Query *q, bool force_date) { + CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); + SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInFlag) { + if (desc->kind == kSecDbCreationDateAttr || + desc->kind == kSecDbModificationDateAttr) { + if (force_date) { + query_set_attribute_with_desc(desc, now, q); + } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) { + query_add_attribute_with_desc(desc, now, q); + } + } else if ((desc->flags & kSecDbNotNullFlag) && + !CFDictionaryContainsKey(q->q_item, desc->name)) { + CFTypeRef value = NULL; + if (desc->flags & kSecDbDefault0Flag) { + if (desc->kind == kSecDbDateAttr) + value = CFDateCreate(kCFAllocatorDefault, 0.0); + else { + SInt32 vzero = 0; + value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero); + } + } else if (desc->flags & kSecDbDefaultEmptyFlag) { + if (desc->kind == kSecDbDataAttr || desc->kind == kSecDbUUIDAttr) + value = CFDataCreate(kCFAllocatorDefault, NULL, 0); + else { + value = CFSTR(""); + CFRetain(value); + } + } + if (value) { + /* Safe to use query_add_attribute here since the attr wasn't + set yet. */ + query_add_attribute_with_desc(desc, value, q); + CFRelease(value); + } + } + } + CFReleaseSafe(now); +} + +// Return a tri state value false->never make a tombstone, true->always make a +// tombstone, NULL->make a tombstone, but delete it if the tombstone itself is not currently being synced. +static CFBooleanRef s3dl_should_make_tombstone(Query *q, bool item_is_syncable, SecDbItemRef item) { + if (q->q_use_tomb) + return q->q_use_tomb; + else if (item_is_syncable && !SecDbItemIsTombstone(item)) + return NULL; + else + return kCFBooleanFalse; +} +/* AUDIT[securityd](done): + attributesToUpdate (ok) is a caller provided dictionary, + only its cf types have been checked. + */ +bool +s3dl_query_update(SecDbConnectionRef dbt, Query *q, + CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error) +{ + /* Sanity check the query. */ + if (query_match_count(q) != 0) + return SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported in attributes to update")); + if (q->q_ref) + return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported in attributes to update")); + if (q->q_row_id && query_attr_count(q)) + return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both row_id and other attributes can't be updated at the same time")); + if (q->q_token_object_id && query_attr_count(q) != 1) + return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both token persistent ref and other attributes can't be updated at the same time")); + + __block bool result = true; + Query *u = query_create(q->q_class, NULL, attributesToUpdate, error); + if (u == NULL) return false; + require_action_quiet(query_update_parse(u, attributesToUpdate, error), errOut, result = false); + query_pre_update(u); + result &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + // Make sure we only update real items, not tombstones, unless the client explicitly asks otherwise. + if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + result &= SecDbItemQuery(q, accessGroups, dbt, error, ^(SecDbItemRef item, bool *stop) { + // We always need to know the error here. + CFErrorRef localError = NULL; + if (q->q_token_object_id) { + const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); + CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) + return; + } + // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. + const SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL); + CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, NULL)); + SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, u->q_item, &localError); + SecDbItemSetValue(item, sha1attr, storedSHA1, NULL); + CFReleaseSafe(storedSHA1); + if (SecErrorGetOSStatus(localError) == errSecDecode) { + // We just ignore this, and treat as if item is not found. + secwarning("deleting corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError); + CFReleaseNull(localError); + if (!SecDbItemDelete(item, dbt, false, &localError)) { + secerror("failed to delete corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError); + CFReleaseNull(localError); + } + CFReleaseNull(new_item); + return; + } + if (new_item != NULL && u->q_access_control != NULL) + SecDbItemSetAccessControl(new_item, u->q_access_control, &localError); + result = SecErrorPropagate(localError, error) && new_item; + if (new_item) { + bool item_is_sync = SecDbItemIsSyncable(item); + result = SecDbItemUpdate(item, new_item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), q->q_uuid_from_primary_key, error); + if (result) { + q->q_changed = true; + if (item_is_sync || SecDbItemIsSyncable(new_item)) + q->q_sync_changed = true; + } + CFRelease(new_item); + } + }); + if (!result) + *commit = false; + }); + if (result && !q->q_changed) + result = SecError(errSecItemNotFound, error, CFSTR("No items updated")); +errOut: + if (!query_destroy(u, error)) + result = false; + return result; +} + +static bool SecDbItemNeedAuth(SecDbItemRef item, CFErrorRef *error) +{ + CFErrorRef localError = NULL; + if (!SecDbItemEnsureDecrypted(item, true, &localError) && localError && CFErrorGetCode(localError) == errSecAuthNeeded) { + if (error) + *error = localError; + return true; + } + + CFReleaseSafe(localError); + return false; +} + +bool +s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error) +{ + __block bool ok = true; + __block bool needAuth = false; + // Only delete things that aren't tombstones, unless the client explicitly asks otherwise. + if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + ok &= SecDbItemSelect(q, dbt, error, NULL, ^bool(const SecDbAttr *attr) { + return false; + },^bool(CFMutableStringRef sql, bool *needWhere) { + SecDbAppendWhereClause(sql, q, accessGroups); + return true; + },^bool(sqlite3_stmt * stmt, int col) { + return sqlBindWhereClause(stmt, q, accessGroups, &col, error); + }, ^(SecDbItemRef item, bool *stop) { + // Check if item for token persitence ref + if (q->q_token_object_id) { + const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); + CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) + return; + } + // Check if item need to be authenticated by LocalAuthentication + item->cryptoOp = kAKSKeyOpDelete; + if (SecDbItemNeedAuth(item, error)) { + needAuth = true; + return; + } + // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. + const SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL); + CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, NULL)); + bool item_is_sync = SecDbItemIsSyncable(item); + SecDbItemSetValue(item, sha1attr, storedSHA1, NULL); + CFReleaseSafe(storedSHA1); + ok = SecDbItemDelete(item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), error); + if (ok) { + q->q_changed = true; + if (item_is_sync) + q->q_sync_changed = true; + } + }); + if (ok && !q->q_changed && !needAuth) { + ok = SecError(errSecItemNotFound, error, CFSTR("Delete failed to delete anything")); + } + return ok && !needAuth; +} + +static bool +matchAnyString(CFStringRef needle, CFStringRef *haystack) +{ + while (*haystack) { + if (CFEqual(needle, *haystack)) + return true; + haystack++; + } + return false; +} + +/* Return true iff the item in question should not be backed up, nor restored, + but when restoring a backup the original version of the item should be + added back to the keychain again after the restore completes. */ +bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser) { + CFNumberRef sysb = CFDictionaryGetValue(item, kSecAttrSysBound); + if (isNumber(sysb)) { + int32_t num = 0; + if (!CFNumberGetValue(sysb, kCFNumberSInt32Type, &num)) + return false; + if (num == kSecSecAttrSysBoundNot) { + return false; + } else if (num == kSecSecAttrSysBoundPreserveDuringRestore) { + return true; + } + return true; + } + + CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup); + if (!isString(agrp)) + return false; + + if (CFEqualSafe(agrp, kSOSInternalAccessGroup)) { + secdebug("backup", "found sysbound item: %@", item); + return true; + } + + if (CFEqual(agrp, CFSTR("lockdown-identities"))) { + secdebug("backup", "found sys_bound item: %@", item); + return true; + } + + if (CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount); + + if (isString(service) && isString(account)) { + static CFStringRef mcAccounts[] = { + CFSTR("Public"), + CFSTR("Private"), + NULL, + }; + + if (CFEqual(service, CFSTR("com.apple.managedconfiguration")) + && matchAnyString(account, mcAccounts)) + { + secdebug("backup", "found sys_bound item: %@", item); + return true; + } + } + + if (isString(service) && CFEqual(service, CFSTR("com.apple.account.CloudKit.token"))) { + secdebug("backup", "found sys_bound item: %@", item); + return true; + } + + if (isString(service) && CFEqual(service, CFSTR("com.apple.account.idms.continuation-key"))) { + secdebug("backup", "found sys_bound item: %@", item); + return true; + } + } + + if (multiUser && CFEqual(agrp, CFSTR("com.apple.apsd")) && cls == genp_class()) { + static CFStringRef pushServices[] = { + CFSTR("push.apple.com"), + CFSTR("push.apple.com,PerAppToken.v0"), + NULL + }; + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + + if (isString(service) && matchAnyString(service, pushServices)) { + secdebug("backup", "found sys_bound item: %@", item); + return true; + } + } + + if (multiUser && CFEqual(agrp, CFSTR("appleaccount")) && cls == genp_class()) { + static CFStringRef accountServices[] = { + CFSTR("com.apple.appleaccount.fmf.token"), /* temporary tokens while accout is being setup */ + CFSTR("com.apple.appleaccount.fmf.apptoken"), + CFSTR("com.apple.appleaccount.fmip.siritoken"), + CFSTR("com.apple.appleaccount.cloudkit.token"), + NULL + }; + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + + if (isString(service) && matchAnyString(service, accountServices)) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + } + + if (multiUser && CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { + static CFStringRef accountServices[] = { + /* accounts, remove with rdar://37595482 */ + CFSTR("com.apple.account.AppleAccount.token"), + CFSTR("com.apple.account.AppleAccount.password"), + CFSTR("com.apple.account.AppleAccount.rpassword"), + CFSTR("com.apple.account.idms.token"), + CFSTR("com.apple.account.idms.heartbeat-token"), + CFSTR("com.apple.account.idms.continuation-key"), + CFSTR("com.apple.account.CloudKit.token"), + CFSTR("com.apple.account.IdentityServices.password"), /* accountsd for ids */ + CFSTR("com.apple.account.IdentityServices.rpassword"), + CFSTR("com.apple.account.IdentityServices.token"), + /* IDS stuff */ + CFSTR("BackupIDSAccountToken"), + CFSTR("com.apple.ids"), + CFSTR("ids"), + CFSTR("IDS"), + NULL + }; + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + + if (isString(service) && matchAnyString(service, accountServices)) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + if (isString(service) && CFStringHasPrefix(service, CFSTR("com.apple.gs."))) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + if (isString(service) && CFEqual(service, CFSTR("com.apple.facetime"))) { + CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount); + if (isString(account) && CFEqual(account, CFSTR("registrationV1"))) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + } + } + + /* accounts, remove with rdar://37595482 */ + if (multiUser && CFEqual(agrp, CFSTR("com.apple.ind")) && cls == genp_class()) { + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + if (isString(service) && CFEqual(service, CFSTR("com.apple.ind.registration"))) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + } + + if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == genp_class()) { + static CFStringRef accountServices[] = { + CFSTR("ids"), + NULL + }; + CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); + + if (isString(service) && matchAnyString(service, accountServices)) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + } + + if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == keys_class()) { + static CFStringRef exactMatchingLabel[] = { + CFSTR("iMessage Encryption Key"), + CFSTR("iMessage Signing Key"), + }; + CFStringRef label = CFDictionaryGetValue(item, kSecAttrLabel); + if (isString(label)) { + if (matchAnyString(label, exactMatchingLabel)) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + } + } + + if (multiUser && CFEqual(agrp, CFSTR("com.apple.rapport")) && cls == genp_class()) { + secdebug("backup", "found exact sys_bound item: %@", item); + return true; + } + + secdebug("backup", "found non sys_bound item: %@", item); + return false; +} + +/* Delete all items from the current keychain. If this is not an in + place upgrade we don't delete items in the 'lockdown-identities' + access group, this ensures that an import or restore of a backup + will never overwrite an existing activation record. */ +static bool SecServerDeleteAll(SecDbConnectionRef dbt, CFErrorRef *error) { + secwarning("SecServerDeleteAll"); + + return kc_transaction(dbt, error, ^{ + + bool ok = (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) && + SecDbExec(dbt, CFSTR("DELETE from inet;"), error) && + SecDbExec(dbt, CFSTR("DELETE from cert;"), error) && + SecDbExec(dbt, CFSTR("DELETE from keys;"), error)); + return ok; + }); +} + +#if TARGET_OS_IPHONE + +static bool DeleteAllFromTableForMUSRView(SecDbConnectionRef dbt, + CFStringRef sql, + CFDataRef musr, + bool keepU, + CFErrorRef *error) +{ + sqlite3_stmt *stmt = NULL; + CFStringRef sql2 = NULL; + bool ok = false; + + if (keepU) { + sql2 = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ AND pdmn NOT IN ('aku','akpu','cku','dku')"), sql); + } else { + sql2 = CFRetain(sql); + } + require(sql2, fail); + + stmt = SecDbCopyStmt(dbt, sql2, NULL, error); + require(stmt, fail); + + ok = SecDbBindObject(stmt, 1, musr, error); + require(ok, fail); + + ok = SecDbStep(dbt, stmt, error, ^(bool *stop) { }); + require(ok, fail); + +fail: + if (stmt) { + ok = SecDbFinalize(stmt, error); + } + if (!ok) + secwarning("DeleteAllFromTableForMUSRView failed for %@ for musr: %@: %@", sql2, musr, error ? *error : NULL); + + CFReleaseNull(sql2); + + return ok; +} + +bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool keepU, CFErrorRef *error) { + secwarning("SecServerDeleteAllForUser for user: %@ keepU %s", musrView, keepU ? "yes" : "no"); + + return kc_transaction(dbt, error, ^{ + bool ok; + + ok = (DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM genp WHERE musr = ?"), musrView, keepU, error) && + DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM inet WHERE musr = ?"), musrView, keepU, error) && + DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM cert WHERE musr = ?"), musrView, keepU, error) && + DeleteAllFromTableForMUSRView(dbt, CFSTR("DELETE FROM keys WHERE musr = ?"), musrView, keepU, error)); + + return ok; + }); +} +#endif + + +struct s3dl_export_row_ctx { + struct s3dl_query_ctx qc; + keybag_handle_t dest_keybag; + enum SecItemFilter filter; + bool multiUser; +}; + +static void s3dl_export_row(sqlite3_stmt *stmt, void *context) { + struct s3dl_export_row_ctx *c = context; + Query *q = c->qc.q; + SecAccessControlRef access_control = NULL; + CFErrorRef localError = NULL; + + /* Skip akpu items when backing up, those are intentionally lost across restores. The same applies to SEP-based keys */ + bool skip_akpu_or_token = c->filter == kSecBackupableItemFilter; + + sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); + CFMutableDictionaryRef allAttributes = NULL; + CFMutableDictionaryRef metadataAttributes = NULL; + CFMutableDictionaryRef secretStuff = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + keyclass_t keyclass = 0; + bool ok = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups, &allAttributes, &access_control, &keyclass, &localError); + + if (ok) { + metadataAttributes = CFDictionaryCreateMutableCopy(NULL, 0, allAttributes); + SecDbForEachAttrWithMask(q->q_class, desc, kSecDbReturnDataFlag) { + CFTypeRef value = CFDictionaryGetValue(metadataAttributes, desc->name); + if (value) { + CFDictionarySetValue(secretStuff, desc->name, value); + CFDictionaryRemoveValue(metadataAttributes, desc->name); + } + } + } + + bool is_akpu = access_control ? CFEqualSafe(SecAccessControlGetProtection(access_control), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) + // Mask generation, only look at class per se + : (keyclass & key_class_last) == key_class_akpu; + bool is_token = (ok && allAttributes != NULL) ? CFDictionaryContainsKey(allAttributes, kSecAttrTokenID) : false; + + if (ok && allAttributes && !(skip_akpu_or_token && (is_akpu || is_token))) { + /* Only export sysbound items if do_sys_bound is true, only export non sysbound items otherwise. */ + bool do_sys_bound = c->filter == kSecSysBoundItemFilter; + if (c->filter == kSecNoItemFilter || + SecItemIsSystemBound(allAttributes, q->q_class, c->multiUser) == do_sys_bound) { + /* Re-encode the item. */ + secdebug("item", "export rowid %llu item: %@", rowid, allAttributes); + /* The code below could be moved into handle_row. */ + CFDataRef pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, allAttributes); + if (pref) { + if (c->dest_keybag != KEYBAG_NONE) { + CFMutableDictionaryRef auth_attribs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInAuthenticatedDataFlag) { + CFTypeRef value = CFDictionaryGetValue(metadataAttributes, desc->name); + if(value) { + CFDictionaryAddValue(auth_attribs, desc->name, value); + CFDictionaryRemoveValue(metadataAttributes, desc->name); + } + } + + /* Encode and encrypt the item to the specified keybag. */ + CFDataRef edata = NULL; + bool encrypted = ks_encrypt_data(c->dest_keybag, access_control, q->q_use_cred_handle, secretStuff, metadataAttributes, auth_attribs, &edata, false, &q->q_error); + CFDictionaryRemoveAllValues(allAttributes); + CFRelease(auth_attribs); + if (encrypted) { + CFDictionarySetValue(allAttributes, kSecValueData, edata); + CFReleaseSafe(edata); + } else { + seccritical("ks_encrypt_data %@,rowid=%" PRId64 ": failed: %@", q->q_class->name, rowid, q->q_error); + CFReleaseNull(q->q_error); + } + } + if (CFDictionaryGetCount(allAttributes)) { + CFDictionarySetValue(allAttributes, kSecValuePersistentRef, pref); + CFArrayAppendValue((CFMutableArrayRef)c->qc.result, allAttributes); + c->qc.found++; + } + CFReleaseSafe(pref); + } + } + } else { + OSStatus status = SecErrorGetOSStatus(localError); + + if (status == errSecInteractionNotAllowed && is_akpu) { + if (skip_akpu_or_token) { + secdebug("item", "Skipping akpu item for backup"); + } else { // Probably failed to decrypt sysbound item. Should never be an akpu item in backup. + secerror("Encountered akpu item we cannot export (filter %d), skipping. %@", c->filter, localError); + CFDictionaryRef payload = NULL; + CFTypeRef agrp = CFDictionaryGetValue(allAttributes, CFSTR("agrp")); + if (agrp) { + payload = CFDictionaryCreateForCFTypes(NULL, CFSTR("agrp"), agrp, NULL); + } + SecABCTrigger(CFSTR("keychain"), CFSTR("invalid-akpu+sysbound"), NULL, payload); + CFReleaseNull(payload); + } + // We expect akpu items to be inaccessible when the device is locked. + CFReleaseNull(localError); + } else { + /* This happens a lot when trying to migrate keychain before first unlock, so only a notice */ + /* If the error is "corrupted item" then we just ignore it, otherwise we save it in the query */ + secinfo("item","Could not export item for rowid %llu: %@", rowid, localError); + + if (status == errSecDecode) { + CFReleaseNull(localError); + } else { + CFReleaseSafe(q->q_error); + q->q_error = localError; + } + } + } + CFReleaseNull(access_control); + CFReleaseNull(allAttributes); + CFReleaseNull(metadataAttributes); + CFReleaseNull(secretStuff); +} + +static CFStringRef +SecCreateKeybagUUID(keybag_handle_t keybag) +{ +#if !TARGET_HAS_KEYSTORE + return NULL; +#else + char uuidstr[37]; + uuid_t uuid; + if (aks_get_bag_uuid(keybag, uuid) != KERN_SUCCESS) + return NULL; + uuid_unparse_lower(uuid, uuidstr); + return CFStringCreateWithCString(NULL, uuidstr, kCFStringEncodingUTF8); +#endif +} + + +CFDictionaryRef +SecServerCopyKeychainPlist(SecDbConnectionRef dbt, + SecurityClient *client, + keybag_handle_t src_keybag, + keybag_handle_t dest_keybag, + enum SecItemFilter filter, + CFErrorRef *error) { + CFMutableDictionaryRef keychain; + keychain = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + unsigned class_ix; + bool inMultiUser = false; + CFStringRef keybaguuid = NULL; + Query q = { .q_keybag = src_keybag, + .q_musrView = NULL + }; + + if (!keychain) { + if (error && !*error) + SecError(errSecAllocate, error, CFSTR("Can't create keychain dictionary")); + goto errOut; + } + + q.q_return_type = + kSecReturnDataMask | + kSecReturnAttributesMask | + kSecReturnPersistentRefMask; + q.q_limit = kSecMatchUnlimited; + q.q_skip_acl_items = true; + + +#if TARGET_OS_IPHONE + if (client && client->inMultiUser) { + q.q_musrView = SecMUSRCreateActiveUserUUID(client->uid); + inMultiUser = true; + } else +#endif + { + q.q_musrView = SecMUSRGetSingleUserKeychainUUID(); + CFRetain(q.q_musrView); + + keybaguuid = SecCreateKeybagUUID(dest_keybag); + if (keybaguuid) { + CFDictionarySetValue(keychain, kSecBackupKeybagUUIDKey, keybaguuid); + } + } + + /* Get rid of this duplicate. */ + const SecDbClass *SecDbClasses[] = { + genp_class(), + inet_class(), + cert_class(), + keys_class() + }; + + for (class_ix = 0; class_ix < array_size(SecDbClasses); + ++class_ix) { + q.q_class = SecDbClasses[class_ix]; + struct s3dl_export_row_ctx ctx = { + .qc = { .q = &q, .dbt = dbt }, + .dest_keybag = dest_keybag, .filter = filter, + .multiUser = inMultiUser, + }; + + secnotice("item", "exporting %ssysbound class '%@'", filter != kSecSysBoundItemFilter ? "non-" : "", q.q_class->name); + + CFErrorRef localError = NULL; + if (s3dl_query(s3dl_export_row, &ctx, &localError)) { + secnotice("item", "exporting class '%@' complete", q.q_class->name); + if (CFArrayGetCount(ctx.qc.result)) { + SecSignpostBackupCount(SecSignpostImpulseBackupClassCount, q.q_class->name, CFArrayGetCount(ctx.qc.result), filter); + CFDictionaryAddValue(keychain, q.q_class->name, ctx.qc.result); + } + + } else { + OSStatus status = (OSStatus)CFErrorGetCode(localError); + if (status == errSecItemNotFound) { + secnotice("item", "exporting class '%@' complete (no items)", q.q_class->name); + CFRelease(localError); + } else { + secerror("exporting class '%@' failed: %@", q.q_class->name, localError); + if (error) { + CFReleaseSafe(*error); + *error = localError; + } else { + CFRelease(localError); + } + CFReleaseNull(keychain); + CFReleaseNull(ctx.qc.result); + break; + } + } + CFReleaseNull(ctx.qc.result); + } + +errOut: + CFReleaseNull(q.q_musrView); + CFReleaseNull(keybaguuid); + + return keychain; +} + +struct SecServerImportClassState { + SecDbConnectionRef dbt; + CFErrorRef error; + keybag_handle_t src_keybag; + keybag_handle_t dest_keybag; + SecurityClient *client; + enum SecItemFilter filter; +}; + +struct SecServerImportItemState { + const SecDbClass *class; + struct SecServerImportClassState *s; +}; + +static void +SecServerImportItem(const void *value, void *context) +{ + struct SecServerImportItemState *state = (struct SecServerImportItemState *)context; + bool inMultiUser = false; +#if TARGET_OS_IPHONE + if (state->s->client->inMultiUser) + inMultiUser = true; +#endif + + if (state->s->error) + return; + + if (!isDictionary(value)) { + SecError(errSecParam, &state->s->error, CFSTR("value %@ is not a dictionary"), value); + return; + } + + CFDictionaryRef dict = (CFDictionaryRef)value; + + secdebug("item", "Import Item : %@", dict); + + SecDbItemRef item = NULL; + + /* This is sligthly confusing: + - During upgrade all items are exported with KEYBAG_NONE. + - During restore from backup, existing sys_bound items are exported with KEYBAG_NONE, and are exported as dictionary of attributes. + - Item in the actual backup are export with a real keybag, and are exported as encrypted v_Data and v_PersistentRef + */ + if (state->s->src_keybag == KEYBAG_NONE) { + item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, state->class, dict, state->s->dest_keybag, &state->s->error); + } else { + item = SecDbItemCreateWithBackupDictionary(kCFAllocatorDefault, state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error); + } + + /* If item is NULL here, control flow ends up at the end where error is cleared. */ + if (item && !SecDbItemEnsureDecrypted(item, true, &state->s->error)) { + secdebug("item", "Failed to import item because of decryption failure: %@", state->s->error); + CFReleaseNull(item); + /* No early return; as just above, go to the end where error is cleared. */ + } + + /* We use the kSecSysBoundItemFilter to indicate that we don't + * preserve rowid's during import. + */ + if (item && item->attributes && state->s->filter == kSecBackupableItemFilter) { + CFTypeRef pdmu; + + /* We don't filter non sys_bound items during import since we know we + * will never have any in this case. + */ + if (SecItemIsSystemBound(item->attributes, state->class, inMultiUser)) { + secdebug("item", "skipping backup of item: %@", dict); + CFReleaseNull(item); + return; + } + + /* + * Don't bother with u items when in edu mode since our current backup system + * don't keep track of items that blongs to the device (u) but rather just + * merge them into one blob. + */ + if (inMultiUser && (pdmu = CFDictionaryGetValue(item->attributes, kSecAttrAccessible))) { + if (CFEqual(pdmu, kSecAttrAccessibleWhenUnlockedThisDeviceOnly) || + CFEqual(pdmu, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) || + CFEqual(pdmu, kSecAttrAccessibleWhenUnlockedThisDeviceOnly) || + CFEqual(pdmu, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) + { + secdebug("item", "Skipping KU item : %@", dict); + CFReleaseNull(item); + return; + } + } + + /* Avoid importing token-based items. Although newer backups should not have them, + * older (iOS9, iOS10.0) produced backups with token-based items. + */ + if (CFDictionaryContainsKey(item->attributes, kSecAttrTokenID)) { + secdebug("item", "Skipping token-based item : %@", dict); + CFReleaseNull(item); + return; + } + } + + /* + * + */ + + if (item && item->attributes) { + CFDataRef musr = NULL; + CFDataRef musrBackup = CFDictionaryGetValue(item->attributes, kSecAttrMultiUser); + CFDataRef systemKeychainUUID = SecMUSRGetSystemKeychainUUID(); + bool systemKeychain = CFEqualSafe(musrBackup, systemKeychainUUID); + +#if TARGET_OS_IPHONE + if (state->s->client && state->s->client->inMultiUser) { + if (systemKeychain) { + secwarning("system keychain not allowed in multi user mode for item: %@", item); + } else { + musr = SecMUSRCreateActiveUserUUID(state->s->client->uid); + } + } else +#endif + { + if (systemKeychain) { + musr = SecMUSRCopySystemKeychainUUID(); + } else { + musr = SecMUSRGetSingleUserKeychainUUID(); + CFRetainSafe(musr); + } + } + if (musr == NULL) { + CFReleaseNull(item); + } else { + SecDbItemSetValueWithName(item, CFSTR("musr"), musr, &state->s->error); + CFRelease(musr); + } + } + + /* + * + */ + + if (item) { + bool insertStatus; + + if(state->s->filter != kSecSysBoundItemFilter) { + SecDbItemExtractRowIdFromBackupDictionary(item, dict, &state->s->error); + } + SecDbItemInferSyncable(item, &state->s->error); + insertStatus = SecDbItemInsert(item, state->s->dbt, &state->s->error); + if (!insertStatus) { + /* + When running in EduMode, multiple users share the same + keychain and unfortionaly the rowid is used a + persistant reference and is part of the contraints (its + UNIQUE), so lets clear the rowid and try to insert the + entry again. + + This even happens for normal operation because of + SysBound entries, so in case of a failure, lets try + again to insert the record. + */ + SecDbItemClearRowId(item, NULL); + SecDbItemInsert(item, state->s->dbt, &state->s->error); + } + } + + /* Reset error if we had one, since we just skip the current item + and continue importing what we can. */ + if (state->s->error) { + secwarning("Failed to import an item (%@) of class '%@': %@ - ignoring error.", + item, state->class->name, state->s->error); + CFReleaseNull(state->s->error); + } + + CFReleaseSafe(item); +} + +static void SecServerImportClass(const void *key, const void *value, + void *context) { + struct SecServerImportClassState *state = + (struct SecServerImportClassState *)context; + if (state->error) + return; + if (!isString(key)) { + SecError(errSecParam, &state->error, CFSTR("class name %@ is not a string"), key); + return; + } + /* ignore the Keybag UUID */ + if (CFEqual(key, kSecBackupKeybagUUIDKey)) + return; + const SecDbClass *class = kc_class_with_name(key); + if (!class) { + secwarning("Ignoring unknown key class '%@'", key); + return; + } + if (class == identity_class()) { + SecError(errSecParam, &state->error, CFSTR("attempt to import an identity")); + return; + } + struct SecServerImportItemState item_state = { + .class = class, .s = state, + }; + if (isArray(value)) { + CFArrayRef items = (CFArrayRef)value; + secwarning("Import %ld items of class %@ (filter %d)", (long)CFArrayGetCount(items), key, state->filter); + SecSignpostBackupCount(SecSignpostImpulseRestoreClassCount, class->name, CFArrayGetCount(items), state->filter); + CFArrayApplyFunction(items, CFRangeMake(0, CFArrayGetCount(items)), + SecServerImportItem, &item_state); + } else if (isDictionary(value)) { + CFDictionaryRef item = (CFDictionaryRef)value; + secwarning("Import %ld items of class %@ (filter %d)", (long)1, key, state->filter); + SecSignpostBackupCount(SecSignpostImpulseRestoreClassCount, class->name, 1, state->filter); + SecServerImportItem(item, &item_state); + } else { + secwarning("Unknown value type for class %@ (filter %d)", key, state->filter); + } +} + +bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, SecurityClient *client, + keybag_handle_t src_keybag, keybag_handle_t dest_keybag, + CFDictionaryRef keychain, enum SecItemFilter filter, + bool removeKeychainContent, CFErrorRef *error) { + CFStringRef keybaguuid = NULL; + bool ok = true; + + CFDictionaryRef sys_bound = NULL; + if (filter == kSecBackupableItemFilter) { + /* Grab a copy of all the items for which SecItemIsSystemBound() + returns true. */ + require(sys_bound = SecServerCopyKeychainPlist(dbt, client, KEYBAG_DEVICE, + KEYBAG_NONE, kSecSysBoundItemFilter, + error), errOut); + } + + /* + * Validate the uuid of the source keybag matches what we have in the backup + */ + keybaguuid = SecCreateKeybagUUID(src_keybag); + if (keybaguuid) { + CFStringRef uuid = CFDictionaryGetValue(keychain, kSecBackupKeybagUUIDKey); + if (isString(uuid)) { + require_action(CFEqual(keybaguuid, uuid), errOut, + SecError(errSecDecode, error, CFSTR("Keybag UUID (%@) mismatch with backup (%@)"), + keybaguuid, uuid)); + } + } + +#if TARGET_OS_IOS + /* + * Shared iPad is very special, it always delete's the user keychain, and never merge content + */ + if (client->inMultiUser) { + CFDataRef musrView = SecMUSRCreateActiveUserUUID(client->uid); + require_action(musrView, errOut, ok = false); + require_action(ok = SecServerDeleteAllForUser(dbt, musrView, true, error), errOut, CFReleaseNull(musrView)); + CFReleaseNull(musrView); + } else +#endif + { + /* + * Delete everything in the keychain. + * We don't want this if we're restoring backups because we probably already synced stuff over + */ + if (removeKeychainContent) { + require(ok = SecServerDeleteAll(dbt, error), errOut); + } else { + // Custom hack to support bluetooth's workflow for 11.3. Should be removed in a future release. + __block CFErrorRef btError = NULL; + bool deletedBT = kc_transaction(dbt, &btError, ^bool{ + +#define EXCLUDE_AGRPS "'com.apple.security.sos', 'com.apple.security.sos-usercredential', 'com.apple.security.ckks', 'com.apple.security.egoIdentities', 'com.apple.security.octagon'" + + bool tok = SecDbExec(dbt, CFSTR("DELETE FROM genp WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); + tok &= SecDbExec(dbt, CFSTR("DELETE FROM inet WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); + tok &= SecDbExec(dbt, CFSTR("DELETE FROM cert WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); + tok &= SecDbExec(dbt, CFSTR("DELETE FROM keys WHERE sync = 0 AND NOT agrp IN (" EXCLUDE_AGRPS ");"), &btError); + +#undef EXCLUDE_AGRPS + return tok; + }); + if (!deletedBT) { + secerror("Unable to delete nonsyncable items prior to keychain restore: %@", btError); + } else { + secnotice("restore", "Successfully deleted nonsyncable items"); + } + CFReleaseNull(btError); + } + } + + struct SecServerImportClassState state = { + .dbt = dbt, + .src_keybag = src_keybag, + .dest_keybag = dest_keybag, + .client = client, + .filter = filter, + }; + /* Import the provided items, preserving rowids. */ + secwarning("Restoring backup items '%ld'", (long)CFDictionaryGetCount(keychain)); + CFDictionaryApplyFunction(keychain, SecServerImportClass, &state); + + if (sys_bound) { + state.src_keybag = KEYBAG_NONE; + /* Import the items we preserved with random rowids. */ + state.filter = kSecSysBoundItemFilter; + secwarning("Restoring sysbound items '%ld'", (long)CFDictionaryGetCount(sys_bound)); + CFDictionaryApplyFunction(sys_bound, SecServerImportClass, &state); + } + if (state.error) { + if (error) { + CFReleaseSafe(*error); + *error = state.error; + } else { + CFRelease(state.error); + } + ok = false; + } + + // If CKKS had spun up, it's very likely that we just deleted its data. + // Tell it to perform a local resync. +#if OCTAGON + SecCKKSPerformLocalResync(); +#endif + +errOut: + CFReleaseSafe(sys_bound); + CFReleaseSafe(keybaguuid); + + return ok; +} + +CFStringRef +SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error) +{ + CFStringRef uuid = CFDictionaryGetValue(keychain, kSecBackupKeybagUUIDKey); + if (!isString(uuid)) { + SecError(errSecDecode, error, CFSTR("Missing or invalid %@ in backup dictionary"), kSecBackupKeybagUUIDKey); + return NULL; + } + return uuid; +} + +#pragma mark - key rolling support +#if USE_KEYSTORE + +struct check_generation_ctx { + struct s3dl_query_ctx query_ctx; + uint32_t current_generation; +}; + +static void check_generation(sqlite3_stmt *stmt, void *context) { + struct check_generation_ctx *c = context; + CFDataRef blob = NULL; + size_t blobLen = 0; + const uint8_t *cursor = NULL; + uint32_t version; + keyclass_t keyclass; + uint32_t current_generation = c->current_generation; + + require(blob = s3dl_copy_data_from_col(stmt, 1, &c->query_ctx.q->q_error), out); + blobLen = CFDataGetLength(blob); + cursor = CFDataGetBytePtr(blob); + + /* Check for underflow, ensuring we have at least one full AES block left. */ + if (blobLen < sizeof(version) + sizeof(keyclass)) { + SecError(errSecDecode, &c->query_ctx.q->q_error, CFSTR("check_generation: Check for underflow")); + goto out; + } + + version = *((uint32_t *)cursor); + cursor += sizeof(version); + + (void) version; // TODO: do something with the version number. + + keyclass = *((keyclass_t *)cursor); + + // TODO: export get_key_gen macro + if (((keyclass & ~key_class_last) == 0) != (current_generation == 0)) { + c->query_ctx.found++; + } + + CFReleaseSafe(blob); + return; + +out: + c->query_ctx.found++; + CFReleaseSafe(blob); +} + +bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, CFErrorRef *error) { + CFErrorRef localError = NULL; + struct check_generation_ctx ctx = { .query_ctx = { .dbt = dbt }, .current_generation = current_generation }; + + const SecDbClass *classes[] = { + genp_class(), + inet_class(), + keys_class(), + cert_class(), + }; + + for (size_t class_ix = 0; class_ix < array_size(classes); ++class_ix) { + Query *q = query_create(classes[class_ix], NULL, NULL, &localError); + if (!q) + return false; + + ctx.query_ctx.q = q; + q->q_limit = kSecMatchUnlimited; + + bool ok = s3dl_query(check_generation, &ctx, &localError); + query_destroy(q, NULL); + CFReleaseNull(ctx.query_ctx.result); + + if (!ok && localError && (CFErrorGetCode(localError) == errSecItemNotFound)) { + CFReleaseNull(localError); + continue; + } + secerror("Class %@ not up to date", classes[class_ix]->name); + return false; + } + return true; +} + +bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, SecurityClient *client, CFErrorRef *error) { + return SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + __block bool ok = false; + uint32_t keystore_generation_status; + + /* can we migrate to new class keys right now? */ + if (!aks_generation(KEYBAG_DEVICE, generation_noop, &keystore_generation_status) && + (keystore_generation_status & generation_change_in_progress)) { + + /* take a lock assertion */ + bool operated_while_unlocked = SecAKSDoWithUserBagLockAssertion(error, ^{ + CFErrorRef localError = NULL; + CFDictionaryRef backup = SecServerCopyKeychainPlist(dbt, NULL, + KEYBAG_DEVICE, KEYBAG_NONE, kSecNoItemFilter, &localError); + if (backup) { + if (localError) { + secerror("Ignoring export error: %@ during roll export", localError); + CFReleaseNull(localError); + } + // 'true' argument: we're replacing everything with newly wrapped entries so remove the old stuff + ok = SecServerImportKeychainInPlist(dbt, client, KEYBAG_NONE, + KEYBAG_DEVICE, backup, kSecNoItemFilter, true, &localError); + if (localError) { + secerror("Ignoring export error: %@ during roll export", localError); + CFReleaseNull(localError); + } + CFRelease(backup); + } + }); + if (!operated_while_unlocked) + ok = false; + } else { + ok = SecError(errSecBadReq, error, CFSTR("No key roll in progress.")); + } + + *commit = ok; + }); +} +#endif diff --git a/keychain/securityd/SecItemDb.h b/keychain/securityd/SecItemDb.h new file mode 100644 index 00000000..3a07bb65 --- /dev/null +++ b/keychain/securityd/SecItemDb.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemDb.h - A Database full of SecDbItems. + */ + +#ifndef _SECURITYD_SECITEMDB_H_ +#define _SECURITYD_SECITEMDB_H_ + +#include "keychain/securityd/SecDbQuery.h" + +struct SecurityClient; + +__BEGIN_DECLS + +bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error); + +bool SecItemDbDeleteSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFErrorRef *error); + +CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error); + +bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, + bool (^return_attr)(const SecDbAttr *attr), + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), + bool (^bind_added_where)(sqlite3_stmt *stmt, int col), + void (^handle_row)(SecDbItemRef item, bool *stop)); + +CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query, + bool (^return_attr)(const SecDbAttr *attr), + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)); +bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error, + bool (^use_attr_in_where)(const SecDbAttr *attr), + bool (^bind_added_where)(sqlite3_stmt *stmt, int col)); + +bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error, + void (^handle_row)(SecDbItemRef item, bool *stop)); + +void query_pre_add(Query *q, bool force_date); + +bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser); + +// +// MARK: backup restore stuff +// + +/* Forward declaration of import export SPIs. */ +enum SecItemFilter { + kSecNoItemFilter, + kSecSysBoundItemFilter, + kSecBackupableItemFilter, +}; + +CFDictionaryRef SecServerCopyKeychainPlist(SecDbConnectionRef dbt, + struct SecurityClient *client, + keybag_handle_t src_keybag, + keybag_handle_t dest_keybag, + enum SecItemFilter filter, + CFErrorRef *error); +bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, + struct SecurityClient *client, + keybag_handle_t src_keybag, + keybag_handle_t dest_keybag, + CFDictionaryRef keychain, + enum SecItemFilter filter, + bool removeKeychainContent, + CFErrorRef *error); + +CFStringRef +SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error); + + +#if TARGET_OS_IPHONE +bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool keepU, CFErrorRef *error); +#endif + +bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)(void)); +bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)(void)); +bool s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, + CFArrayRef accessGroups, CFErrorRef *error); +bool s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error); +bool s3dl_query_update(SecDbConnectionRef dbt, Query *q, + CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error); +bool s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error); +bool s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error); + +const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, CFTypeRef key, CFErrorRef *error); + +bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, CFErrorRef *error); +bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, struct SecurityClient *client, CFErrorRef *error); + +// We'd love to take a query here, but switching layers at the callsite means we don't have it +bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error); + +__END_DECLS + +#endif /* _SECURITYD_SECITEMDB_H_ */ diff --git a/keychain/securityd/SecItemSchema.c b/keychain/securityd/SecItemSchema.c new file mode 100644 index 00000000..9a58ef42 --- /dev/null +++ b/keychain/securityd/SecItemSchema.c @@ -0,0 +1,3047 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecItemSchema.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#include "SecItemSchema.h" +#include "keychain/securityd/SecDbKeychainItem.h" +#include +#include "CheckV12DevEnabled.h" + +// MARK - +// MARK Keychain version 6 schema + +#define __FLAGS(ARG, ...) SECDBFLAGS(__VA_ARGS__) +#define SECDBFLAGS(ARG, ...) __FLAGS_##ARG | __FLAGS(__VA_ARGS__) + +#define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N,U,V,Y) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N|__FLAGS_##U|__FLAGS_##V|__FLAGS_##Y) + +#define __FLAGS_ 0 +#define __FLAGS_P kSecDbPrimaryKeyFlag +#define __FLAGS_L kSecDbInFlag +#define __FLAGS_I kSecDbIndexFlag +#define __FLAGS_S kSecDbSHA1ValueInFlag +#define __FLAGS_A kSecDbReturnAttrFlag +#define __FLAGS_D kSecDbReturnDataFlag +#define __FLAGS_R kSecDbReturnRefFlag +#define __FLAGS_C kSecDbInCryptoDataFlag +#define __FLAGS_H kSecDbInHashFlag +#define __FLAGS_B kSecDbInBackupFlag +#define __FLAGS_Z kSecDbDefault0Flag +#define __FLAGS_E kSecDbDefaultEmptyFlag +#define __FLAGS_N kSecDbNotNullFlag +#define __FLAGS_U kSecDbInAuthenticatedDataFlag +#define __FLAGS_V0 kSecDbSyncPrimaryKeyV0 +#define __FLAGS_V2 (kSecDbSyncPrimaryKeyV0 | kSecDbSyncPrimaryKeyV2) +#define __FLAGS_Y kSecDbSyncFlag + +// ,----------------- P : Part of primary key +// / ,---------------- L : Stored in local database +// / / ,--------------- I : Attribute wants an index in the database +// / / / ,-------------- S : SHA1 hashed attribute value in database (implies L) +// / / / / ,------------- A : Returned to client as attribute in queries +// / / / / / ,------------ D : Returned to client as data in queries +// / / / / / / ,----------- R : Returned to client as ref/persistent ref in queries +// / / / / / / / ,---------- C : Part of encrypted blob +// / / / / / / / / ,--------- H : Attribute is part of item SHA1 hash (Implied by C) +// / / / / / / / / / ,-------- B : Attribute is part of iTunes/iCloud backup bag +// / / / / / / / / / / ,------- Z : Attribute has a default value of 0 +// / / / / / / / / / / / ,------ E : Attribute has a default value of "" or empty data +// / / / / / / / / / / / / ,----- N : Attribute must have a value +// / / / / / / / / / / / / / ,---- U : Attribute is stored in authenticated, but not necessarily encrypted data +// / / / / / / / / / / / / / / ,--- V0: Sync primary key version +// / / / / / / / / / / / / / / / ,- Y : Attribute should be synced +// | | | | | | | | | | | | | | | | +// common to all | | | | | | | | | | | | | | | | +SECDB_ATTR(v6rowid, "rowid", RowId, SecDbFlags( ,L, , , , ,R, , ,B, , , , , , ), NULL, NULL); +SECDB_ATTR(v6cdat, "cdat", CreationDate, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), SecDbKeychainItemCopyCurrentDate, NULL); +SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), SecDbKeychainItemCopyCurrentDate, NULL); +SECDB_ATTR(v6labl, "labl", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6data, "data", EncryptedData, SecDbFlags( ,L, , , , , , , ,B, , , , , , ), SecDbKeychainItemCopyEncryptedData, NULL); +SECDB_ATTR(v6agrp, "agrp", String, SecDbFlags(P,L,I, ,A, , , ,H, , , ,N,U,V0,Y), NULL, NULL); +SECDB_ATTR(v6pdmn, "pdmn", Access, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6sync, "sync", Sync, SecDbFlags(P,L,I, ,A, , , ,H, ,Z, ,N,U,V0, ), NULL, NULL); +SECDB_ATTR(v6tomb, "tomb", Tomb, SecDbFlags( ,L, , , , , , ,H, ,Z, ,N,U, ,Y), NULL, NULL); +SECDB_ATTR(v6sha1, "sha1", SHA1, SecDbFlags( ,L,I, ,A, ,R, , , , , , , , ,Y), SecDbKeychainItemCopySHA1, NULL); +SECDB_ATTR(v6accc, "accc", AccessControl, SecDbFlags( , , , ,A, , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v6v_Data, "v_Data", Data, SecDbFlags( , , , , ,D, ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey, SecDbFlags( , , , , , , , , , , , , , , , ), SecDbKeychainItemCopyPrimaryKey, NULL); +SECDB_ATTR(v7vwht, "vwht", String, SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL); +SECDB_ATTR(v7tkid, "tkid", String, SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL); +SECDB_ATTR(v7utomb, "u_Tomb", UTomb, SecDbFlags( , , , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v8musr, "musr", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N,U, ,Y), NULL, NULL); +// genp and inet and keys | | | | | | | | | | | | | | | | +SECDB_ATTR(v6crtr, "crtr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6alis, "alis", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// genp and inet | | | | | | | | | | | | | | | | +SECDB_ATTR(v6desc, "desc", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6icmt, "icmt", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6type, "type", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6invi, "invi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6nega, "nega", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6cusi, "cusi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6prot, "prot", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6scrp, "scrp", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6acct, "acct", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +// genp only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6svce, "svce", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6gena, "gena", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// inet only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6sdmn, "sdmn", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6srvr, "srvr", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6ptcl, "ptcl", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6atyp, "atyp", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6port, "port", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6path, "path", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +// cert only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6ctyp, "ctyp", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6cenc, "cenc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6subj, "subj", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6issr, "issr", Data, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6slnr, "slnr", Data, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6skid, "skid", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6pkhh, "pkhh", Data, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// cert attributes that share names with common ones but have different flags +SECDB_ATTR(v6certalis, "alis", Blob, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// keys only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6kcls, "kcls", Number, SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6perm, "perm", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6priv, "priv", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6modi, "modi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6klbl, "klbl", Data, SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6atag, "atag", Blob, SecDbFlags(P,L,I,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6bsiz, "bsiz", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6esiz, "esiz", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6sdat, "sdat", Date, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6edat, "edat", Date, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6sens, "sens", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6asen, "asen", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6extr, "extr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6next, "next", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6encr, "encr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6decr, "decr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6drve, "drve", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6sign, "sign", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6vrfy, "vrfy", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6snrc, "snrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6vyrc, "vyrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6wrap, "wrap", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6unwp, "unwp", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// keys attributes that share names with common ones but have different flags +SECDB_ATTR(v6keytype, "type", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6keycrtr, "crtr", Number, SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +// | | | | | | | | | | | | | | | +SECDB_ATTR(v6version, "version", Number, SecDbFlags(P,L,I, , , , , , , , , ,N, , ,Y), NULL, NULL); +SECDB_ATTR(v91minor, "minor", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , ,Y), NULL, NULL); + +SECDB_ATTR(v10_1pcsservice, "pcss", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v10_1pcspublickey, "pcsk", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v10_1pcspublicidentity,"pcsi", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); + +SECDB_ATTR(v10itemuuid, "UUID", String, SecDbFlags( ,L,I, , , , , , , , , , ,U, , ), NULL, NULL); +SECDB_ATTR(v10syncuuid, "UUID", String, SecDbFlags(P,L,I, , , , , , , , , , ,U, , ), NULL, NULL); +SECDB_ATTR(v10parentKeyUUID, "parentKeyUUID", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10currentKeyUUID,"currentKeyUUID",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10wrappedkey, "wrappedkey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10encrypteditem, "encitem", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10gencount, "gencount", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10action, "action", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10state, "state", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10waituntiltime, "waituntil", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10encodedCKRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1wasCurrent, "wascurrent", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10accessgroup, "accessgroup", String, SecDbFlags( ,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10keyclass, "keyclass", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10currentkey, "currentkey", Number, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10ckzone, "ckzone", String, SecDbFlags(P,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10ckzonecreated, "ckzonecreated", Number, SecDbFlags( ,L, , , , , , , , ,Z, , ,N, , ), NULL, NULL); +SECDB_ATTR(v10ckzonesubscribed,"ckzonesubscribed", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10ratelimiter, "ratelimiter", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10changetoken, "changetoken", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10lastfetchtime, "lastfetch", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10itempersistentref,"persistref", UUID, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10sysbound, "sysb", Number, SecDbFlags( ,L, , ,A, , ,C,H, ,Z, , , , , ), NULL, NULL); +SECDB_ATTR(v10encryptionver, "encver", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N,U, , ), NULL, NULL); + +SECDB_ATTR(v10primaryKey, "primaryKey", String, SecDbFlags(P,L,I, ,A, , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10publickeyHash, "publickeyHash", Blob, SecDbFlags(P,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10publickey, "publickey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10backupData, "backupData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); + +SECDB_ATTR(v10_1digest, "digest", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1signatures, "signatures", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1signerID, "signerID", String, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1leafIDs, "leafIDs", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1peerManIDs, "peerManifests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1entryDigests,"entryDigests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_2currentItems,"currentItems", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_2futureData, "futureData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_2schema, "schema", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1encRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_1keyArchiveHash, "key_archive_hash", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1keyArchive, "key_archive", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1archivedKey, "archived_key", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1keyArchiveName, "keyarchive_name", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1optionalEncodedCKRecord, "ckrecord", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_1archiveEscrowID,"archive_escrowid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_1itempersistentref,"persistref", UUID, SecDbFlags( ,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); + +SECDB_ATTR(v10_1currentItemUUID,"currentItemUUID",String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_4currentItemUUID,"currentItemUUID",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_1currentPtrIdentifier,"identifier",String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_2device, "device", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2peerid, "peerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2circleStatus,"circlestatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2keyState, "keystate", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentTLK, "currentTLK", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentClassA,"currentClassA",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentClassC,"currentClassC",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_4lastFixup, "lastfixup", Number, SecDbFlags( ,L, , , , , , , , ,Z, , ,N, , ), NULL, NULL); + +SECDB_ATTR(v10_5senderPeerID,"senderpeerid", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_5recvPeerID, "recvpeerid", String, SecDbFlags(P,L,I, , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_5recvPubKey, "recvpubenckey", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_5curve, "curve", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_5poisoned, "poisoned", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_5epoch, "epoch", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_5signature, "signature", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_5version, "version", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N,U, , ), NULL, NULL); + +SECDB_ATTR(v11_1osversion, "osversion", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v11_1lastunlock, "lastunlock", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v11_2actualKeyclass, "actualKeyclass", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v11_5octagonpeerid, "octagonpeerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v11_5octagonStatus, "octagonstatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v11_6moreComing, "morecoming", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v12_backupUUIDPrimary, "backupUUID", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v12_backupUUID, "backupUUID", UUID, SecDbFlags( ,L,I, , , , , , , , ,E, , , , ), NULL, NULL); +SECDB_ATTR(v12_backupBag, "backupbag", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v12_defaultValue, "defaultvalue", Number, SecDbFlags( ,L,I, , , , , , , ,Z, , , , , ), NULL, NULL); +SECDB_ATTR(v12_keyClassSigningKey, "signingkey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v12_recoveryType, "recoverytype", String, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v12_recoverySet, "recoveryset", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v12_metadatakeydata, "metadatakeydata", Blob, SecDbFlags( ,L, , , , , , , , , ,E, , , , ), NULL, NULL); + +const SecDbClass v12_backupbags_class = { + .name = CFSTR("backupbags"), + .itemclass = false, + .attrs = { + &v12_backupUUIDPrimary, // primary + &v12_backupBag, + &v12_defaultValue, + 0 + } +}; + +const SecDbClass v12_backupkeyclasssigningkeys_class = { + .name = CFSTR("backupkeyclasssigningkeys"), + .itemclass = false, + .attrs = { + &v10keyclass, // primary + &v12_backupUUIDPrimary, // primary + &v12_keyClassSigningKey, + 0 + } +}; + +const SecDbClass v12_backuprecoverysets_class = { + .name = CFSTR("backuprecoverysets"), + .itemclass = false, + .attrs = { + &v12_backupUUIDPrimary, // primary + &v12_recoveryType, // primary + &v12_recoverySet, + 0 + } +}; + +const SecDbClass v12_metadatakeys_class = { + .name = CFSTR("metadatakeys"), + .itemclass = false, + .attrs = { + &v10keyclass, + &v11_2actualKeyclass, + &v6data, + &v12_metadatakeydata, + 0 + } +}; + +const SecDbClass v12_genp_class = { + .name = CFSTR("genp"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + &v12_backupUUID, + 0 + }, +}; + +const SecDbClass v12_inet_class = { + .name = CFSTR("inet"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + &v12_backupUUID, + 0 + }, +}; + +const SecDbClass v12_cert_class = { + .name = CFSTR("cert"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + &v12_backupUUID, + 0 + }, +}; + +const SecDbClass v12_keys_class = { + .name = CFSTR("keys"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + &v12_backupUUID, + 0 + } +}; + +const SecDbClass v11_6_ckstate_class = { + .name = CFSTR("ckstate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10ckzonecreated, + &v10ckzonesubscribed, + &v10lastfetchtime, + &v10changetoken, + &v10ratelimiter, + &v10_4lastFixup, + &v11_6moreComing, + 0 + } +}; + +const SecDbClass v11_5_ckdevicestate_class = { + .name = CFSTR("ckdevicestate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_2device, + &v11_1osversion, + &v11_1lastunlock, + &v10_2peerid, + &v10_2circleStatus, + &v11_5octagonpeerid, + &v11_5octagonStatus, + &v10_2keyState, + &v10_2currentTLK, + &v10_2currentClassA, + &v10_2currentClassC, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v11_2_metadatakeys_class = { + .name = CFSTR("metadatakeys"), + .itemclass = false, + .attrs = { + &v10keyclass, + &v11_2actualKeyclass, + &v6data, + 0 + } +}; + +const SecDbClass v11_1_ckdevicestate_class = { + .name = CFSTR("ckdevicestate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_2device, + &v11_1osversion, + &v11_1lastunlock, + &v10_2peerid, + &v10_2circleStatus, + &v10_2keyState, + &v10_2currentTLK, + &v10_2currentClassA, + &v10_2currentClassC, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v11_metadatakeys_class = { + .name = CFSTR("metadatakeys"), + .itemclass = false, + .attrs = { + &v10keyclass, + &v6data, + 0 + } +}; + +const SecDbClass v10_5_tlkshare_class = { + .name = CFSTR("tlkshare"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10_5senderPeerID, + &v10_5recvPeerID, + &v10_5recvPubKey, + &v10_5curve, + &v10_5poisoned, + &v10_5epoch, + &v10wrappedkey, + &v10_5signature, + &v10_1encRecord, + &v10_5version, + 0 + } +}; + + +const SecDbClass v10_4_current_item_class = { + .name = CFSTR("currentitems"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_1currentPtrIdentifier, + &v10_4currentItemUUID, + &v10state, + &v10encodedCKRecord, + 0 + } +}; + +const SecDbClass v10_4_ckstate_class = { + .name = CFSTR("ckstate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10ckzonecreated, + &v10ckzonesubscribed, + &v10lastfetchtime, + &v10changetoken, + &v10ratelimiter, + &v10_4lastFixup, + 0 + } +}; + +const SecDbClass v10_3_ckdevicestate_class = { + .name = CFSTR("ckdevicestate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_2device, + &v10_2peerid, + &v10_2circleStatus, + &v10_2keyState, + &v10_2currentTLK, + &v10_2currentClassA, + &v10_2currentClassC, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_2_ckmanifest_class = { + .name = CFSTR("ckmanifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_2currentItems, + &v10_2futureData, + &v10_2schema, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_2_pending_manifest_class = { + .name = CFSTR("pending_manifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_2currentItems, + &v10_2futureData, + &v10_2schema, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmanifest_class = { + .name = CFSTR("ckmanifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_pending_manifest_class = { + .name = CFSTR("pending_manifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmanifest_leaf_class = { + .name = CFSTR("ckmanifest_leaf"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10_1digest, + &v10_1entryDigests, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_pending_manifest_leaf_class = { + .name = CFSTR("pending_manifest_leaf"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10_1digest, + &v10_1entryDigests, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_genp_class = { + .name = CFSTR("genp"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + 0 + }, +}; + +const SecDbClass v10_1_inet_class = { + .name = CFSTR("inet"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + 0 + }, +}; + +const SecDbClass v10_1_cert_class = { + .name = CFSTR("cert"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + 0 + }, +}; + +const SecDbClass v10_1_keys_class = { + .name = CFSTR("keys"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, + 0 + } +}; + +const SecDbClass v10_0_tversion_class = { + .name = CFSTR("tversion"), + .itemclass = false, + .attrs = { + &v6rowid, + &v6version, + &v91minor, + 0 + } +}; + +const SecDbClass v10_2_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1optionalEncodedCKRecord, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_2_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1optionalEncodedCKRecord, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + + +const SecDbClass v10_1_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_1_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + + +const SecDbClass v10_0_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_sync_key_class = { + .name = CFSTR("synckeys"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10keyclass, + &v10currentkey, + &v10parentKeyUUID, + &v10state, + &v10wrappedkey, + &v10encodedCKRecord, + 0 + } +}; + +// Stores the "Current Key" records, and parentKeyUUID refers to items in the synckeys table +// Wouldn't foreign keys be nice? +const SecDbClass v10_0_current_key_class = { + .name = CFSTR("currentkeys"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10keyclass, + &v10currentKeyUUID, + &v10encodedCKRecord, + 0 + } +}; + +const SecDbClass v10_1_current_item_class = { + .name = CFSTR("currentitems"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_1currentPtrIdentifier, + &v10_1currentItemUUID, + &v10state, + &v10encodedCKRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmirror_class = { + .name = CFSTR("ckmirror"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encodedCKRecord, + &v10encryptionver, + &v10_1wasCurrent, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_0_ckmirror_class = { + .name = CFSTR("ckmirror"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encodedCKRecord, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_ckstate_class = { + .name = CFSTR("ckstate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10ckzonecreated, + &v10ckzonesubscribed, + &v10lastfetchtime, + &v10changetoken, + &v10ratelimiter, + 0 + } +}; + +/* Backup table */ +/* Primary keys: v10primaryKey, v8musr */ +/* This table is currently unused */ +const SecDbClass v10_0_item_backup_class = { + .name = CFSTR("item_backup"), + .itemclass = false, + .attrs = { + &v6rowid, + &v10primaryKey, // Primary key of the original item, from v6v_pk + &v8musr, // + &v6sha1, // Hash of the original item + &v10backupData, // Data wrapped to backup keybag + &v6pkhh, // Hash of the public key of the backup bag [v10publickeyHash] + 0 + } +}; + +/* Backup Keybag table */ +/* Primary keys: v10publickeyHash, v8musr */ +/* This table is currently unused */ +const SecDbClass v10_0_backup_keybag_class = { + .name = CFSTR("backup_keybag"), + .itemclass = false, + .attrs = { + &v6rowid, + &v10publickeyHash, // Hash of the public key of the backup bag + &v8musr, // + &v10publickey, // Public key for the asymmetric backup bag + &v6agrp, // Used for backup agent + 0 + } +}; + +const SecDbClass v10_1_backup_keyarchive_class = { + .name = CFSTR("backup_keyarchive"), + .itemclass = false, + .attrs = { + &v10_1keyArchiveHash, // Hash of the key archive + &v8musr, // + &v10_1keyArchive, // Serialised key archive + &v10ckzone, + &v10_1optionalEncodedCKRecord, + &v10_1archiveEscrowID, + 0 + } +}; + +const SecDbClass v10_1_current_archived_keys_class = { + .name = CFSTR("archived_key_backup"), + .itemclass = false, + .attrs = { + &v6pdmn, + &v10syncuuid, + &v8musr, + &v6agrp, + &v10_1keyArchiveHash, + &v10_1archivedKey, + &v10ckzone, + &v10_1optionalEncodedCKRecord, + &v10_1archiveEscrowID, + 0 + } +}; + +const SecDbClass v10_1_current_keyarchive_class = { + .name = CFSTR("currentkeyarchives"), + .itemclass = false, + .attrs = { + &v10_1keyArchiveHash, + &v10_1keyArchiveName, + 0 + } +}; + +/* An identity which is really a cert + a key, so all cert and keys attrs are + allowed. */ +const SecDbClass v_identity_class = { + .name = CFSTR("idnt"), + .itemclass = true, + .attrs = { + 0 + }, +}; + +/* + * Version 12.0 + * Add backup/restore mechanism + */ +const SecDbSchema v12_0_schema = { + .majorVersion = 12, + .minorVersion = 0, + .classes = { + &v12_genp_class, + &v12_inet_class, + &v12_cert_class, + &v12_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v11_6_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_5_ckdevicestate_class, + &v10_5_tlkshare_class, + &v12_metadatakeys_class, + &v12_backupbags_class, + &v12_backupkeyclasssigningkeys_class, + &v12_backuprecoverysets_class, + 0 + } +}; + +/* + * Version 11.6 (Add 'moreComing' field to zone state) + */ +const SecDbSchema v11_6_schema = { + .majorVersion = 11, + .minorVersion = 6, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v11_6_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_5_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + +/* + * Version 11.5 (Add octagon fields to device state) + */ +const SecDbSchema v11_5_schema = { + .majorVersion = 11, + .minorVersion = 5, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_5_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + + +/* + * Version 11.4 (Add some more indexes) + */ +const SecDbSchema v11_4_schema = { + .majorVersion = 11, + .minorVersion = 4, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_1_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + +/* + * Version 11.3 (no changes, restores the use of indexes in upgrade code. Gotta go fast!) + */ +const SecDbSchema v11_3_schema = { + .majorVersion = 11, + .minorVersion = 3, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_1_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + +/* + * Version 11.2 + */ +const SecDbSchema v11_2_schema = { + .majorVersion = 11, + .minorVersion = 2, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_1_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + +/* + * Version 11.1 + */ +const SecDbSchema v11_1_schema = { + .majorVersion = 11, + .minorVersion = 1, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_1_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_metadatakeys_class, + 0 + } +}; + +/* + * Version 11 + */ +const SecDbSchema v11_schema = { + .majorVersion = 11, + .minorVersion = 0, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v10_3_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_metadatakeys_class, + 0 + } +}; + + +/* + * Version 10.5 + */ +const SecDbSchema v10_5_schema = { + .majorVersion = 10, + .minorVersion = 5, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v10_3_ckdevicestate_class, + &v10_5_tlkshare_class, + 0 + } +}; + +/* + * Version 10.4 + */ +const SecDbSchema v10_4_schema = { + .majorVersion = 10, + .minorVersion = 4, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_4_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v10_3_ckdevicestate_class, + 0 + } +}; + +/* + * Version 10.3 + */ +const SecDbSchema v10_3_schema = { + .majorVersion = 10, + .minorVersion = 3, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_1_current_item_class, + &v10_3_ckdevicestate_class, + 0 + } +}; + +/* + * Version 10.2 + */ +const SecDbSchema v10_2_schema = { + .majorVersion = 10, + .minorVersion = 2, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_1_current_item_class, + 0 + } +}; + +/* + * Version 10.1 + */ +const SecDbSchema v10_1_schema = { + .majorVersion = 10, + .minorVersion = 1, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_1_outgoing_queue_class, + &v10_1_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_1_ckmanifest_class, + &v10_1_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_1_current_item_class, + 0 + } +}; + +/* + * Version 10.0 + */ + +const SecDbClass v10_0_genp_class = { + .name = CFSTR("genp"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_inet_class = { + .name = CFSTR("inet"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_cert_class = { + .name = CFSTR("cert"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_keys_class = { + .name = CFSTR("keys"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + &v10itemuuid, + &v10itempersistentref, + &v10sysbound, + 0 + } +}; + +const SecDbSchema v10_0_schema = { + .majorVersion = 10, + .minorVersion = 0, + .classes = { + &v10_0_genp_class, + &v10_0_inet_class, + &v10_0_cert_class, + &v10_0_keys_class, + &v10_0_tversion_class, + &v10_0_outgoing_queue_class, + &v10_0_incoming_queue_class, + &v10_0_sync_key_class, + &v10_0_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + 0 + } +}; + +const SecDbClass v9_1_tversion_class = { + .name = CFSTR("tversion91"), + .itemclass = false, + .attrs = { + &v6rowid, + &v6version, + &v91minor, + 0 + } +}; + +const SecDbClass v9_1_genp_class = { + .name = CFSTR("genp91"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9_1_inet_class = { + .name = CFSTR("inet91"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9_1_cert_class = { + .name = CFSTR("cert91"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9_1_keys_class = { + .name = CFSTR("keys91"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + } +}; + +/* + * Version 9.1 (iOS 10.0 and OSX 10.11.8/10.12 addded minor version. + */ +const SecDbSchema v9_1_schema = { + .majorVersion = 9, + .minorVersion = 1, + .classes = { + &v9_1_genp_class, + &v9_1_inet_class, + &v9_1_cert_class, + &v9_1_keys_class, + &v9_1_tversion_class, + 0 + } +}; + +const SecDbClass v9genp_class = { + .name = CFSTR("genp9"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9inet_class = { + .name = CFSTR("inet9"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9cert_class = { + .name = CFSTR("cert9"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v9keys_class = { + .name = CFSTR("keys9"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + } +}; + +const SecDbClass v5tversion_class = { + .name = CFSTR("tversion5"), + .itemclass = false, + .attrs = { + &v6version, + 0 + } +}; + +/* Version 9 (iOS 9.3 and OSX 10.11.5) database schema + * Same contents as v8 tables; table names changed to force upgrade + * and correct default values in table. + */ +const SecDbSchema v9_schema = { + .majorVersion = 9, + .classes = { + &v9genp_class, + &v9inet_class, + &v9cert_class, + &v9keys_class, + &v5tversion_class, + 0 + } +}; + +// Version 8 (Internal release iOS 9.3 and OSX 10.11.5) database schema +const SecDbClass v8genp_class = { + .name = CFSTR("genp8"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v8inet_class = { + .name = CFSTR("inet8"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v8cert_class = { + .name = CFSTR("cert8"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + }, +}; + +const SecDbClass v8keys_class = { + .name = CFSTR("keys8"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + &v8musr, + 0 + } +}; + +const SecDbSchema v8_schema = { + .majorVersion = 8, + .classes = { + &v8genp_class, + &v8inet_class, + &v8cert_class, + &v8keys_class, + &v5tversion_class, + 0 + } +}; + +// Version 7 (iOS 9 and OSX 10.11) database schema +const SecDbClass v7genp_class = { + .name = CFSTR("genp7"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + 0 + }, +}; + +const SecDbClass v7inet_class = { + .name = CFSTR("inet7"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + 0 + }, +}; + +const SecDbClass v7cert_class = { + .name = CFSTR("cert7"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + 0 + }, +}; + +const SecDbClass v7keys_class = { + .name = CFSTR("keys7"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v7vwht, + &v7tkid, + &v6v_Data, + &v6v_pk, + &v6accc, + &v7utomb, + 0 + } +}; + + +const SecDbSchema v7_schema = { + .majorVersion = 7, + .classes = { + &v7genp_class, + &v7inet_class, + &v7cert_class, + &v7keys_class, + &v5tversion_class, + 0 + } +}; + + +// Version 6 (iOS 7 and OSX 10.9) database schema +static const SecDbClass v6genp_class = { + .name = CFSTR("genp6"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v6v_Data, + &v6v_pk, + &v6accc, + 0 + }, +}; + +static const SecDbClass v6inet_class = { + .name = CFSTR("inet6"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v6v_Data, + &v6v_pk, + &v6accc, + 0 + }, +}; + +static const SecDbClass v6cert_class = { + .name = CFSTR("cert6"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v6v_Data, + &v6v_pk, + &v6accc, + 0 + }, +}; + +static const SecDbClass v6keys_class = { + .name = CFSTR("keys6"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6sync, + &v6tomb, + &v6sha1, + &v6v_Data, + &v6v_pk, + &v6accc, + 0 + } +}; + +static const SecDbSchema v6_schema = { + .majorVersion = 6, + .classes = { + &v6genp_class, + &v6inet_class, + &v6cert_class, + &v6keys_class, + &v5tversion_class, + 0 + } +}; + + +// Version 5 (iOS 5 & iOS 6) database schema. +static const SecDbClass v5genp_class = { + .name = CFSTR("genp5"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6svce, + &v6gena, + &v6data, + &v6agrp, + &v6pdmn, + &v6v_Data, + 0 + }, +}; + +static const SecDbClass v5inet_class = { + .name = CFSTR("inet5"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6desc, + &v6icmt, + &v6crtr, + &v6type, + &v6scrp, + &v6labl, + &v6alis, + &v6invi, + &v6nega, + &v6cusi, + &v6prot, + &v6acct, + &v6sdmn, + &v6srvr, + &v6ptcl, + &v6atyp, + &v6port, + &v6path, + &v6data, + &v6agrp, + &v6pdmn, + &v6v_Data, + 0 + }, +}; + +static const SecDbClass v5cert_class = { + .name = CFSTR("cert5"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6ctyp, + &v6cenc, + &v6labl, + &v6certalis, + &v6subj, + &v6issr, + &v6slnr, + &v6skid, + &v6pkhh, + &v6data, + &v6agrp, + &v6pdmn, + &v6v_Data, + 0 + }, +}; + +static const SecDbClass v5keys_class = { + .name = CFSTR("keys5"), + .itemclass = true, + .attrs = { + &v6rowid, + &v6cdat, + &v6mdat, + &v6kcls, + &v6labl, + &v6alis, + &v6perm, + &v6priv, + &v6modi, + &v6klbl, + &v6atag, + &v6keycrtr, + &v6keytype, + &v6bsiz, + &v6esiz, + &v6sdat, + &v6edat, + &v6sens, + &v6asen, + &v6extr, + &v6next, + &v6encr, + &v6decr, + &v6drve, + &v6sign, + &v6vrfy, + &v6snrc, + &v6vyrc, + &v6wrap, + &v6unwp, + &v6data, + &v6agrp, + &v6pdmn, + &v6v_Data, + 0 + } +}; + +static const SecDbSchema v5_schema = { + .majorVersion = 5, + .classes = { + &v5genp_class, + &v5inet_class, + &v5cert_class, + &v5keys_class, + &v5tversion_class, + 0 + } +}; + +SecDbSchema const * const * kc_schemas = NULL; + +const SecDbSchema *v10_kc_schemas_dev[] = { + &v12_0_schema, + &v11_6_schema, + &v11_5_schema, + &v11_4_schema, + &v11_3_schema, + &v11_2_schema, + &v11_1_schema, + &v11_schema, + &v10_5_schema, + &v10_4_schema, + &v10_3_schema, + &v10_2_schema, + &v10_1_schema, + &v10_0_schema, + &v9_1_schema, + &v9_schema, + &v8_schema, + &v7_schema, + &v6_schema, + &v5_schema, + 0 +}; + +const SecDbSchema *v10_kc_schemas[] = { + &v11_6_schema, + &v11_5_schema, + &v11_4_schema, + &v11_3_schema, + &v11_2_schema, + &v11_1_schema, + &v11_schema, + &v10_5_schema, + &v10_4_schema, + &v10_3_schema, + &v10_2_schema, + &v10_1_schema, + &v10_0_schema, + &v9_1_schema, + &v9_schema, + &v8_schema, + &v7_schema, + &v6_schema, + &v5_schema, + 0 +}; + +const SecDbSchema * const * all_schemas() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (checkV12DevEnabled()) { + secwarning("SecItemSchema: v12 development enabled, returning experimental schema"); + } else { + secnotice("SecItemSchema", "v12 development disabled, returning production schemas"); + } + }); + if (checkV12DevEnabled() != 0) { + return v10_kc_schemas_dev; + } else { + return v10_kc_schemas; + } +} + +const SecDbSchema* current_schema() { + // For now, the current schema is the first in the list. + return all_schemas()[0]; +} + +// class accessors for current schema. +static const SecDbClass* find_class(const SecDbSchema* schema, CFStringRef class_name) { + for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { + if( CFEqualSafe((*pclass)->name, class_name) ) { + return *pclass; + } + } + return NULL; +} + +const SecDbClass* genp_class() { + static const SecDbClass* genp = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + genp = find_class(current_schema(), CFSTR("genp")); + }); + return genp; +} +const SecDbClass* inet_class() { + static const SecDbClass* inet = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + inet = find_class(current_schema(), CFSTR("inet")); + }); + return inet; +} +const SecDbClass* cert_class() { + static const SecDbClass* cert = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cert = find_class(current_schema(), CFSTR("cert")); + }); + return cert; +} +const SecDbClass* keys_class() { + static const SecDbClass* keys = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + keys = find_class(current_schema(), CFSTR("keys")); + }); + return keys; +} + +// Not really a class per-se +const SecDbClass* identity_class() { + return &v_identity_class; +} + +// Class with 1 element in it which is the database version-> +const SecDbClass* tversion_class() { + static const SecDbClass* tversion = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + tversion = find_class(current_schema(), CFSTR("tversion")); + }); + return tversion; +} + + diff --git a/keychain/securityd/SecItemSchema.h b/keychain/securityd/SecItemSchema.h new file mode 100644 index 00000000..adbcd3fc --- /dev/null +++ b/keychain/securityd/SecItemSchema.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemSchema.h - The thing that does the stuff with the gibli. + */ + +#ifndef _SECURITYD_SECITEMSCHEMA_H_ +#define _SECURITYD_SECITEMSCHEMA_H_ + +#include "keychain/securityd/SecDbItem.h" + +__BEGIN_DECLS + +const SecDbSchema* current_schema(void); +const SecDbSchema * const * all_schemas(void); + +// class accessors for current schema +const SecDbClass* genp_class(void); +const SecDbClass* inet_class(void); +const SecDbClass* cert_class(void); +const SecDbClass* keys_class(void); + +// Not really a class per-se +const SecDbClass* identity_class(void); + +// Class with 1 element in it which is the database version. +const SecDbClass* tversion_class(void); + +// Direct attribute accessors +// If you change one of these, update it here +extern const SecDbAttr v6v_Data; + +extern const SecDbAttr v6agrp; +extern const SecDbAttr v6desc; +extern const SecDbAttr v6svce; +extern const SecDbAttr v7vwht; +extern const SecDbAttr v7tkid; +extern const SecDbAttr v7utomb; +extern const SecDbAttr v8musr; +extern const SecDbAttr v10itemuuid; +extern const SecDbAttr v10itempersistentref; + +// TODO: Directly expose other important attributes like +// kSecItemSyncAttr, kSecItemTombAttr, kSecItemCdatAttr, kSecItemMdatAttr, kSecItemDataAttr +// This will prevent having to do lookups in SecDbItem for things by kind. + +__END_DECLS + +#endif /* _SECURITYD_SECITEMSCHEMA_H_ */ diff --git a/keychain/securityd/SecItemServer.c b/keychain/securityd/SecItemServer.c new file mode 100644 index 00000000..039b8252 --- /dev/null +++ b/keychain/securityd/SecItemServer.c @@ -0,0 +1,3951 @@ +/* + * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecItemServer.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#if TARGET_DARWINOS +#undef OCTAGON +#undef SECUREOBJECTSYNC +#undef SHAREDWEBCREDENTIALS +#endif + +#include "keychain/securityd/SecItemServer.h" + +#include +#include "keychain/securityd/SecItemDataSource.h" +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" +#include +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SOSCloudCircleServer.h" +#include +#include +#include +#include "keychain/securityd/SecDbBackupManager.h" +#import "keychain/SecureObjectSync/SOSChangeTracker.h" +#include "keychain/SecureObjectSync/SOSDigestVector.h" +#include "keychain/SecureObjectSync/SOSEngine.h" +#include +#include +#include +#include +#include +#include + +#include +#import "keychain/ot/OT.h" +#import "keychain/ot/OTConstants.h" +#import "keychain/escrowrequest/EscrowRequestServerHelpers.h" + +#if USE_KEYSTORE + +#if __has_include() +#include +#else +#include "OSX/utilities/SecAKSWrappers.h" +#endif + +#if __has_include() +#include +#endif + +#include + +#endif + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "swcagent_client.h" +#include "SecPLWrappers.h" + +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE +#include +#endif + +#include + + +#include "Analytics/Clients/LocalKeychainAnalytics.h" + +/* Changed the name of the keychain changed notification, for testing */ +static const char *g_keychain_changed_notification = kSecServerKeychainChangedNotification; + +void SecItemServerSetKeychainChangedNotification(const char *notification_name) +{ + g_keychain_changed_notification = notification_name; +} + +void SecKeychainChanged() { + static dispatch_once_t once; + static sec_action_t action; + + dispatch_once(&once, ^{ + action = sec_action_create("SecKeychainChanged", 1); + sec_action_set_handler(action, ^{ + uint32_t result = notify_post(g_keychain_changed_notification); + if (result == NOTIFY_STATUS_OK) + secnotice("item", "Sent %s", g_keychain_changed_notification); + else + secerror("notify_post %s returned: %" PRIu32, g_keychain_changed_notification, result); + }); + }); + + sec_action_perform(action); +} + +/* Return the current database version in *version. */ +bool SecKeychainDbGetVersion(SecDbConnectionRef dbt, int *version, CFErrorRef *error) +{ + __block bool ok = true; + __block CFErrorRef localError = NULL; + __block bool found = false; + + /* + * First check for the version table itself + */ + + ok &= SecDbPrepare(dbt, CFSTR("SELECT name FROM sqlite_master WHERE type='table' AND name='tversion'"), &localError, ^(sqlite3_stmt *stmt) { + ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { + found = true; + *stop = true; + }); + }); + require_action(ok, out, SecDbError(SQLITE_CORRUPT, error, CFSTR("Failed to read sqlite_master table: %@"), localError)); + if (!found) { + secnotice("upgr", "no tversion table, will setup a new database: %@", localError); + *version = 0; + goto out; + } + + /* + * Now build up major.minor + */ + + ok &= SecDbPrepare(dbt, CFSTR("SELECT version FROM tversion"), &localError, ^(sqlite3_stmt *stmt) { + ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { + *version = sqlite3_column_int(stmt, 0); + if (*version) + *stop = true; + }); + }); + if (ok && (*version & 0xffff) >= 9) { + ok &= SecDbPrepare(dbt, CFSTR("SELECT minor FROM tversion WHERE version = ?"), &localError, ^(sqlite3_stmt *stmt) { + ok = SecDbBindInt(stmt, 1, *version, &localError) && + SecDbStep(dbt, stmt, NULL, ^(bool *stop) { + int64_t minor = sqlite3_column_int64(stmt, 0); + *version |= ((minor & 0xff) << 8) | ((minor & 0xff0000) << 8); + *stop = true; + }); + }); + ok = true; + } +out: + secnotice("upgr", "database version is: 0x%08x : %d : %@", *version, ok, localError); + CFReleaseSafe(localError); + + + return ok; +} + +static bool +isClassD(SecDbItemRef item) +{ + CFTypeRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); + + if (CFEqualSafe(accessible, kSecAttrAccessibleAlwaysPrivate) || CFEqualSafe(accessible, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) + return true; + return false; +} + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + +static int64_t +measureDuration(struct timeval *start) +{ + struct timeval stop; + int64_t duration; + + gettimeofday(&stop, NULL); + + duration = (stop.tv_sec-start->tv_sec) * 1000; + duration += (stop.tv_usec / 1000) - (start->tv_usec / 1000); + + return SecBucket2Significant(duration); +} + +static void +measureUpgradePhase1(struct timeval *start, bool success, int64_t itemsMigrated) +{ + int64_t duration = measureDuration(start); + + if (success) { + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration); + } else { + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration); + } +} + +static void +measureUpgradePhase2(struct timeval *start, int64_t itemsMigrated) +{ + int64_t duration = measureDuration(start); + + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-time"), duration); +} +#endif /* TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */ + +static bool DBClassesAreEqual(const SecDbClass* class1, const SecDbClass* class2) +{ + if (CFEqual(class1->name, class2->name) && class1->itemclass == class2->itemclass) { + int attrIndex = 0; + const SecDbAttr* class1Attr = class1->attrs[attrIndex]; + const SecDbAttr* class2Attr = class2->attrs[attrIndex]; + + while (class1Attr && class2Attr) { + if (CFEqual(class1Attr->name, class2Attr->name) && class1Attr->kind == class2Attr->kind && class1Attr->flags == class2Attr->flags && class1Attr->copyValue == class2Attr->copyValue && class1Attr->setValue == class2Attr->setValue) { + attrIndex++; + class1Attr = class1->attrs[attrIndex]; + class2Attr = class2->attrs[attrIndex]; + } + else { + return false; + } + } + + // if everything has checked out to this point, and we've hit the end of both class's attr list, then they're equal + if (class1Attr == NULL && class2Attr == NULL) { + return true; + } + } + + return false; +} + +static bool ShouldRenameTable(const SecDbClass* class1, const SecDbClass* class2, int oldTableVersion) +{ + return oldTableVersion < 10 || !DBClassesAreEqual(class1, class2); +} + +#define SCHEMA_VERSION(schema) ((((schema)->minorVersion) << 8) | ((schema)->majorVersion)) +#define VERSION_MAJOR(version) ((version) & 0xff) +#define VERSION_MINOR(version) (((version) >> 8) & 0xff) +#define VERSION_NEW(version) ((version) & 0xffff) +#define VERSION_OLD(version) (((version) >> 16) & 0xffff) + +// Goes through all tables represented by old_schema and tries to migrate all items from them into new (current version) tables. +static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSchema, CFErrorRef *error) +{ + int oldVersion = SCHEMA_VERSION(oldSchema); + const SecDbSchema *newSchema = current_schema(); + int newVersion = SCHEMA_VERSION(newSchema); + __block bool ok = true; + SecDbClass const *const *oldClass; + SecDbClass const *const *newClass; + SecDbQueryRef query = NULL; + CFMutableStringRef sql = NULL; + SecDbClass* renamedOldClass = NULL; +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + __block int64_t itemsMigrated = 0; + struct timeval start; + + gettimeofday(&start, NULL); +#endif + + // Rename existing tables to names derived from old schema names + sql = CFStringCreateMutable(NULL, 0); + bool oldClassDone = false; + CFMutableArrayRef classIndexesForNewTables = CFArrayCreateMutable(NULL, 0, NULL); + int classIndex = 0; + for (oldClass = oldSchema->classes, newClass = newSchema->classes; + *newClass != NULL; classIndex++, oldClass++, newClass++) { + if (!oldClassDone) { + oldClassDone |= (*oldClass) == NULL; // Check if the new schema has more tables than the old + } + + if (!oldClassDone && !CFEqual((*oldClass)->name, (*newClass)->name) && ShouldRenameTable(*oldClass, *newClass, oldSchema->majorVersion)) { + CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + + } else if (!oldClassDone && !DBClassesAreEqual(*oldClass, *newClass)) { + CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + } + + if(oldClassDone && *newClass) { + // These should be no-ops, unless you're upgrading a previously-upgraded database with an invalid version number + CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE IF EXISTS %@;"), (*newClass)->name); + + if (classIndexesForNewTables) { + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + } + } + } + + if(CFStringGetLength(sql) > 0) { + require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1AlterTables, error ? *error : NULL)); + } + CFReleaseNull(sql); + + // Drop indices that that new schemas will use + sql = CFStringCreateMutable(NULL, 0); + for (newClass = newSchema->classes; *newClass != NULL; newClass++) { + SecDbForEachAttrWithMask((*newClass), desc, kSecDbIndexFlag | kSecDbInFlag) { + CFStringAppendFormat(sql, 0, CFSTR("DROP INDEX IF EXISTS %@%@;"), (*newClass)->name, desc->name); + if (desc->kind == kSecDbSyncAttr) { + CFStringAppendFormat(sql, 0, CFSTR("DROP INDEX IF EXISTS %@%@0;"), (*newClass)->name, desc->name); + } + } + } + require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1DropIndices, error ? *error : NULL)); + CFReleaseNull(sql); + + // Create tables for new schema. + require_action_quiet(ok &= SecItemDbCreateSchema(dbt, newSchema, classIndexesForNewTables, false, error), out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1CreateSchema, error ? *error : NULL)); + // Go through all classes of current schema to transfer all items to new tables. + for (oldClass = oldSchema->classes, newClass = newSchema->classes; + *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { + + if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { + continue; + } + + secnotice("upgr", "Upgrading table %@", (*oldClass)->name); + + // Create a new 'old' class with a new 'old' name. + int count = 0; + SecDbForEachAttr(*oldClass, attr) { + count++; + } + if(renamedOldClass) { + CFReleaseNull(renamedOldClass->name); + free(renamedOldClass); + } + renamedOldClass = (SecDbClass*) malloc(sizeof(SecDbClass) + sizeof(SecDbAttr*)*(count+1)); + renamedOldClass->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@_old"), (*oldClass)->name); + renamedOldClass->itemclass = (*oldClass)->itemclass; + for(; count >= 0; count--) { + renamedOldClass->attrs[count] = (*oldClass)->attrs[count]; + } + + // SecDbItemSelect only works for item classes. + if((*oldClass)->itemclass) { + // Prepare query to iterate through all items in cur_class. + if (query != NULL) + query_destroy(query, NULL); + require_quiet(query = query_create(renamedOldClass, SecMUSRGetAllViews(), NULL, error), out); + + ok &= SecDbItemSelect(query, dbt, error, ^bool(const SecDbAttr *attr) { + // We are interested in all attributes which are physically present in the DB. + return (attr->flags & kSecDbInFlag) != 0; + }, ^bool(const SecDbAttr *attr) { + // No filtering please. + return false; + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + CFErrorRef localError = NULL; + + #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + itemsMigrated++; + #endif + // Switch item to the new class. + item->class = *newClass; + + if (isClassD(item)) { + // Decrypt the item. + ok &= SecDbItemEnsureDecrypted(item, true, &localError); + require_quiet(ok, out); + + // Delete SHA1 field from the item, so that it is newly recalculated before storing + // the item into the new table. + require_quiet(ok &= SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), + kCFNull, error), out); + } else { + // Leave item encrypted, do not ever try to decrypt it since it will fail. + item->_edataState = kSecDbItemAlwaysEncrypted; + } + // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute + // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. + // + if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) && + SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) { + secnotice("upgr", "dropping item during schema upgrade due to agrp=com.apple.token: %@", item); + } else { + // Insert new item into the new table. + if (!SecDbItemInsert(item, dbt, &localError)) { + secerror("item: %@ insert during upgrade: %@", item, localError); + ok = false; + } + } + + out: + if (localError) { + OSStatus status = SecErrorGetOSStatus(localError); + + switch (status) { + // continue to upgrade and don't propagate errors for insert failures + // that are typical of a single item failure + case errSecDecode: + case errSecDuplicateItem: + ok = true; + break; + case errSecInteractionNotAllowed: + case errSecAuthNeeded: + ok = true; + break; + // This does not mean the keychain is hosed, we just can't use it right now +#if USE_KEYSTORE + case kAKSReturnNotReady: + case kAKSReturnTimeout: +#endif + case errSecNotAvailable: + secnotice("upgr", "Bailing in phase 1 because AKS is unavailable: %@", localError); + // FALLTHROUGH + default: + ok &= CFErrorPropagate(CFRetainSafe(localError), error); + break; + } + CFReleaseSafe(localError); + } + + *stop = !ok; + + }); + + require_action_quiet(ok, out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1Items, error ? *error : NULL)); + } else { + // This table does not contain secdb items, and must be transferred without using SecDbItemSelect. + // For now, this code does not support removing or renaming any columns, or adding any new non-null columns. + CFReleaseNull(sql); + sql = CFStringCreateMutable(NULL, 0); + bool comma = false; + + CFMutableStringRef columns = CFStringCreateMutable(NULL, 0); + + SecDbForEachAttr(renamedOldClass, attr) { + if(comma) { + CFStringAppendFormat(columns, NULL, CFSTR(",")); + } + CFStringAppendFormat(columns, NULL, CFSTR("%@"), attr->name); + comma = true; + } + + CFStringAppendFormat(sql, NULL, CFSTR("INSERT OR REPLACE INTO %@ (%@) SELECT %@ FROM %@;"), (*newClass)->name, columns, columns, renamedOldClass->name); + + CFReleaseNull(columns); + require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1NonItems, error ? *error : NULL)); + } + } + + // Remove old tables from the DB. + CFReleaseNull(sql); + sql = CFStringCreateMutable(NULL, 0); + for (oldClass = oldSchema->classes, newClass = newSchema->classes; + *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { + if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { + continue; + } + + CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE %@_old;"), (*oldClass)->name); + } + + if(CFStringGetLength(sql) > 0) { + require_action_quiet(ok &= SecDbExec(dbt, sql, error), out, + LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase1DropOld, error ? *error : NULL)); + } +out: +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + measureUpgradePhase1(&start, ok, SecBucket2Significant(itemsMigrated)); +#endif + + if (query != NULL) { + query_destroy(query, NULL); + } + CFReleaseSafe(sql); + CFReleaseNull(classIndexesForNewTables); + if(renamedOldClass) { + CFReleaseNull(renamedOldClass->name); + free(renamedOldClass); + } + return ok; +} + +__thread SecDbConnectionRef threadDbt = NULL; + +// Goes through all tables represented by old_schema and tries to migrate all items from them into new (current version) tables. +static bool UpgradeItemPhase2(SecDbConnectionRef inDbt, bool *inProgress, int oldVersion, CFErrorRef *error) { + SecDbConnectionRef oldDbt = threadDbt; + threadDbt = inDbt; + __block bool ok = true; + SecDbQueryRef query = NULL; +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + __block int64_t itemsMigrated = 0; + struct timeval start; + + gettimeofday(&start, NULL); +#endif + +#if SECDB_BACKUPS_ENABLED + CFErrorRef backuperror = NULL; + if (!SecDbBackupCreateOrLoadBackupInfrastructure(&backuperror)) { + secerror("upgr: failed to create backup infrastructure: %@", backuperror); + } else { + secnotice("upgr", "setup backup infrastructure"); + } +#else + secnotice("upgr", "skipping backup setup for this platform"); +#endif + + // Go through all classes in new schema + const SecDbSchema *newSchema = current_schema(); + int newVersion = SCHEMA_VERSION(newSchema); + for (const SecDbClass *const *class = newSchema->classes; *class != NULL && !*inProgress; class++) { + if(!((*class)->itemclass)) { + //Don't try to decrypt non-item 'classes' + continue; + } + + const SecDbAttr *pdmn = SecDbClassAttrWithKind(*class, kSecDbAccessAttr, error); + if (pdmn == nil) { + continue; + } + + // Prepare query to go through all non-DK|DKU items + if (query != NULL) { + query_destroy(query, NULL); + } + require_action_quiet(query = query_create(*class, SecMUSRGetAllViews(), NULL, error), out, ok = false); + ok &= SecDbItemSelect(query, threadDbt, error, NULL, ^bool(const SecDbAttr *attr) { + // No simple per-attribute filtering. + return false; + }, ^bool(CFMutableStringRef sql, bool *needWhere) { + // Select only non-D-class items + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppendFormat(sql, NULL, CFSTR("NOT %@ IN (?,?)"), pdmn->name); + return true; + }, ^bool(sqlite3_stmt *stmt, int col) { + return SecDbBindObject(stmt, col++, kSecAttrAccessibleAlwaysPrivate, error) && + SecDbBindObject(stmt, col++, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, error); + }, ^(SecDbItemRef item, bool *stop) { + CFErrorRef localError = NULL; + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + itemsMigrated++; +#endif + + // Decrypt the item. + if (SecDbItemEnsureDecrypted(item, true, &localError)) { + + // Delete SHA1 field from the item, so that it is newly recalculated before storing + // the item into the new table. + require_quiet(ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), + kCFNull, &localError), out); + // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute + // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. + // + if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) && + SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) { + secnotice("upgr", "dropping item during item upgrade due to agrp=com.apple.token: %@", item); + ok = SecDbItemDelete(item, threadDbt, kCFBooleanFalse, &localError); + } else { + // Replace item with the new value in the table; this will cause the item to be decoded and recoded back, + // incl. recalculation of item's hash. + ok = SecDbItemUpdate(item, item, threadDbt, false, query->q_uuid_from_primary_key, &localError); + } + } + + if (localError) { + CFIndex status = CFErrorGetCode(localError); + + switch (status) { + case errSecDecode: { + // Items producing errSecDecode are silently dropped - they are not decodable and lost forever. + // make sure we use a local error so that this error is not proppaged upward and cause a + // migration failure. + CFErrorRef deleteError = NULL; + (void)SecDbItemDelete(item, threadDbt, false, &deleteError); + CFReleaseNull(deleteError); + ok = true; + break; + } + case errSecInteractionNotAllowed: + // If we are still not able to decrypt the item because the class key is not released yet, + // remember that DB still needs phase2 migration to be run next time a connection is made. Also + // stop iterating next items, it would be just waste of time because the whole iteration will be run + // next time when this phase2 will be rerun. + LKAReportKeychainUpgradeOutcome(oldVersion, newVersion, LKAKeychainUpgradeOutcomeLocked); + *inProgress = true; + *stop = true; + ok = true; + break; + case errSecAuthNeeded: + // errSecAuthNeeded means that it is an ACL-based item which requires authentication (or at least + // ACM context, which we do not have). + ok = true; + break; + case SQLITE_CONSTRAINT: // yeah... + if (!CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) { + secerror("Received SQLITE_CONSTRAINT with wrong error domain. Huh? Item: %@, error: %@", item, localError); + break; + } + case errSecDuplicateItem: + // continue to upgrade and don't propagate errors for insert failures + // that are typical of a single item failure + secnotice("upgr", "Ignoring duplicate item: %@", item); + secdebug("upgr", "Duplicate item error: %@", localError); + ok = true; + break; +#if USE_KEYSTORE + case kAKSReturnNotReady: + case kAKSReturnTimeout: +#endif + case errSecNotAvailable: + *inProgress = true; // We're not done, call me again later! + secnotice("upgr", "Bailing in phase 2 because AKS is unavailable: %@", localError); + // FALLTHROUGH + default: + // Other errors should abort the migration completely. + ok = CFErrorPropagate(CFRetainSafe(localError), error); + break; + } + } + + out: + CFReleaseSafe(localError); + *stop = *stop || !ok; + + }); + require_action(ok, out, LKAReportKeychainUpgradeOutcomeWithError(oldVersion, newVersion, LKAKeychainUpgradeOutcomePhase2, error ? *error : NULL)); + } + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + measureUpgradePhase2(&start, SecBucket2Significant(itemsMigrated)); +#endif + +out: + if (query != NULL) + query_destroy(query, NULL); + + threadDbt = oldDbt; + return ok; +} + +static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, bool *inProgress, CFErrorRef *error) { + __block bool didPhase2 = false; + __block bool ok = true; + __block CFErrorRef localError = NULL; + + if (error) + *error = NULL; + + const SecDbSchema *newSchema = current_schema(); + int newVersion = SCHEMA_VERSION(newSchema); + bool skipped_upgrade = false; + + // If DB schema is the one we want, we are done. + require_action_quiet(SCHEMA_VERSION(newSchema) != version, out, skipped_upgrade = true); + + // Check if the schema of the database on disk is the same major, but newer version then what we have + // in code, lets just skip this since a newer version of the OS have upgrade it. Since its the same + // major, its a promise that it will be compatible. + if (newSchema->majorVersion == VERSION_MAJOR(version) && newSchema->minorVersion < VERSION_MINOR(version)) { + secnotice("upgr", "skipping upgrade since minor is newer"); + goto out; + } + + ok &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + CFStringRef sql = NULL; + bool didPhase1 = false; + + // Get version again once we start a transaction, someone else might change the migration state. + int version2 = 0; + require_quiet(ok = SecKeychainDbGetVersion(dbt, &version2, &localError), out); + // Check if someone has raced us to the migration of the database + require_action(version == version2, out, CFReleaseNull(localError); ok = true); + + require_quiet(SCHEMA_VERSION(newSchema) != version2, out); + + // If this is empty database, just create table according to schema and be done with it. + require_action_quiet(version2 != 0, out, ok = SecItemDbCreateSchema(dbt, newSchema, NULL, true, &localError); + LKAReportKeychainUpgradeOutcomeWithError(version2, newVersion, LKAKeychainUpgradeOutcomeNewDb, localError)); + + int oldVersion = VERSION_OLD(version2); + version2 = VERSION_NEW(version2); + + require_action_quiet(version2 == SCHEMA_VERSION(newSchema) || oldVersion == 0, out, + ok = SecDbError(SQLITE_CORRUPT, &localError, + CFSTR("Half migrated but obsolete DB found: found 0x%x(0x%x) but 0x%x is needed"), + version2, oldVersion, SCHEMA_VERSION(newSchema)); + LKAReportKeychainUpgradeOutcome(version2, newVersion, LKAKeychainUpgradeOutcomeObsoleteDb)); + + // Check whether we have both old and new tables in the DB. + if (oldVersion == 0) { + // Pure old-schema migration attempt, with full blown table renames etc (a.k.a. phase1) + oldVersion = version2; + version2 = SCHEMA_VERSION(newSchema); + + // Find schema for old database. + const SecDbSchema *oldSchema = NULL; + for (const SecDbSchema * const *pschema = all_schemas(); *pschema; ++pschema) { + if (SCHEMA_VERSION((*pschema)) == oldVersion) { + oldSchema = *pschema; + break; + } + } + + // If we are attempting to upgrade from a version for which we have no schema, fail. + require_action_quiet(oldSchema != NULL, out, + ok = SecDbError(SQLITE_CORRUPT, &localError, CFSTR("no schema for version: 0x%x"), oldVersion); + secerror("no schema for version 0x%x", oldVersion); + LKAReportKeychainUpgradeOutcome(version2, newVersion, LKAKeychainUpgradeOutcomeNoSchema)); + + secnotice("upgr", "Upgrading from version 0x%x to 0x%x", oldVersion, SCHEMA_VERSION(newSchema)); + SecSignpostStart(SecSignpostUpgradePhase1); + require_action(ok = UpgradeSchemaPhase1(dbt, oldSchema, &localError), out, secerror("upgrade: Upgrade phase1 failed: %@", localError)); + SecSignpostStop(SecSignpostUpgradePhase1); + + didPhase1 = true; + } + + { + CFErrorRef phase2Error = NULL; + + SecSignpostStart(SecSignpostUpgradePhase2); + + // Lets try to go through non-D-class items in new tables and apply decode/encode on them + // If this fails the error will be ignored after doing a phase1 since but not in the second + // time when we are doing phase2. + ok = UpgradeItemPhase2(dbt, inProgress, version2, &phase2Error); + if (!ok) { + if (didPhase1) { + *inProgress = true; + ok = true; + CFReleaseNull(phase2Error); + } else { + SecErrorPropagate(phase2Error, &localError); + } + } + require_action(ok, out, secerror("upgrade: Upgrade phase2 (%d) failed: %@", didPhase1, localError)); + + if (!*inProgress) { + // If either migration path we did reported that the migration was complete, signalize that + // in the version database by cleaning oldVersion (which is stored in upper halfword of the version) + secnotice("upgr", "Done upgrading from version 0x%x to 0x%x", oldVersion, SCHEMA_VERSION(newSchema)); + oldVersion = 0; + + didPhase2 = true; + SecSignpostStop(SecSignpostUpgradePhase2); + } + } + + // Update database version table. + uint32_t major = (VERSION_MAJOR(version2)) | (VERSION_MAJOR(oldVersion) << 16); + uint32_t minor = (VERSION_MINOR(version2)) | (VERSION_MINOR(oldVersion) << 16); + secnotice("upgr", "Upgrading saving version major 0x%x minor 0x%x", major, minor); + sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("UPDATE tversion SET version='%d', minor='%d'"), + major, minor); + require_action_quiet(ok = SecDbExec(dbt, sql, &localError), out, secerror("upgrade: Setting version failed: %@", localError)); + + out: + if (!ok) { + secerror("upgrade: SecDB upgrade failed: %@", localError); + } + CFReleaseSafe(sql); + *commit = ok; + }); + + if (ok && didPhase2) { +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-success"), 1); +#endif + } + +out: + if (!ok || localError) { + // TODO: This logic should be inverted to a do-not-corrupt-unless default, + /* + * We assume that database is corrupt at this point, but we need to + * check if the error we got isn't severe enough to mark the database as corrupt. + * In those cases we opt out of corrupting the database. + */ + bool markedCorrupt = true; + + if (ok) { + secwarning("upgrade: error has been set but status is true"); + ok = false; + } + secerror("upgrade: error occurred, considering marking database as corrupt: %@", localError); + if (localError) { + CFStringRef domain = CFErrorGetDomain(localError); + CFIndex code = CFErrorGetCode(localError); + + if ((CFEqualSafe(domain, kSecDbErrorDomain) && + ((code & 0xff) == SQLITE_LOCKED || (code & 0xff) == SQLITE_BUSY || (code & 0xff) == SQLITE_FULL)) || +#if USE_KEYSTORE + code == kAKSReturnNotReady || code == kAKSReturnTimeout || +#endif + code == errSecNotAvailable) + { + secerror("upgrade: not marking keychain database corrupt for error: %@", localError); + markedCorrupt = false; + CFReleaseNull(localError); + } else { + secerror("upgrade: unable to complete upgrade, marking DB as corrupt: %@", localError); + } + } else { + secerror("upgrade: unable to complete upgrade and no error object returned, marking DB as corrupt"); + } + if (markedCorrupt) { + secerror("upgrade: marking database as corrupt"); + SecDbCorrupt(dbt, localError); +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-failure"), 1); +#endif + } + } else { + // Things seemed to go okay! + if (didPhase2) { + LKAReportKeychainUpgradeOutcome(version, newVersion, LKAKeychainUpgradeOutcomeSuccess); + } + + //If we're done here, we should opportunistically re-add all indices (just in case) + if(skipped_upgrade || didPhase2) { + // Create indices, ignoring all errors + for (SecDbClass const* const* newClass = newSchema->classes; *newClass; ++newClass) { + SecDbForEachAttrWithMask((*newClass), desc, kSecDbIndexFlag | kSecDbInFlag) { + CFStringRef sql = NULL; + CFErrorRef classLocalError = NULL; + bool localOk = true; + + if (desc->kind == kSecDbSyncAttr) { + // Replace the complete sync index with a partial index for sync=0. Most items are sync=1, so the complete index isn't helpful for sync=1 queries. + sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("DROP INDEX IF EXISTS %@%@; CREATE INDEX IF NOT EXISTS %@%@0 on %@(%@) WHERE %@=0;"), + (*newClass)->name, desc->name, (*newClass)->name, desc->name, (*newClass)->name, desc->name, desc->name); + } else { + sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("CREATE INDEX IF NOT EXISTS %@%@ ON %@(%@);"), (*newClass)->name, desc->name, (*newClass)->name, desc->name); + } + localOk &= SecDbExec(dbt, sql, &classLocalError); + CFReleaseNull(sql); + + if(!localOk) { + secerror("upgrade: unable to opportunistically create index (%@,%@): %@", (*newClass)->name, desc->name, classLocalError); + } + CFReleaseNull(classLocalError); + } + } + } + } + if (localError) { + if (error) { + *error = (CFErrorRef)CFRetain(localError); + } + CFReleaseNull(localError); + } + + return ok; +} + +static bool accessGroupIsNetworkExtensionAndClientIsEntitled(CFStringRef accessGroup, SecurityClient* client) +{ + return client && client->canAccessNetworkExtensionAccessGroups && accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix); +} + +/* AUDIT[securityd](done): + accessGroup (ok) is a caller provided, non NULL CFTypeRef. + + Return true iff accessGroup is allowable according to accessGroups. + */ +bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client) { + /* NULL accessGroups is wildcard. */ + if (!accessGroups) + return true; + /* Make sure we have a string. */ + if (!isString(accessGroup)) + return false; + + /* Having the special accessGroup "*" allows access to all accessGroups. */ + CFRange range = { 0, CFArrayGetCount(accessGroups) }; + if (range.length && + (CFArrayContainsValue(accessGroups, range, accessGroup) || + CFArrayContainsValue(accessGroups, range, CFSTR("*")) || + accessGroupIsNetworkExtensionAndClientIsEntitled(accessGroup, client))) + return true; + + return false; +} + +bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) { + return accessGroupsAllows(accessGroups, + CFDictionaryGetValue(item, kSecAttrAccessGroup), NULL); +} + + +static CF_RETURNS_RETAINED CFDataRef SecServerExportBackupableKeychain(SecDbConnectionRef dbt, + SecurityClient *client, + keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFErrorRef *error) { + CFDataRef data_out = NULL; + + SecSignpostStart(SecSignpostBackupKeychainBackupable); + + /* Export everything except the items for which SecItemIsSystemBound() + returns true. */ + CFDictionaryRef keychain = SecServerCopyKeychainPlist(dbt, client, + src_keybag, dest_keybag, kSecBackupableItemFilter, + error); + if (keychain) { + data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain, + kCFPropertyListBinaryFormat_v1_0, + 0, error); + CFRelease(keychain); + } + SecSignpostStop(SecSignpostBackupKeychainBackupable); + + return data_out; +} + +static bool SecServerImportBackupableKeychain(SecDbConnectionRef dbt, + SecurityClient *client, + keybag_handle_t src_keybag, + keybag_handle_t dest_keybag, + CFDataRef data, + CFErrorRef *error) +{ + return kc_transaction(dbt, error, ^{ + bool ok = false; + CFDictionaryRef keychain; + + SecSignpostStart(SecSignpostRestoreKeychainBackupable); + + keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data, + kCFPropertyListImmutable, NULL, + error); + if (keychain) { + if (isDictionary(keychain)) { + ok = SecServerImportKeychainInPlist(dbt, + client, + src_keybag, + dest_keybag, + keychain, + kSecBackupableItemFilter, + false, // Restoring backup should not remove stuff that got into the keychain before us + error); + } else { + ok = SecError(errSecParam, error, CFSTR("import: keychain is not a dictionary")); + } + CFRelease(keychain); + } + + SecSignpostStop(SecSignpostRestoreKeychainBackupable); + + return ok; + }); +} + +#if USE_KEYSTORE +/* + * Similar to ks_open_keybag, but goes through MKB interface + */ +static bool mkb_open_keybag(CFDataRef keybag, CFDataRef password, MKBKeyBagHandleRef *handle, bool emcs, CFErrorRef *error) { + kern_return_t rc; + MKBKeyBagHandleRef mkbhandle = NULL; + + rc = MKBKeyBagCreateWithData(keybag, &mkbhandle); + if (rc != kMobileKeyBagSuccess) { + return SecKernError(rc, error, CFSTR("MKBKeyBagCreateWithData failed: %d"), rc); + } + + if (!emcs) { + rc = MKBKeyBagUnlock(mkbhandle, password); + if (rc != kMobileKeyBagSuccess) { + CFRelease(mkbhandle); + return SecKernError(rc, error, CFSTR("failed to unlock bag: %d"), rc); + } + } else { + secnotice("keychainbackup", "skipping keybag unlock for EMCS"); + } + + *handle = mkbhandle; + + return true; +} +#endif + + +static CFDataRef SecServerKeychainCreateBackup(SecDbConnectionRef dbt, SecurityClient *client, CFDataRef keybag, + CFDataRef password, bool emcs, CFErrorRef *error) { + CFDataRef backup = NULL; + keybag_handle_t backup_keybag; + + SecSignpostStart(SecSignpostBackupOpenKeybag); + +#if USE_KEYSTORE + MKBKeyBagHandleRef mkbhandle = NULL; + require(mkb_open_keybag(keybag, password, &mkbhandle, emcs, error), out); + + require_noerr(MKBKeyBagGetAKSHandle(mkbhandle, &backup_keybag), out); + +#else + backup_keybag = KEYBAG_NONE; +#endif + SecSignpostStop(SecSignpostBackupOpenKeybag); + SecSignpostStart(SecSignpostBackupKeychain); + + /* Export from system keybag to backup keybag. */ + backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag, error); + +#if USE_KEYSTORE +out: + SecSignpostStop(SecSignpostBackupOpenKeybag); + + if (mkbhandle) + CFRelease(mkbhandle); +#endif + return backup; +} + +static bool SecServerKeychainRestore(SecDbConnectionRef dbt, + SecurityClient *client, + CFDataRef backup, + CFDataRef keybag, + CFDataRef password, + CFErrorRef *error) +{ + bool ok = false; + keybag_handle_t backup_keybag; + + secnotice("SecServerKeychainRestore", "Restoring keychain backup"); + + SecSignpostStart(SecSignpostRestoreOpenKeybag); +#if USE_KEYSTORE + MKBKeyBagHandleRef mkbhandle = NULL; + require(mkb_open_keybag(keybag, password, &mkbhandle, false, error), out); + + require_noerr(MKBKeyBagGetAKSHandle(mkbhandle, &backup_keybag), out); +#else + backup_keybag = KEYBAG_NONE; +#endif + SecSignpostStop(SecSignpostRestoreOpenKeybag); + SecSignpostStart(SecSignpostRestoreKeychain); + + /* Import from backup keybag to system keybag. */ + require(SecServerImportBackupableKeychain(dbt, client, backup_keybag, KEYBAG_DEVICE, backup, error), out); + + ok = true; +out: + SecSignpostStop(SecSignpostRestoreKeychain); +#if USE_KEYSTORE + if (mkbhandle) + CFRelease(mkbhandle); +#endif + + if (ok) { + secnotice("SecServerKeychainRestore", "Restore completed successfully"); + } else { + secwarning("SecServerKeychainRestore: Restore failed with: %@", error ? *error : NULL); + } + + return ok; +} + +// MARK - External SPI support code. + +CFStringRef __SecKeychainCopyPath(void) { + CFStringRef kcRelPath = NULL; + + if (os_variant_is_recovery("securityd")) { + kcRelPath = CFSTR("keychain-recovery-2.db"); + } else if (use_hwaes()) { + kcRelPath = CFSTR("keychain-2.db"); + } else { + kcRelPath = CFSTR("keychain-2-debug.db"); + } + + CFStringRef kcPath = NULL; + CFURLRef kcURL = SecCopyURLForFileInKeychainDirectory(kcRelPath); + if (kcURL) { + kcPath = CFURLCopyFileSystemPath(kcURL, kCFURLPOSIXPathStyle); + CFRelease(kcURL); + } + return kcPath; +} + +// MARK; - +// MARK: kc_dbhandle init and reset + +SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error) { + __block CFErrorRef localerror = NULL; + + SecDbRef kc = SecDbCreate(path, 0600, true, true, true, true, kSecDbMaxIdleHandles, + ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *createError) + { + // Upgrade from version 0 means create the schema in empty db. + int version = 0; + bool ok = true; + if (!didCreate) + ok = SecKeychainDbGetVersion(dbconn, &version, createError); + + ok = ok && SecKeychainDbUpgradeFromVersion(dbconn, version, callMeAgainForNextConnection, createError); + if (!ok) + secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", createError ? *createError : NULL); + + localerror = createError ? *createError : NULL; + + if(ok) { + // This block might get called many, many times due to callMeAgainForNextConnection. + // When we no longer want to be called, we believe we're done. Begin the rest of initialization. + if( !callMeAgainForNextConnection || !(*callMeAgainForNextConnection)) { + SecKeychainDbInitialize(db); + } + } + + return ok; + }); + + if (kc) { + SecDbSetCorruptionReset(kc, ^{ + SecDbResetMetadataKeys(); + }); + } + + if(error) { + *error = localerror; + } + + return kc; +} + +SecDbRef SecKeychainDbInitialize(SecDbRef db) { + +#if OCTAGON + if(SecCKKSIsEnabled()) { + // This needs to be async, otherwise we get hangs between securityd, cloudd, and apsd + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + SecCKKSInitialize(db); + + }); + } + + if(OctagonIsEnabled() && OctagonShouldPerformInitialization()) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + OctagonInitialize(); + }); + } + + if(EscrowRequestServerIsEnabled()) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + EscrowRequestServerInitialize(); + }); + } +#endif + + return db; +} + +static SecDbRef _kc_dbhandle = NULL; +static dispatch_queue_t _kc_dbhandle_dispatch = NULL; +static dispatch_once_t _kc_dbhandle_dispatch_onceToken = 0; +static dispatch_queue_t get_kc_dbhandle_dispatch() { + dispatch_once(&_kc_dbhandle_dispatch_onceToken, ^{ + _kc_dbhandle_dispatch = dispatch_queue_create("sec_kc_dbhandle", DISPATCH_QUEUE_SERIAL); + }); + + return _kc_dbhandle_dispatch; +} + +static bool kc_dbhandle_init(CFErrorRef* error) { + SecDbRef oldHandle = _kc_dbhandle; + _kc_dbhandle = NULL; + CFStringRef dbPath = __SecKeychainCopyPath(); + if (dbPath) { + _kc_dbhandle = SecKeychainDbCreate(dbPath, error); + CFRelease(dbPath); + } else { + secerror("no keychain path available"); + } + if (oldHandle) { + secerror("replaced %@ with %@", oldHandle, _kc_dbhandle); + CFRelease(oldHandle); + } + // Having a dbhandle means we succeeded. + return !!_kc_dbhandle; +} + +static SecDbRef kc_dbhandle(CFErrorRef* error) +{ + dispatch_sync(get_kc_dbhandle_dispatch(), ^{ + if(_kc_dbhandle == NULL) { + _SecDbServerSetup(); + kc_dbhandle_init(error); + } + }); + return _kc_dbhandle; +} + +/* For whitebox testing only */ +void SecKeychainDbReset(dispatch_block_t inbetween) +{ + dispatch_sync(get_kc_dbhandle_dispatch(), ^{ + CFReleaseNull(_kc_dbhandle); + SecDbResetMetadataKeys(); + + if (inbetween) + inbetween(); + }); +} + +static bool kc_acquire_dbt(bool writeAndRead, SecDbConnectionRef* dbconn, CFErrorRef *error) { + SecDbRef db = kc_dbhandle(error); + if (db == NULL) { + if(error && !(*error)) { + SecError(errSecDataNotAvailable, error, CFSTR("failed to get a db handle")); + } + return NULL; + } + + return SecDbConnectionAcquireRefMigrationSafe(db, !writeAndRead, dbconn, error); +} + +/* Return a per thread dbt handle for the keychain. If create is true create + the database if it does not yet exist. If it is false, just return an + error if it fails to auto-create. */ +bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) +{ + return kc_with_custom_db(writeAndRead, true, NULL, error, perform); +} + +bool kc_with_dbt_non_item_tables(bool writeAndRead, CFErrorRef* error, bool (^perform)(SecDbConnectionRef dbt)) +{ + return kc_with_custom_db(writeAndRead, false, NULL, error, perform); +} + +bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) +{ + if (db && db != kc_dbhandle(error)) { + __block bool result = false; + if (writeAndRead) { + SecDbPerformWrite(db, error, ^(SecDbConnectionRef dbconn) { + result = perform(dbconn); + }); + } + else { + SecDbPerformRead(db, error, ^(SecDbConnectionRef dbconn) { + result = perform(dbconn); + }); + } + return result; + } + + if(threadDbt) { + // The kc_with_dbt upthread will clean this up when it's done. + return perform(threadDbt); + } + + if (writeAndRead && usesItemTables) { +#if SECUREOBJECTSYNC + SecItemDataSourceFactoryGetDefault(); +#endif + } + + bool ok = false; + if (kc_acquire_dbt(writeAndRead, &threadDbt, error)) { + ok = perform(threadDbt); + SecDbConnectionRelease(threadDbt); + threadDbt = NULL; + } + return ok; +} + +static bool +items_matching_issuer_parent(SecDbConnectionRef dbt, CFArrayRef accessGroups, CFDataRef musrView, + CFDataRef issuer, CFArrayRef issuers, int recurse) +{ + Query *q; + CFArrayRef results = NULL; + CFIndex i, count; + bool found = false; + + if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer)) + return true; + + /* XXX make musr supported */ + const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrSubject }; + const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, issuer }; + CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL); + + if (!query) + return false; + + CFErrorRef localError = NULL; + q = query_create_with_limit(query, musrView, kSecMatchUnlimited, &localError); + CFRelease(query); + if (q) { + s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError); + query_destroy(q, &localError); + } + if (localError) { + secerror("items matching issuer parent: %@", localError); + CFReleaseNull(localError); + return false; + } + + count = CFArrayGetCount(results); + for (i = 0; (i < count) && !found; i++) { + CFDictionaryRef cert_dict = (CFDictionaryRef)CFArrayGetValueAtIndex(results, i); + CFDataRef cert_issuer = CFDictionaryGetValue(cert_dict, kSecAttrIssuer); + if (CFEqual(cert_issuer, issuer)) + continue; + if (recurse-- > 0) + found = items_matching_issuer_parent(dbt, accessGroups, musrView, cert_issuer, issuers, recurse); + } + CFReleaseSafe(results); + + return found; +} + +static bool +_FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert) +{ + CFDictionaryRef props = NULL; + CFArrayRef keychains = NULL; + CFArrayRef anchors = NULL; + CFArrayRef certs = NULL; + CFArrayRef chain = NULL; + SecTrustRef trust = NULL; + + SecTrustResultType trustResult; + Boolean needChain = false; + __block bool ok = false; + + if (!policy || !cert) return false; + + certs = CFArrayCreate(NULL, (const void **)&cert, (CFIndex)1, &kCFTypeArrayCallBacks); + require_noerr_quiet(SecTrustCreateWithCertificates(certs, policy, &trust), cleanup); + + /* Set evaluation date, if specified (otherwise current date is implied) */ + if (date && (CFGetTypeID(date) == CFDateGetTypeID())) { + require_noerr_quiet(SecTrustSetVerifyDate(trust, date), cleanup); + } + + /* Check whether this is the X509 Basic policy, which means chain building */ + props = SecPolicyCopyProperties(policy); + if (props) { + CFTypeRef oid = (CFTypeRef) CFDictionaryGetValue(props, kSecPolicyOid); + if (oid && (CFEqual(oid, kSecPolicyAppleX509Basic) || + CFEqual(oid, kSecPolicyAppleRevocation))) { + needChain = true; + } + } + + if (!needChain) { + require_noerr_quiet(SecTrustEvaluateLeafOnly(trust, &trustResult), cleanup); + } else { + require_noerr_quiet(SecTrustEvaluate(trust, &trustResult), cleanup); + } + + require_quiet((trustResult == kSecTrustResultProceed || + trustResult == kSecTrustResultUnspecified || + trustResult == kSecTrustResultRecoverableTrustFailure), cleanup); + + ok = true; +#if TARGET_OS_IPHONE + CFArrayRef properties = SecTrustCopyProperties(trust); +#else + CFArrayRef properties = SecTrustCopyProperties_ios(trust); +#endif + if (properties) { + CFArrayForEach(properties, ^(const void *property) { + CFDictionaryForEach((CFDictionaryRef)property, ^(const void *key, const void *value) { + if (CFEqual((CFTypeRef)key, kSecPropertyKeyType) && CFEqual((CFTypeRef)value, kSecPropertyTypeError)) + ok = false; + }); + }); + CFRelease(properties); + } + +cleanup: + if(props) CFRelease(props); + if(chain) CFRelease(chain); + if(anchors) CFRelease(anchors); + if(keychains) CFRelease(keychains); + if(certs) CFRelease(certs); + if(trust) CFRelease(trust); + + return ok; +} + +static bool +_FilterWithDate(CFDateRef validOnDate, SecCertificateRef cert) +{ + if (!validOnDate || !cert) return false; + + CFAbsoluteTime at, nb, na; + at = CFDateGetAbsoluteTime((CFDateRef)validOnDate); + + bool ok = true; + nb = SecCertificateNotValidBefore(cert); + na = SecCertificateNotValidAfter(cert); + + if (nb == 0 || na == 0 || nb == na) { + ok = false; + secnotice("FilterWithDate", "certificate cannot operate"); + } + else if (at < nb) { + ok = false; + secnotice("FilterWithDate", "certificate is not valid yet"); + } + else if (at > na) { + ok = false; + secnotice("FilterWithDate", "certificate expired"); + } + + return ok; +} + +static bool +_FilterWithTrust(Boolean trustedOnly, SecCertificateRef cert) +{ + if (!cert) return false; + if (!trustedOnly) return true; + + bool ok = false; + CFArrayRef certArray = CFArrayCreate(NULL, (const void**)&cert, 1, &kCFTypeArrayCallBacks); + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + require_quiet(policy, out); + + require_noerr_quiet(SecTrustCreateWithCertificates(certArray, policy, &trust), out); + SecTrustResultType trustResult; + require_noerr_quiet(SecTrustEvaluate(trust, &trustResult), out); + + require_quiet((trustResult == kSecTrustResultProceed || + trustResult == kSecTrustResultUnspecified), out); + ok = true; +out: + CFReleaseSafe(trust); + CFReleaseSafe(policy); + CFReleaseSafe(certArray); + return ok; +} + +static SecCertificateRef +CopyCertificateFromItem(Query *q, CFDictionaryRef item) { + SecCertificateRef certRef = NULL; + CFDictionaryRef itemValue = NULL; + + CFTypeRef tokenID = NULL; + CFDataRef certData = NULL; + if (q->q_class == identity_class()) { + certData = CFDictionaryGetValue(item, kSecAttrIdentityCertificateData); + tokenID = CFDictionaryGetValue(item, kSecAttrIdentityCertificateTokenID); + } else if (q->q_class == cert_class()) { + certData = CFDictionaryGetValue(item, kSecValueData); + tokenID = CFDictionaryGetValue(item, kSecAttrTokenID); + } + + require_quiet(certData, out); + if (tokenID != NULL) { + CFErrorRef error = NULL; + itemValue = SecTokenItemValueCopy(certData, &error); + require_action_quiet(itemValue, out, { secerror("function SecTokenItemValueCopy failed with: %@", error); CFReleaseSafe(error); }); + CFDataRef tokenCertData = CFDictionaryGetValue(itemValue, kSecTokenValueDataKey); + require_action_quiet(tokenCertData, out, { secerror("token item doesn't contain token value data");}); + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, tokenCertData); + } + else + certRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData); + +out: + CFReleaseNull(itemValue); + return certRef; +} + +bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item) +{ + bool ok = false; + SecCertificateRef certRef = NULL; + if (q->q_match_issuer) { + CFDataRef issuer = CFDictionaryGetValue(item, kSecAttrIssuer); + if (!items_matching_issuer_parent(dbt, accessGroups, q->q_musrView, issuer, q->q_match_issuer, 10 /*max depth*/)) + return ok; + } + + if (q->q_match_policy && (q->q_class == identity_class() || q->q_class == cert_class())) { + if (!certRef) + certRef = CopyCertificateFromItem(q, item); + require_quiet(certRef, out); + require_quiet(_FilterWithPolicy(q->q_match_policy, q->q_match_valid_on_date, certRef), out); + } + + if (q->q_match_valid_on_date && (q->q_class == identity_class() || q->q_class == cert_class())) { + if (!certRef) + certRef = CopyCertificateFromItem(q, item); + require_quiet(certRef, out); + require_quiet(_FilterWithDate(q->q_match_valid_on_date, certRef), out); + } + + if (q->q_match_trusted_only && (q->q_class == identity_class() || q->q_class == cert_class())) { + if (!certRef) + certRef = CopyCertificateFromItem(q, item); + require_quiet(certRef, out); + require_quiet(_FilterWithTrust(CFBooleanGetValue(q->q_match_trusted_only), certRef), out); + } + + /* Add future match checks here. */ + ok = true; +out: + CFReleaseSafe(certRef); + return ok; +} + +/**************************************************************************** + **************** Beginning of Externally Callable Interface **************** + ****************************************************************************/ + +static bool SecEntitlementError(CFErrorRef *error) +{ +#if TARGET_OS_OSX +#define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.application-identifier nor com.apple.security.application-groups nor keychain-access-groups") +#elif TARGET_OS_IOSMAC +#define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.developer.associated-application-identifier nor application-identifier nor com.apple.security.application-groups nor keychain-access-groups") +#else +#define SEC_ENTITLEMENT_WARNING CFSTR("application-identifier nor keychain-access-groups") +#endif + + return SecError(errSecMissingEntitlement, error, CFSTR("Client has neither %@ entitlements"), SEC_ENTITLEMENT_WARNING); +} + +static bool SecEntitlementErrorForExplicitAccessGroup(CFStringRef agrp, CFArrayRef clientGroups, CFErrorRef* error) +{ + return SecError(errSecMissingEntitlement, error, CFSTR("Client explicitly specifies access group %@ but is only entitled for %@"), agrp, clientGroups); +} + +static CFStringRef CopyAccessGroupForRowID(sqlite_int64 rowID, CFStringRef itemClass) +{ + __block CFStringRef accessGroup = NULL; + + __block CFErrorRef error = NULL; + bool ok = kc_with_dbt(false, &error, ^bool(SecDbConnectionRef dbt) { + CFStringRef table = CFEqual(itemClass, kSecClassIdentity) ? kSecClassCertificate : itemClass; + CFStringRef sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("SELECT agrp FROM %@ WHERE rowid == %u"), table, (unsigned int)rowID); + bool dbOk = SecDbWithSQL(dbt, sql, &error, ^bool(sqlite3_stmt *stmt) { + bool rowOk = SecDbForEach(dbt, stmt, &error, ^bool(int row_index) { + accessGroup = CFStringCreateWithBytes(NULL, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0), kCFStringEncodingUTF8, false); + return accessGroup != NULL; + }); + + return (bool)(rowOk && accessGroup != NULL); + }); + + CFReleaseNull(sql); + return (bool)(dbOk && accessGroup); + }); + + if (ok) { + return accessGroup; + } + else { + CFReleaseNull(accessGroup); + return NULL; + } +} + +/* AUDIT[securityd](done): + query (ok) is a caller provided dictionary, only its cf type has been checked. + */ +static bool +SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, + SecurityClient *client, CFErrorRef *error) +{ + CFArrayRef accessGroups = CFRetainSafe(client->accessGroups); + + CFIndex ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + CFReleaseNull(accessGroups); + return SecEntitlementError(error); + } + + SecSignpostStart(SecSignpostSecItemCopyMatching); + + if (client->canAccessNetworkExtensionAccessGroups) { + CFDataRef persistentRef = CFDictionaryGetValue(query, kSecValuePersistentRef); + CFStringRef itemClass = NULL; + sqlite_int64 itemRowID = 0; + if (persistentRef && _SecItemParsePersistentRef(persistentRef, &itemClass, &itemRowID, NULL)) { + CFStringRef accessGroup = CopyAccessGroupForRowID(itemRowID, itemClass); + if (accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix) && !CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), accessGroup)) { + CFMutableArrayRef mutableAccessGroups = CFArrayCreateMutableCopy(NULL, 0, accessGroups); + CFArrayAppendValue(mutableAccessGroups, accessGroup); + CFReleaseNull(accessGroups); + accessGroups = mutableAccessGroups; + } + CFReleaseNull(accessGroup); + } + } + + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { + /* Having the special accessGroup "*" allows access to all accessGroups. */ + CFReleaseNull(accessGroups); + } + + bool ok = false; + Query *q = query_create_with_limit(query, client->musr, 1, error); + if (q) { + CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup); + if (agrp) { + if (accessGroupsAllows(accessGroups, agrp, client)) { + const void *val = agrp; + CFReleaseNull(accessGroups); + accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks); + } else { + (void)SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); + CFReleaseNull(accessGroups); + query_destroy(q, NULL); + return false; + } + } else { +#if !TARGET_OS_OSX + if (accessGroups != NULL) { + // On iOS, drop 'com.apple.token' AG from allowed accessGroups, to avoid inserting token elements into + // unsuspecting application's keychain. If the application on iOS wants to access token items, it needs + // explicitly specify kSecAttrAccessGroup=kSecAttrAccessGroupToken in its query. + CFMutableArrayRef mutableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, accessGroups); + CFArrayRemoveAllValue(mutableGroups, kSecAttrAccessGroupToken); + CFReleaseNull(accessGroups); + accessGroups = mutableGroups; + } +#endif + } + +#if TARGET_OS_IPHONE + if (q->q_sync_bubble && client->inMultiUser) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCreateSyncBubbleUserUUID(q->q_sync_bubble); + } else if (client->inMultiUser && client->isNetworkExtension) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCreateBothUserAndSystemUUID(client->uid); + } else if (q->q_system_keychain && client->inMultiUser) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCopySystemKeychainUUID(); + } else { + q->q_system_keychain = false; + } +#endif + + query_set_caller_access_groups(q, accessGroups); + + /* Sanity check the query. */ + if (q->q_system_keychain && !client->allowSystemKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); + } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); + } else if (q->q_system_keychain && q->q_sync_bubble) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("can't do both system and syncbubble keychain")); + } else if (q->q_use_item_list) { + ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported")); + } else if (q->q_match_issuer && ((q->q_class != cert_class()) && + (q->q_class != identity_class()))) { + ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute")); + } else if (q->q_match_policy && ((q->q_class != cert_class()) && + (q->q_class != identity_class()))) { + ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported kSecMatchPolicy attribute")); + } else if (q->q_return_type != 0 && result == NULL) { + ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer")); + } else if (!q->q_error) { + ok = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { + return s3dl_copy_matching(dbt, q, result, accessGroups, error); + }); + } + + if (!query_destroy(q, error)) + ok = false; + } + CFReleaseNull(accessGroups); + + SecSignpostStop(SecSignpostSecItemCopyMatching); + + return ok; +} + +bool +_SecItemCopyMatching(CFDictionaryRef query, SecurityClient *client, CFTypeRef *result, CFErrorRef *error) { + return SecItemServerCopyMatching(query, result, client, error); +} + +#if TARGET_OS_IPHONE +static bool +SecItemSynchronizable(CFDictionaryRef query) +{ + bool result = false; + CFTypeRef value = CFDictionaryGetValue(query, kSecAttrSynchronizable); + if (isBoolean(value)) + return CFBooleanGetValue(value); + else if (isNumber(value)) { + SInt32 number = 0; + (void)CFNumberGetValue(value, kCFNumberSInt32Type, &number); + result = !!number; + } + + return result; +} +#endif + +static CFArrayRef +SecurityClientCopyWritableAccessGroups(SecurityClient *client) { + if (client == NULL || client->accessGroups == NULL) { + return NULL; + } + CFIndex count = CFArrayGetCount(client->accessGroups); + if (CFArrayContainsValue(client->accessGroups, CFRangeMake(0, count), kSecAttrAccessGroupToken)) { + CFMutableArrayRef writableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, client->accessGroups); + CFArrayRemoveAllValue(writableGroups, kSecAttrAccessGroupToken); + return writableGroups; + } else { + return CFRetainSafe(client->accessGroups); + } +} + + +/* AUDIT[securityd](done): + attributes (ok) is a caller provided dictionary, only its cf type has + been checked. + */ +bool +_SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *result, CFErrorRef *error) +{ + CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); + + bool ok = true; + CFIndex ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + CFReleaseNull(accessGroups); + return SecEntitlementError(error); + } + + SecSignpostStart(SecSignpostSecItemAdd); + + Query *q = query_create_with_limit(attributes, client->musr, 0, error); + if (q) { + /* Access group sanity checking. */ + CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes, + kSecAttrAccessGroup); + + /* Having the special accessGroup "*" allows access to all accessGroups. */ + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) + CFReleaseNull(accessGroups); + + if (agrp) { + /* The user specified an explicit access group, validate it. */ + if (!accessGroupsAllows(accessGroups, agrp, client)) + ok = SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); + } else { + agrp = (CFStringRef)CFArrayGetValueAtIndex(client->accessGroups, 0); + + /* We are using an implicit access group, add it as if the user + specified it as an attribute. */ + query_add_attribute(kSecAttrAccessGroup, agrp, q); + } + + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("add"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } +#if TARGET_OS_IPHONE + if (q->q_system_keychain && client->inMultiUser) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCopySystemKeychainUUID(); + } else { + q->q_system_keychain = false; + } + query_add_attribute_with_desc(&v8musr, q->q_musrView, q); +#endif + + if (ok) { + query_ensure_access_control(q, agrp); + +#if OCTAGON + void (^add_sync_callback)(bool, CFErrorRef) = CFDictionaryGetValue(attributes, CFSTR("f_ckkscallback")); + if(add_sync_callback) { + // The existence of this callback indicates that we need a predictable UUID for this item. + q->q_uuid_from_primary_key = true; + q->q_add_sync_callback = add_sync_callback; + } +#endif + + if (q->q_system_keychain && !client->allowSystemKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); + } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); +#if TARGET_OS_IPHONE + } else if (q->q_system_keychain && SecItemSynchronizable(attributes) && !client->inMultiUser) { + ok = SecError(errSecInvalidKey, error, CFSTR("Can't store system keychain and synchronizable")); +#endif + } else if (q->q_row_id || q->q_token_object_id) { + ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id")); // TODO: better error string + } else if (!q->q_error) { + ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){ + return kc_transaction(dbt, error, ^{ + query_pre_add(q, true); + return s3dl_query_add(dbt, q, result, error); + }); + }); + } + } + ok = query_notify_and_destroy(q, ok, error); + } else { + ok = false; + } + CFReleaseNull(accessGroups); + + SecSignpostStop(SecSignpostSecItemAdd); + + return ok; +} + +/* AUDIT[securityd](done): + query (ok) and attributesToUpdate (ok) are a caller provided dictionaries, + only their cf types have been checked. + */ +bool +_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, + SecurityClient *client, CFErrorRef *error) +{ + CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); + + CFIndex ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + CFReleaseNull(accessGroups); + return SecEntitlementError(error); + } + + // Queries using implicit access groups which only find items that're inaccessible yield errSecItemNotFound, + // but we can pre-emptively shut down queries which are clearly illegal + CFTypeRef q_agrp = CFDictionaryGetValue(query, kSecAttrAccessGroup); + if (q_agrp && !accessGroupsAllows(accessGroups, q_agrp, client)) { + SecEntitlementErrorForExplicitAccessGroup(q_agrp, accessGroups, error); + CFReleaseSafe(accessGroups); + return false; + } + + SecSignpostStart(SecSignpostSecItemUpdate); + + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("update"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } + + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { + /* Having the special accessGroup "*" allows access to all accessGroups. */ + CFReleaseNull(accessGroups); + } + + bool ok = true; + Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); + if (!q) { + ok = false; + } + if (ok) { +#if TARGET_OS_IPHONE + if (q->q_system_keychain && client->inMultiUser) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCopySystemKeychainUUID(); + } else { + q->q_system_keychain = false; + } +#endif + + /* Sanity check the query. */ + query_set_caller_access_groups(q, accessGroups); + if (q->q_system_keychain && !client->allowSystemKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); + } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); +#if TARGET_OS_IPHONE + } else if (q->q_system_keychain && SecItemSynchronizable(attributesToUpdate) && !client->inMultiUser) { + ok = SecError(errSecInvalidKey, error, CFSTR("Can't update an system keychain item with synchronizable")); +#endif + } else if (q->q_use_item_list) { + ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list not supported")); + } else if (q->q_return_type & kSecReturnDataMask) { + /* Update doesn't return anything so don't ask for it. */ + ok = SecError(errSecReturnDataUnsupported, error, CFSTR("return data not supported by update")); + } else if (q->q_return_type & kSecReturnAttributesMask) { + ok = SecError(errSecReturnAttributesUnsupported, error, CFSTR("return attributes not supported by update")); + } else if (q->q_return_type & kSecReturnRefMask) { + ok = SecError(errSecReturnRefUnsupported, error, CFSTR("return ref not supported by update")); + } else if (q->q_return_type & kSecReturnPersistentRefMask) { + ok = SecError(errSecReturnPersistentRefUnsupported, error, CFSTR("return persistent ref not supported by update")); + } else { + /* Access group sanity checking. */ + CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate, + kSecAttrAccessGroup); + if (agrp) { + /* The user is attempting to modify the access group column, + validate it to make sure the new value is allowable. */ + if (!accessGroupsAllows(accessGroups, agrp, client)) { + secerror("Cannot update keychain item to access group %@", agrp); + ok = SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error); + } + } + } + } + if (ok) { + ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + return s3dl_query_update(dbt, q, attributesToUpdate, accessGroups, error); + }); + }); + } + if (q) { + ok = query_notify_and_destroy(q, ok, error); + } + CFReleaseNull(accessGroups); + + SecSignpostStop(SecSignpostSecItemUpdate); + + return ok; +} + + +/* AUDIT[securityd](done): + query (ok) is a caller provided dictionary, only its cf type has been checked. + */ +bool +_SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error) +{ + CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client); + + CFIndex ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + CFReleaseNull(accessGroups); + return SecEntitlementError(error); + } + + CFTypeRef q_agrp = CFDictionaryGetValue(query, kSecAttrAccessGroup); + if (q_agrp && !accessGroupsAllows(accessGroups, q_agrp, client)) { + SecEntitlementErrorForExplicitAccessGroup(q_agrp, accessGroups, error); + CFReleaseSafe(accessGroups); + return false; + } + + SecSignpostStart(SecSignpostSecItemDelete); + + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("delete"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } + + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { + /* Having the special accessGroup "*" allows access to all accessGroups. */ + CFReleaseNull(accessGroups); + } + + Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); + bool ok; + if (q) { +#if TARGET_OS_IPHONE + if (q->q_system_keychain && client->inMultiUser) { + CFReleaseNull(q->q_musrView); + q->q_musrView = SecMUSRCopySystemKeychainUUID(); + } else { + q->q_system_keychain = false; + } +#endif + + query_set_caller_access_groups(q, accessGroups); + /* Sanity check the query. */ + if (q->q_system_keychain && !client->allowSystemKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); + } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); + } else if (q->q_limit != kSecMatchUnlimited) { + ok = SecError(errSecMatchLimitUnsupported, error, CFSTR("match limit not supported by delete")); + } else if (query_match_count(q) != 0) { + ok = SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported by delete")); + } else if (q->q_ref) { + ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete")); + } else if (q->q_row_id && query_attr_count(q)) { + ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive")); + } else if (q->q_token_object_id && query_attr_count(q) != 1) { + ok = SecError(errSecItemIllegalQuery, error, CFSTR("token persistent ref and other attributes are mutually exclusive")); + } else { + ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + return s3dl_query_delete(dbt, q, accessGroups, error); + }); + }); + } + ok = query_notify_and_destroy(q, ok, error); + } else { + ok = false; + } + CFReleaseNull(accessGroups); + + SecSignpostStop(SecSignpostSecItemDelete); + + return ok; +} + +static bool SecItemDeleteTokenItems(SecDbConnectionRef dbt, CFTypeRef classToDelete, CFTypeRef tokenID, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) { + CFTypeRef keys[] = { kSecClass, kSecAttrTokenID }; + CFTypeRef values[] = { classToDelete, tokenID }; + + CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error); + CFRelease(query); + bool ok; + if (q) { + query_set_caller_access_groups(q, accessGroups); + ok = s3dl_query_delete(dbt, q, accessGroups, error); + ok = query_notify_and_destroy(q, ok, error); + } else { + ok = false; + } + + return ok; +} + +static bool SecItemAddTokenItem(SecDbConnectionRef dbt, CFDictionaryRef attributes, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) { + bool ok = true; + Query *q = query_create_with_limit(attributes, client->musr, 0, error); + if (q) { + CFStringRef agrp = kSecAttrAccessGroupToken; + query_add_attribute(kSecAttrAccessGroup, agrp, q); + + if (ok) { + query_ensure_access_control(q, agrp); + if (q->q_system_keychain && !client->allowSystemKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain")); + } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) { + ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain")); + } else if (q->q_row_id || q->q_token_object_id) { + ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id")); // TODO: better error string + } else if (!q->q_error) { + query_pre_add(q, true); + ok = s3dl_query_add(dbt, q, NULL, error); + } + } + ok = query_notify_and_destroy(q, ok, error); + } else { + return false; + } + return ok; +} + +bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error) { + bool ok = true; + CFArrayRef accessGroups = client->accessGroups; + CFIndex ag_count; + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { + return SecEntitlementError(error); + } + + ok = kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^bool { + if (items) { + const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey }; + for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) { + SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, NULL); + } + + for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { + if (!SecItemAddTokenItem(dbt, CFArrayGetValueAtIndex(items, i), accessGroups, client, error)) + return false; + } + return true; + } + else { + const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey }; + bool deleted = true; + for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) { + if (!SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, error) && error && CFErrorGetCode(*error) != errSecItemNotFound) { + deleted = false; + break; + } + else if (error && *error) { + CFReleaseNull(*error); + } + } + return deleted; + } + }); + }); + + return ok; +} + +static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClass const* class, CFErrorRef* error) { + CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL); + CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); + + __block CFErrorRef localError = NULL; + SecDbQueryRef q = query_create(class, NULL, query, &localError); + if (q == NULL) { // illegal query or out of memory + secerror("SecItemServerDeleteAll: aborting because failed to initialize Query: %@", localError); + abort(); + } + SecDbItemSelect(q, dbt, &localError, ^bool(const SecDbAttr *attr) { + return (attr->flags & kSecDbInFlag) && !CFEqual(attr->name, CFSTR("data")); + }, NULL, NULL, NULL, + ^(SecDbItemRef item, bool *stop) { + if (!SecItemIsSystemBound(item->attributes, class, false) && + !CFEqual(CFDictionaryGetValue(item->attributes, kSecAttrAccessGroup), CFSTR("com.apple.bluetooth"))) + { + SecDbItemDelete(item, dbt, kCFBooleanFalse, &localError); + } + }); + query_destroy(q, &localError); + + if (localError) { + if (error) { + CFReleaseNull(*error); + *error = localError; + } else { + CFReleaseNull(localError); + } + return false; + } + return true; +} + +// Delete all the items except sysbound ones because horrible things happen if you do, like bluetooth devices unpairing +static bool +SecItemServerDeleteAll(CFErrorRef *error) { + secerror("SecItemServerDeleteAll"); + return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) { + return (kc_transaction(dbt, error, ^bool { + bool ok = true; + ok &= SecDbExec(dbt, CFSTR("DELETE FROM genp WHERE sync=1;"), error); + ok &= SecDbExec(dbt, CFSTR("DELETE FROM inet WHERE sync=1;"), error); + ok &= SecDbExec(dbt, CFSTR("DELETE FROM cert WHERE sync=1;"), error); + ok &= SecDbExec(dbt, CFSTR("DELETE FROM keys WHERE sync=1;"), error); + + ok &= deleteNonSysboundItemsForItemClass(dbt, genp_class(), error); + ok &= deleteNonSysboundItemsForItemClass(dbt, inet_class(), error); + ok &= deleteNonSysboundItemsForItemClass(dbt, cert_class(), error); + ok &= deleteNonSysboundItemsForItemClass(dbt, keys_class(), error); + + return ok; + }) && SecDbExec(dbt, CFSTR("VACUUM;"), error)); + }); +} + +bool +_SecItemDeleteAll(CFErrorRef *error) { + return SecItemServerDeleteAll(error); +} + +bool +_SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) +{ + __block bool ok = true; + static dispatch_once_t onceToken; + static CFSetRef illegalAccessGroups = NULL; + + dispatch_once(&onceToken, ^{ + const CFStringRef values[] = { + CFSTR("*"), + CFSTR("apple"), + CFSTR("com.apple.security.sos"), + CFSTR("lockdown-identities"), + }; + illegalAccessGroups = CFSetCreate(NULL, (const void **)values, sizeof(values)/sizeof(values[0]), &kCFTypeSetCallBacks); + }); + + static CFTypeRef qclasses[] = { + NULL, + NULL, + NULL, + NULL + }; + // strange construction needed for schema indirection + static dispatch_once_t qclassesOnceToken; + dispatch_once(&qclassesOnceToken, ^{ + qclasses[0] = inet_class(); + qclasses[1] = genp_class(); + qclasses[2] = keys_class(); + qclasses[3] = cert_class(); + }); + + require_action_quiet(isArray(accessGroups), fail, + ok = false; + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("accessGroups not CFArray, got %@"), accessGroups)); + + // TODO: whitelist instead? look for dev IDs like 7123498YQX.com.somedev.app + + require_action(CFArrayGetCount(accessGroups) != 0, fail, + ok = false; + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("accessGroups e empty"))); + + + // Pre-check accessGroups for prohibited values + CFArrayForEach(accessGroups, ^(const void *value) { + CFStringRef agrp = (CFStringRef)value; + + if (!isString(agrp)) { + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, + CFSTR("access not a string: %@"), agrp); + ok &= false; + } else if (CFSetContainsValue(illegalAccessGroups, agrp)) { + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, + CFSTR("illegal access group: %@"), accessGroups); + ok &= false; + } + }); + require(ok,fail); + + ok = kc_with_dbt(true, error, ^bool(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^bool { + CFErrorRef localError = NULL; + bool ok1 = true; + size_t n; + + for (n = 0; n < sizeof(qclasses)/sizeof(qclasses[0]) && ok1; n++) { + Query *q; + + q = query_create(qclasses[n], client->musr, NULL, error); + require(q, fail2); + + (void)s3dl_query_delete(dbt, q, accessGroups, &localError); + fail2: + query_destroy(q, error); + CFReleaseNull(localError); + } + return ok1; + }) && SecDbExec(dbt, CFSTR("VACUUM"), error); + }); + +fail: + return ok; +} + + +// MARK: - +// MARK: Shared web credentials + +#if SHAREDWEBCREDENTIALS + +/* constants */ +#define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); + +SEC_CONST_DECL (kSecSafariAccessGroup, "com.apple.cfnetwork"); +SEC_CONST_DECL (kSecSafariDefaultComment, "default"); +SEC_CONST_DECL (kSecSafariPasswordsNotSaved, "Passwords not saved"); +SEC_CONST_DECL (kSecSharedCredentialUrlScheme, "https://"); +SEC_CONST_DECL (kSecSharedWebCredentialsService, "webcredentials"); + +#if !TARGET_OS_SIMULATOR +static SWCFlags +_SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error) +{ + __block SWCFlags flags = kSWCFlags_None; + OSStatus status; + + secnotice("swc", "Application %@ is requesting approval for %@", appID, fqdn); + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + if (semaphore == NULL) + return 0; + + status = SWCCheckService(kSecSharedWebCredentialsService, appID, fqdn, ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails) + { + if (inStatus == 0) { + flags = inFlags; + } else { + secerror("SWCCheckService failed with %d", (int)inStatus); + } + dispatch_semaphore_signal(semaphore); + }); + + if (status == 0) { + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + } else { + secerror("SWCCheckService: failed to queue"); + } + dispatch_release(semaphore); + + if (error) { + if (!(flags & kSWCFlag_SiteApproved)) { + SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID); + } else if (flags & kSWCFlag_UserDenied) { + SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID); + } + } + return flags; +} + +static bool +_SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, CFStringRef service) +{ + bool result = false; + CFIndex idx, count = (domains) ? CFArrayGetCount(domains) : (CFIndex) 0; + if (!count || !domain || !service) { + return result; + } + for (idx=0; idx < count; idx++) { + CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx); + if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) { + CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1; + CFIndex substr_len = CFStringGetLength(str) - prefix_len; + CFRange range = { prefix_len, substr_len }; + CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range); + if (substr && CFEqual(substr, domain)) { + result = true; + } + CFReleaseSafe(substr); + if (result) { + break; + } + } + } + return result; +} +#endif /* !TARGET_OS_SIMULATOR */ + +static bool +_SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringRef appID, bool forSafari) +{ +#if !TARGET_OS_SIMULATOR + bool result = false; + if (!fqdn) { return result; } + + // update our database + CFRetainSafe(appID); + CFRetainSafe(fqdn); + if (0 == SWCSetServiceFlags(kSecSharedWebCredentialsService, appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied, + ^void(OSStatus inStatus, SWCFlags inNewFlags){ + CFReleaseSafe(appID); + CFReleaseSafe(fqdn); + })) + { + result = true; + } + else // didn't queue the block + { + CFReleaseSafe(appID); + CFReleaseSafe(fqdn); + } + + if (!forSafari) { return result; } + + // below this point: create a negative Safari web credential item + + CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!attrs) { return result; } + + CFErrorRef error = NULL; + CFStringRef accessGroup = CFSTR("*"); + SecurityClient swcclient = { + .task = NULL, + .accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks), + .allowSystemKeychain = false, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + .musr = client->musr, + }; + + CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup); + CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); + CFDictionaryAddValue(attrs, kSecAttrProtocol, kSecAttrProtocolHTTPS); + CFDictionaryAddValue(attrs, kSecAttrServer, fqdn); + CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue); + + (void)_SecItemDelete(attrs, &swcclient, &error); + CFReleaseNull(error); + + CFDictionaryAddValue(attrs, kSecAttrAccount, kSecSafariPasswordsNotSaved); + CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment); + + CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault, + NULL, CFSTR("%@ (%@)"), fqdn, kSecSafariPasswordsNotSaved); + if (label) { + CFDictionaryAddValue(attrs, kSecAttrLabel, label); + CFReleaseSafe(label); + } + + UInt8 space = ' '; + CFDataRef data = CFDataCreate(kCFAllocatorDefault, &space, 1); + if (data) { + CFDictionarySetValue(attrs, kSecValueData, data); + CFReleaseSafe(data); + } + + CFTypeRef addResult = NULL; + result = _SecItemAdd(attrs, &swcclient, &addResult, &error); + + CFReleaseSafe(addResult); + CFReleaseSafe(error); + CFReleaseSafe(attrs); + CFReleaseSafe(swcclient.accessGroups); + + return result; +#else + return true; +#endif +} + +/* Specialized version of SecItemAdd for shared web credentials */ +bool +_SecAddSharedWebCredential(CFDictionaryRef attributes, + SecurityClient *client, + const audit_token_t *clientAuditToken, + CFStringRef appID, + CFArrayRef domains, + CFTypeRef *result, + CFErrorRef *error) +{ + + SecurityClient swcclient = {}; + + CFStringRef fqdn = CFRetainSafe(CFDictionaryGetValue(attributes, kSecAttrServer)); + CFStringRef account = CFDictionaryGetValue(attributes, kSecAttrAccount); +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE + CFStringRef password = CFDictionaryGetValue(attributes, kSecSharedPassword); +#else + CFStringRef password = CFDictionaryGetValue(attributes, CFSTR("spwd")); +#endif + CFStringRef accessGroup = CFSTR("*"); + CFMutableDictionaryRef query = NULL, attrs = NULL; + SInt32 port = -1; + bool ok = false; + + // check autofill enabled status + if (!swca_autofill_enabled(clientAuditToken)) { + SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings")); + goto cleanup; + } + + // parse fqdn with CFURL here, since it could be specified as domain:port + if (fqdn) { + CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn); + if (urlStr) { + CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil); + if (url) { + CFStringRef hostname = CFURLCopyHostName(url); + if (hostname) { + CFReleaseSafe(fqdn); + fqdn = hostname; + port = CFURLGetPortNumber(url); + } + CFReleaseSafe(url); + } + CFReleaseSafe(urlStr); + } + } + + if (!account) { + SecError(errSecParam, error, CFSTR("No account provided")); + goto cleanup; + } + if (!fqdn) { + SecError(errSecParam, error, CFSTR("No domain provided")); + goto cleanup; + } + +#if TARGET_OS_SIMULATOR + secerror("app/site association entitlements not checked in Simulator"); +#else + OSStatus status = errSecMissingEntitlement; + // validate that fqdn is part of caller's shared credential domains entitlement + if (!appID) { + SecError(status, error, CFSTR("Missing application-identifier entitlement")); + goto cleanup; + } + if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) { + status = errSecSuccess; + } + if (errSecSuccess != status) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains); + if (!msg) { + msg = CFRetain(CFSTR("Requested domain not found in entitlement")); + } + SecError(status, error, CFSTR("%@"), msg); + CFReleaseSafe(msg); + goto cleanup; + } +#endif + +#if TARGET_OS_SIMULATOR + secerror("Ignoring app/site approval state in the Simulator."); +#else + // get approval status for this app/domain pair + SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error); + if (!(flags & kSWCFlag_SiteApproved)) { + goto cleanup; + } +#endif + + // give ourselves access to see matching items for kSecSafariAccessGroup + swcclient.task = NULL; + swcclient.accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks); + swcclient.allowSystemKeychain = false; + swcclient.musr = client->musr; + swcclient.allowSystemKeychain = false; + swcclient.allowSyncBubbleKeychain = false; + swcclient.isNetworkExtension = false; + + + // create lookup query + query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!query) { + SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary")); + goto cleanup; + } + CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(query, kSecAttrAccessGroup, kSecSafariAccessGroup); + CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); + CFDictionaryAddValue(query, kSecAttrServer, fqdn); + CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue); + + // check for presence of Safari's negative entry ('passwords not saved') + CFDictionarySetValue(query, kSecAttrAccount, kSecSafariPasswordsNotSaved); + ok = _SecItemCopyMatching(query, &swcclient, result, error); + if(result) CFReleaseNull(*result); + if (error) CFReleaseNull(*error); + if (ok) { + SecError(errSecDuplicateItem, error, CFSTR("Item already exists for this server")); + goto cleanup; + } + + // now use the provided account (and optional port number, if one was present) + CFDictionarySetValue(query, kSecAttrAccount, account); + if (port < -1 || port > 0) { + SInt16 portValueShort = (port & 0xFFFF); + CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort); + CFDictionaryAddValue(query, kSecAttrPort, portNumber); + CFReleaseSafe(portNumber); + } + + // look up existing password + CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue); + bool matched = _SecItemCopyMatching(query, &swcclient, result, error); + CFDictionaryRemoveValue(query, kSecReturnData); + if (matched) { + // found it, so this becomes either an "update password" or "delete password" operation + bool update = (password != NULL); + if (update) { + attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0); + CFDictionaryAddValue(attrs, kSecValueData, credential); + bool samePassword = result && *result && CFEqual(*result, credential); + CFReleaseSafe(credential); + CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment); + + ok = samePassword || swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error, + ^void (CFStringRef confirm_fqdn) { + _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); + }); + if (ok) { + ok = _SecItemUpdate(query, attrs, &swcclient, error); + } + } + else { + // confirm the delete + // (per rdar://16676288 we always prompt, even if there was prior user approval) + ok = /*approved ||*/ swca_confirm_operation(swca_delete_request_id, clientAuditToken, query, error, + ^void (CFStringRef confirm_fqdn) { + _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); + }); + if (ok) { + ok = _SecItemDelete(query, &swcclient, error); + } + } + + if(result) CFReleaseNull(*result); + if(error) CFReleaseNull(*error); + + goto cleanup; + } + if (result) CFReleaseNull(*result); + if (error) CFReleaseNull(*error); + + // password does not exist, so prepare to add it + if (!password) { + // a NULL password value removes the existing credential. Since we didn't find it, this is a no-op. + ok = true; + goto cleanup; + } + else { + CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ (%@)"), fqdn, account); + if (label) { + CFDictionaryAddValue(query, kSecAttrLabel, label); + CFReleaseSafe(label); + } + // NOTE: we always expect to use HTTPS for web forms. + CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTPS); + + CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0); + CFDictionarySetValue(query, kSecValueData, credential); + CFReleaseSafe(credential); + CFDictionarySetValue(query, kSecAttrComment, kSecSafariDefaultComment); + + CFReleaseSafe(swcclient.accessGroups); + swcclient.accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&kSecSafariAccessGroup, 1, &kCFTypeArrayCallBacks); + + // mark the item as created by this function + const int32_t creator_value = 'swca'; + CFNumberRef creator = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &creator_value); + if (creator) { + CFDictionarySetValue(query, kSecAttrCreator, creator); + CFReleaseSafe(creator); + } + + // confirm the add + ok = swca_confirm_operation(swca_add_request_id, clientAuditToken, query, error, ^void (CFStringRef confirm_fqdn) { + _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false); + }); + } + if (ok) { + ok = _SecItemAdd(query, &swcclient, result, error); + } + +cleanup: + CFReleaseSafe(attrs); + CFReleaseSafe(query); + CFReleaseSafe(swcclient.accessGroups); + CFReleaseSafe(fqdn); + return ok; +} + +/* Specialized version of SecItemCopyMatching for shared web credentials */ +bool +_SecCopySharedWebCredential(CFDictionaryRef query, + SecurityClient *client, + const audit_token_t *clientAuditToken, + CFStringRef appID, + CFArrayRef domains, + CFTypeRef *result, + CFErrorRef *error) +{ + CFMutableArrayRef credentials = NULL; + CFMutableArrayRef foundItems = NULL; + CFMutableArrayRef fqdns = NULL; + CFStringRef fqdn = NULL; + CFStringRef account = NULL; + SInt32 port = -1; + bool ok = false; + + require_quiet(result, cleanup); + credentials = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + foundItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + fqdns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + // give ourselves access to see matching items for kSecSafariAccessGroup + CFStringRef accessGroup = CFSTR("*"); + SecurityClient swcclient = { + .task = NULL, + .accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks), + .allowSystemKeychain = false, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + .musr = client->musr, + }; + + // On input, the query dictionary contains optional fqdn and account entries. + fqdn = CFDictionaryGetValue(query, kSecAttrServer); + account = CFDictionaryGetValue(query, kSecAttrAccount); + + // Check autofill enabled status + if (!swca_autofill_enabled(clientAuditToken)) { + SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings")); + goto cleanup; + } + + // Check fqdn; if NULL, add domains from caller's entitlement. + if (fqdn) { + CFArrayAppendValue(fqdns, fqdn); + } + else if (domains) { + CFIndex idx, count = CFArrayGetCount(domains); + for (idx=0; idx < count; idx++) { + CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx); + // Parse the entry for our service label prefix + if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) { + CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1; + CFIndex substr_len = CFStringGetLength(str) - prefix_len; + CFRange range = { prefix_len, substr_len }; + fqdn = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range); + if (fqdn) { + CFArrayAppendValue(fqdns, fqdn); + CFRelease(fqdn); + } + } + } + } + CFIndex count, idx; + + count = CFArrayGetCount(fqdns); + if (count < 1) { + SecError(errSecParam, error, CFSTR("No domain provided")); + goto cleanup; + } + + // Aggregate search results for each domain + for (idx = 0; idx < count; idx++) { + CFMutableArrayRef items = NULL; + CFMutableDictionaryRef attrs = NULL; + fqdn = (CFStringRef) CFArrayGetValueAtIndex(fqdns, idx); + CFRetainSafe(fqdn); + port = -1; + + // Parse the fqdn for a possible port specifier. + if (fqdn) { + CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn); + if (urlStr) { + CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil); + if (url) { + CFStringRef hostname = CFURLCopyHostName(url); + if (hostname) { + CFReleaseSafe(fqdn); + fqdn = hostname; + port = CFURLGetPortNumber(url); + } + CFReleaseSafe(url); + } + CFReleaseSafe(urlStr); + } + } + +#if TARGET_OS_SIMULATOR + secerror("app/site association entitlements not checked in Simulator"); +#else + OSStatus status = errSecMissingEntitlement; + if (!appID) { + SecError(status, error, CFSTR("Missing application-identifier entitlement")); + CFReleaseSafe(fqdn); + goto cleanup; + } + // validate that fqdn is part of caller's entitlement + if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) { + status = errSecSuccess; + } + if (errSecSuccess != status) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains); + if (!msg) { + msg = CFRetain(CFSTR("Requested domain not found in entitlement")); + } + SecError(status, error, CFSTR("%@"), msg); + CFReleaseSafe(msg); + CFReleaseSafe(fqdn); + goto cleanup; + } +#endif + + attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!attrs) { + SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary")); + CFReleaseSafe(fqdn); + goto cleanup; + } + CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword); + CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup); + CFDictionaryAddValue(attrs, kSecAttrProtocol, kSecAttrProtocolHTTPS); + CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm); + CFDictionaryAddValue(attrs, kSecAttrServer, fqdn); + if (account) { + CFDictionaryAddValue(attrs, kSecAttrAccount, account); + } + if (port < -1 || port > 0) { + SInt16 portValueShort = (port & 0xFFFF); + CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort); + CFDictionaryAddValue(attrs, kSecAttrPort, portNumber); + CFReleaseSafe(portNumber); + } + CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue); + CFDictionaryAddValue(attrs, kSecMatchLimit, kSecMatchLimitAll); + CFDictionaryAddValue(attrs, kSecReturnAttributes, kCFBooleanTrue); + CFDictionaryAddValue(attrs, kSecReturnData, kCFBooleanTrue); + + ok = _SecItemCopyMatching(attrs, &swcclient, (CFTypeRef*)&items, error); + if (count > 1) { + // ignore interim error since we have multiple domains to search + CFReleaseNull(*error); + } + if (ok && items && CFGetTypeID(items) == CFArrayGetTypeID()) { +#if TARGET_OS_SIMULATOR + secerror("Ignoring app/site approval state in the Simulator."); + bool approved = true; +#else + // get approval status for this app/domain pair + SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error); + if (count > 1) { + // ignore interim error since we have multiple domains to check + CFReleaseNull(*error); + } + bool approved = (flags & kSWCFlag_SiteApproved); +#endif + if (approved) { + CFArrayAppendArray(foundItems, items, CFRangeMake(0, CFArrayGetCount(items))); + } + } + CFReleaseSafe(items); + CFReleaseSafe(attrs); + CFReleaseSafe(fqdn); + } + +// If matching credentials are found, the credentials provided to the completionHandler +// will be a CFArrayRef containing CFDictionaryRef entries. Each dictionary entry will +// contain the following pairs (see Security/SecItem.h): +// key: kSecAttrServer value: CFStringRef (the website) +// key: kSecAttrAccount value: CFStringRef (the account) +// key: kSecSharedPassword value: CFStringRef (the password) +// Optional keys: +// key: kSecAttrPort value: CFNumberRef (the port number, if non-standard for https) + + count = CFArrayGetCount(foundItems); + for (idx = 0; idx < count; idx++) { + CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(foundItems, idx); + CFMutableDictionaryRef newdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (newdict && dict && CFGetTypeID(dict) == CFDictionaryGetTypeID()) { + CFStringRef srvr = CFDictionaryGetValue(dict, kSecAttrServer); + CFStringRef acct = CFDictionaryGetValue(dict, kSecAttrAccount); + CFNumberRef pnum = CFDictionaryGetValue(dict, kSecAttrPort); + CFStringRef icmt = CFDictionaryGetValue(dict, kSecAttrComment); + CFDataRef data = CFDictionaryGetValue(dict, kSecValueData); + if (srvr) { + CFDictionaryAddValue(newdict, kSecAttrServer, srvr); + } + if (acct) { + CFDictionaryAddValue(newdict, kSecAttrAccount, acct); + } + if (pnum) { + SInt16 pval = -1; + if (CFNumberGetValue(pnum, kCFNumberSInt16Type, &pval) && + (pval < -1 || pval > 0)) { + CFDictionaryAddValue(newdict, kSecAttrPort, pnum); + } + } + if (data) { + CFStringRef password = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, kCFStringEncodingUTF8); + if (password) { + #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV + CFDictionaryAddValue(newdict, kSecSharedPassword, password); + #else + CFDictionaryAddValue(newdict, CFSTR("spwd"), password); + #endif + CFReleaseSafe(password); + } + } + + if (acct && CFEqual(acct, kSecSafariPasswordsNotSaved)) { + // Do not add to credentials list! + secwarning("copySWC: Skipping \"%@\" item", kSecSafariPasswordsNotSaved); + } else if (icmt && CFEqual(icmt, kSecSafariDefaultComment)) { + CFArrayInsertValueAtIndex(credentials, 0, newdict); + } else { + CFArrayAppendValue(credentials, newdict); + } + } + CFReleaseSafe(newdict); + } + + count = CFArrayGetCount(credentials); + if (count) { + ok = false; + // create a new array of dictionaries (without the actual password) for picker UI + CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + for (idx = 0; idx < count; idx++) { + CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx); + CFMutableDictionaryRef newdict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); + #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV + CFDictionaryRemoveValue(newdict, kSecSharedPassword); + #else + CFDictionaryRemoveValue(newdict, CFSTR("spwd")); + #endif + CFArrayAppendValue(items, newdict); + CFReleaseSafe(newdict); + } + + // prompt user to select one of the dictionary items + CFDictionaryRef selected = swca_copy_selected_dictionary(swca_select_request_id, + clientAuditToken, items, error); + if (selected) { + // find the matching item in our credentials array + CFStringRef srvr = CFDictionaryGetValue(selected, kSecAttrServer); + CFStringRef acct = CFDictionaryGetValue(selected, kSecAttrAccount); + CFNumberRef pnum = CFDictionaryGetValue(selected, kSecAttrPort); + for (idx = 0; idx < count; idx++) { + CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx); + CFStringRef srvr1 = CFDictionaryGetValue(dict, kSecAttrServer); + CFStringRef acct1 = CFDictionaryGetValue(dict, kSecAttrAccount); + CFNumberRef pnum1 = CFDictionaryGetValue(dict, kSecAttrPort); + + if (!srvr || !srvr1 || !CFEqual(srvr, srvr1)) continue; + if (!acct || !acct1 || !CFEqual(acct, acct1)) continue; + if ((pnum && pnum1) && !CFEqual(pnum, pnum1)) continue; + + // we have a match! + CFReleaseSafe(selected); + CFRetainSafe(dict); + selected = dict; + ok = true; + break; + } + } + CFReleaseSafe(items); + CFArrayRemoveAllValues(credentials); + if (selected && ok) { +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR + fqdn = CFDictionaryGetValue(selected, kSecAttrServer); +#endif + CFArrayAppendValue(credentials, selected); + } + + if (ok) { +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR + // register confirmation with database + CFRetainSafe(appID); + CFRetainSafe(fqdn); + if (0 != SWCSetServiceFlags(kSecSharedWebCredentialsService, + appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserApproved, + ^void(OSStatus inStatus, SWCFlags inNewFlags){ + CFReleaseSafe(appID); + CFReleaseSafe(fqdn); + })) + { + // we didn't queue the block + CFReleaseSafe(appID); + CFReleaseSafe(fqdn); + } +#endif + } + CFReleaseSafe(selected); + } + else if (NULL == *error) { + // found no items, and we haven't already filled in the error + SecError(errSecItemNotFound, error, CFSTR("no matching items found")); + } + +cleanup: + if (!ok) { + CFArrayRemoveAllValues(credentials); + CFReleaseNull(credentials); + } + CFReleaseSafe(foundItems); + *result = credentials; + CFReleaseSafe(swcclient.accessGroups); + CFReleaseSafe(fqdns); + + return ok; +} + +#endif /* SHAREDWEBCREDENTIALS */ + + +// MARK: - +// MARK: Keychain backup + +CF_RETURNS_RETAINED CFDataRef +_SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error) { + __block CFDataRef backup = NULL; + kc_with_dbt(false, error, ^bool (SecDbConnectionRef dbt) { + + LKABackupReportStart(!!keybag, !!passcode, emcs); + + return kc_transaction_type(dbt, kSecDbNormalTransactionType, error, ^bool{ + secnotice("SecServerKeychainCreateBackup", "Performing backup from %s keybag%s", keybag ? "provided" : "device", emcs ? ", EMCS mode" : ""); + + if (keybag == NULL && passcode == NULL) { +#if USE_KEYSTORE + backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag_handle, error); +#else /* !USE_KEYSTORE */ + (void)client; + SecError(errSecParam, error, CFSTR("Why are you doing this?")); + backup = NULL; +#endif /* USE_KEYSTORE */ + } else { + backup = SecServerKeychainCreateBackup(dbt, client, keybag, passcode, emcs, error); + } + return (backup != NULL); + }); + }); + + secnotice("SecServerKeychainCreateBackup", "Backup result: %s (%@)", backup ? "success" : "fail", error ? *error : NULL); + LKABackupReportEnd(!!backup, error ? *error : NULL); + + return backup; +} + +bool +_SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { + if (backup == NULL || keybag == NULL) + return SecError(errSecParam, error, CFSTR("backup or keybag missing")); + + __block bool ok = true; + ok &= kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbconn) { + return SecServerKeychainRestore(dbconn, client, backup, keybag, passcode, error); + }); + + if (ok) { + SecKeychainChanged(); + } + + return ok; +} + +CFStringRef +_SecServerBackupCopyUUID(CFDataRef data, CFErrorRef *error) +{ + CFStringRef uuid = NULL; + CFDictionaryRef backup; + + backup = CFPropertyListCreateWithData(kCFAllocatorDefault, data, + kCFPropertyListImmutable, NULL, + error); + if (isDictionary(backup)) { + uuid = SecServerBackupGetKeybagUUID(backup, error); + if (uuid) + CFRetain(uuid); + } + CFReleaseNull(backup); + + return uuid; +} + + + +// MARK: - +// MARK: SecItemDataSource + +#if SECUREOBJECTSYNC + +// Make sure to call this before any writes to the keychain, so that we fire +// up the engines to monitor manifest changes. +SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void) { + return SecItemDataSourceFactoryGetShared(kc_dbhandle(NULL)); +} + +/* AUDIT[securityd]: + args_in (ok) is a caller provided, CFDictionaryRef. + */ + +CF_RETURNS_RETAINED CFArrayRef +_SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) { + // This never fails, trust us! + return SOSCCHandleUpdateMessage(updates); +} + +// +// Truthiness in the cloud backup/restore support. +// + +static CFDictionaryRef +_SecServerCopyTruthInTheCloud(CFDataRef keybag, CFDataRef password, + CFDictionaryRef backup, CFErrorRef *error) +{ + SOSManifestRef mold = NULL, mnow = NULL, mdelete = NULL, madd = NULL; + __block CFMutableDictionaryRef backup_new = NULL; + keybag_handle_t bag_handle; + if (!ks_open_keybag(keybag, password, &bag_handle, error)) + return backup_new; + + // We need to have a datasource singleton for protection domain + // kSecAttrAccessibleWhenUnlocked and keep a single shared engine + // instance around which we create in the datasource constructor as well. + SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); + if (ds) { + backup_new = backup ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + mold = SOSCreateManifestWithBackup(backup, error); + SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); + mnow = SOSEngineCopyManifest(engine, NULL); + if (!mnow) { + mnow = SOSDataSourceCopyManifestWithViewNameSet(ds, SOSViewsGetV0ViewSet(), error); + } + if (!mnow) { + CFReleaseNull(backup_new); + secerror("failed to obtain manifest for keychain: %@", error ? *error : NULL); + } else { + SOSManifestDiff(mold, mnow, &mdelete, &madd, error); + } + + // Delete everything from the new_backup that is no longer in the datasource according to the datasources manifest. + SOSManifestForEach(mdelete, ^(CFDataRef digest_data, bool *stop) { + CFStringRef deleted_item_key = CFDataCopyHexString(digest_data); + CFDictionaryRemoveValue(backup_new, deleted_item_key); + CFRelease(deleted_item_key); + }); + + CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + SOSDataSourceForEachObject(ds, NULL, madd, error, ^void(CFDataRef digest, SOSObjectRef object, bool *stop) { + CFErrorRef localError = NULL; + CFDataRef digest_data = NULL; + CFTypeRef value = NULL; + if (!object) { + // Key in our manifest can't be found in db, remove it from our manifest + SOSChangesAppendDelete(changes, digest); + } else if (!(digest_data = SOSObjectCopyDigest(ds, object, &localError)) + || !(value = SOSObjectCopyBackup(ds, object, bag_handle, &localError))) { + if (SecErrorGetOSStatus(localError) == errSecDecode) { + // Ignore decode errors, pretend the objects aren't there + CFRelease(localError); + // Object undecodable, remove it from our manifest + SOSChangesAppendDelete(changes, digest); + } else { + // Stop iterating and propagate out all other errors. + *stop = true; + *error = localError; + CFReleaseNull(backup_new); + } + } else { + // TODO: Should we skip tombstones here? + CFStringRef key = CFDataCopyHexString(digest_data); + CFDictionarySetValue(backup_new, key, value); + CFReleaseSafe(key); + } + CFReleaseSafe(digest_data); + CFReleaseSafe(value); + }) || CFReleaseNull(backup_new); + + if (CFArrayGetCount(changes)) { + if (!SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, error)) { + CFReleaseNull(backup_new); + } + } + CFReleaseSafe(changes); + + SOSDataSourceRelease(ds, error) || CFReleaseNull(backup_new); + } + + CFReleaseSafe(mold); + CFReleaseSafe(mnow); + CFReleaseSafe(madd); + CFReleaseSafe(mdelete); + ks_close_keybag(bag_handle, error) || CFReleaseNull(backup_new); + + return backup_new; +} + +static bool +_SecServerRestoreTruthInTheCloud(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) { + __block bool ok = true; + keybag_handle_t bag_handle; + if (!ks_open_keybag(keybag, password, &bag_handle, error)) + return false; + + SOSManifestRef mbackup = SOSCreateManifestWithBackup(backup_in, error); + if (mbackup) { + SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); + ok &= ds && SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) { + SOSManifestRef mnow = SOSDataSourceCopyManifestWithViewNameSet(ds, SOSViewsGetV0BackupViewSet(), error); + SOSManifestRef mdelete = NULL, madd = NULL; + SOSManifestDiff(mnow, mbackup, &mdelete, &madd, error); + + // Don't delete everything in datasource not in backup. + + // Add items from the backup + SOSManifestForEach(madd, ^void(CFDataRef e, bool *stop) { + CFDictionaryRef item = NULL; + CFStringRef sha1 = CFDataCopyHexString(e); + if (sha1) { + item = CFDictionaryGetValue(backup_in, sha1); + CFRelease(sha1); + } + if (item) { + CFErrorRef localError = NULL; + + if (!SOSObjectRestoreObject(ds, txn, bag_handle, item, &localError)) { + OSStatus status = SecErrorGetOSStatus(localError); + if (status == errSecDuplicateItem) { + // Log and ignore duplicate item errors during restore + secnotice("titc", "restore %@ not replacing existing item", item); + } else if (status == errSecDecode) { + // Log and ignore corrupted item errors during restore + secnotice("titc", "restore %@ skipping corrupted item %@", item, localError); + } else { + if (status == errSecInteractionNotAllowed) + *stop = true; + // Propagate the first other error upwards (causing the restore to fail). + secerror("restore %@ failed %@", item, localError); + ok = false; + if (error && !*error) { + *error = localError; + localError = NULL; + } + } + CFReleaseSafe(localError); + } + } + }); + ok &= SOSDataSourceRelease(ds, error); + CFReleaseNull(mdelete); + CFReleaseNull(madd); + CFReleaseNull(mnow); + }); + CFRelease(mbackup); + } + + ok &= ks_close_keybag(bag_handle, error); + + return ok; +} + + +CF_RETURNS_RETAINED CFDictionaryRef +_SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) { + require_action_quiet(isData(keybag), errOut, SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag)); + require_action_quiet(!backup || isDictionary(backup), errOut, SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup)); + require_action_quiet(!password || isData(password), errOut, SecError(errSecParam, error, CFSTR("password %@ not a data"), password)); + + return _SecServerCopyTruthInTheCloud(keybag, password, backup, error); + +errOut: + return NULL; +} + +bool +_SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) { + bool ok; + require_action_quiet(isData(keybag), errOut, ok = SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag)); + require_action_quiet(isDictionary(backup), errOut, ok = SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup)); + if (password) { + + require_action_quiet(isData(password), errOut, ok = SecError(errSecParam, error, CFSTR("password not a data"))); + } + + ok = _SecServerRestoreTruthInTheCloud(keybag, password, backup, error); + +errOut: + return ok; +} +#endif /* SECUREOBJECTSYNC */ + +bool _SecServerRollKeysGlue(bool force, CFErrorRef *error) { + return _SecServerRollKeys(force, NULL, error); +} + + +bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error) { +#if USE_KEYSTORE + uint32_t keystore_generation_status = 0; + if (aks_generation(KEYBAG_DEVICE, generation_noop, &keystore_generation_status)) + return false; + uint32_t current_generation = keystore_generation_status & generation_current; + + return kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + bool up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL); + + if (force && !up_to_date) { + up_to_date = s3dl_dbt_update_keys(dbt, client, error); + if (up_to_date) { + secerror("Completed roll keys."); + up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL); + } + if (!up_to_date) + secerror("Failed to roll keys."); + } + return up_to_date; + }); +#else + return true; +#endif +} + +static bool +InitialSyncItems(CFMutableArrayRef items, bool limitToCurrent, CFStringRef agrp, CFStringRef svce, const SecDbClass *qclass, CFErrorRef *error) +{ + bool result = false; + Query *q = NULL; + + q = query_create(qclass, NULL, NULL, error); + require(q, fail); + + q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; + q->q_limit = kSecMatchUnlimited; + q->q_keybag = KEYBAG_DEVICE; + + query_add_attribute(kSecAttrAccessGroup, agrp, q); + query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q); + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + if (svce) + query_add_attribute(kSecAttrService, svce, q); + + result = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + CFErrorRef error2 = NULL; + + SecDbItemSelect(q, dbt, &error2, NULL, ^bool(const SecDbAttr *attr) { + return CFDictionaryGetValue(q->q_item, attr->name); + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + CFErrorRef error3 = NULL; + secinfo("InitialSyncItems", "Copy item"); + + CFMutableDictionaryRef attrs = SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &error3); + if (attrs) { + int match = true; + CFStringRef itemvwht = CFDictionaryGetValue(attrs, kSecAttrSyncViewHint); + /* + * Saying its a SOS viewhint is really not the right answer post Triangle + */ + if (isString(itemvwht) && !SOSViewInSOSSystem(itemvwht)) { + match = false; + } + /* + * Here we encode how PCS stores identities so that we only copy the + * current identites for performance reasons. + */ + if (limitToCurrent) { + enum { PCS_CURRENT_IDENTITY_OFFSET = 0x10000 }; + int32_t s32; + + CFNumberRef type = CFDictionaryGetValue(attrs, kSecAttrType); + if (!isNumber(type)) { + // still allow this case since its not a service identity ?? + } else if (!CFNumberGetValue(type, kCFNumberSInt32Type, &s32)) { + match = false; + } else if ((s32 & PCS_CURRENT_IDENTITY_OFFSET) == 0) { + match = false; + } + } + if (match) { + CFDictionaryAddValue(attrs, kSecClass, SecDbItemGetClass(item)->name); + CFArrayAppendValue(items, attrs); + } + + CFReleaseNull(attrs); + } + CFReleaseNull(error3); + }); + CFReleaseNull(error2); + + return (bool)true; + }); + }); + +fail: + if (q) + query_destroy(q, NULL); + return result; +} + +CFArrayRef +_SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error) +{ + CFMutableArrayRef items = CFArrayCreateMutableForCFTypes(NULL); + + if (flags & SecServerInitialSyncCredentialFlagTLK) { + require_action(InitialSyncItems(items, false, CFSTR("com.apple.security.ckks"), NULL, inet_class(), error), fail, + secerror("failed to collect CKKS-inet keys: %@", error ? *error : NULL)); + } + if (flags & SecServerInitialSyncCredentialFlagPCS) { + bool onlyCurrent = !(flags & SecServerInitialSyncCredentialFlagPCSNonCurrent); + + require_action(InitialSyncItems(items, false, CFSTR("com.apple.ProtectedCloudStorage"), NULL, genp_class(), error), fail, + secerror("failed to collect PCS-genp keys: %@", error ? *error : NULL)); + require_action(InitialSyncItems(items, onlyCurrent, CFSTR("com.apple.ProtectedCloudStorage"), NULL, inet_class(), error), fail, + secerror("failed to collect PCS-inet keys: %@", error ? *error : NULL)); + } + if (flags & SecServerInitialSyncCredentialFlagBluetoothMigration) { + require_action(InitialSyncItems(items, false, CFSTR("com.apple.nanoregistry.migration"), NULL, genp_class(), error), fail, + secerror("failed to collect com.apple.nanoregistry.migration-genp item: %@", error ? *error : NULL)); + require_action(InitialSyncItems(items, false, CFSTR("com.apple.nanoregistry.migration2"), NULL, genp_class(), error), fail, + secerror("failed to collect com.apple.nanoregistry.migration2-genp item: %@", error ? *error : NULL)); + require_action(InitialSyncItems(items, false, CFSTR("com.apple.bluetooth"), CFSTR("BluetoothLESync"), genp_class(), error), fail, + secerror("failed to collect com.apple.bluetooth-genp item: %@", error ? *error : NULL)); + + } + +fail: + return items; +} + +bool +_SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error) +{ + return kc_with_dbt(true, error, ^bool(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^bool(void){ + CFIndex n, count = CFArrayGetCount(array); + + secinfo("ImportInitialSyncItems", "Importing %d items", (int)count); + + for (n = 0; n < count; n++) { + CFErrorRef cferror = NULL; + + CFDictionaryRef item = CFArrayGetValueAtIndex(array, n); + if (!isDictionary(item)) + continue; + + CFStringRef className = CFDictionaryGetValue(item, kSecClass); + if (className == NULL) { + secinfo("ImportInitialSyncItems", "Item w/o class"); + continue; + } + + const SecDbClass *cls = kc_class_with_name(className); + if (cls == NULL) { + secinfo("ImportInitialSyncItems", "Item with unknown class: %@", className); + continue; + } + + SecDbItemRef dbi = SecDbItemCreateWithAttributes(NULL, cls, item, KEYBAG_DEVICE, &cferror); + if (dbi == NULL) { + secinfo("ImportInitialSyncItems", "Item creation failed with: %@", cferror); + CFReleaseNull(cferror); + continue; + } + + if (!SecDbItemSetSyncable(dbi, true, &cferror)) { + secinfo("ImportInitialSyncItems", "Failed to set sync=1: %@ for item %@", cferror, dbi); + CFReleaseNull(cferror); + CFReleaseNull(dbi); + continue; + } + + if (!SecDbItemInsert(dbi, dbt, &cferror)) { + secinfo("ImportInitialSyncItems", "Item store failed with: %@: %@", cferror, dbi); + CFReleaseNull(cferror); + } + CFReleaseNull(dbi); + } + return true; + }); + }); +} + + + +#if TARGET_OS_IOS + +/* + * Sync bubble migration code + */ + +struct SyncBubbleRule { + CFStringRef attribute; + CFTypeRef value; +}; + +static bool +TransmogrifyItemsToSyncBubble(SecurityClient *client, uid_t uid, + bool onlyDelete, + bool copyToo, + const SecDbClass *qclass, + struct SyncBubbleRule *items, CFIndex nItems, + CFErrorRef *error) +{ + CFMutableDictionaryRef updateAttributes = NULL; + CFDataRef syncBubbleView = NULL; + CFDataRef activeUserView = NULL; + bool res = false; + Query *q = NULL; + CFIndex n; + + syncBubbleView = SecMUSRCreateSyncBubbleUserUUID(uid); + require(syncBubbleView, fail); + + activeUserView = SecMUSRCreateActiveUserUUID(uid); + require(activeUserView, fail); + + + if ((onlyDelete && !copyToo) || !onlyDelete) { + + /* + * Clean out items first + */ + + secnotice("syncbubble", "cleaning out old items"); + + q = query_create(qclass, NULL, NULL, error); + require(q, fail); + + q->q_limit = kSecMatchUnlimited; + q->q_keybag = device_keybag_handle; + + for (n = 0; n < nItems; n++) { + query_add_attribute(items[n].attribute, items[n].value, q); + } + q->q_musrView = CFRetain(syncBubbleView); + require(q->q_musrView, fail); + + kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + return s3dl_query_delete(dbt, q, NULL, error); + }); + }); + + query_destroy(q, NULL); + q = NULL; + } + + + if (onlyDelete || !copyToo) { + secnotice("syncbubble", "skip migration of items"); + } else { + /* + * Copy over items from EMCS to sync bubble + */ + + secnotice("syncbubble", "migrating sync bubble items"); + + q = query_create(qclass, NULL, NULL, error); + require(q, fail); + + q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; + q->q_limit = kSecMatchUnlimited; + q->q_keybag = device_keybag_handle; /* XXX change to session key bag when it exists */ + + for (n = 0; n < nItems; n++) { + query_add_or_attribute(items[n].attribute, items[n].value, q); + } + query_add_or_attribute(CFSTR("musr"), activeUserView, q); + q->q_musrView = CFRetain(activeUserView); + + updateAttributes = CFDictionaryCreateMutableForCFTypes(NULL); + require(updateAttributes, fail); + + CFDictionarySetValue(updateAttributes, CFSTR("musr"), syncBubbleView); /* XXX should use kSecAttrMultiUser */ + + + kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + CFErrorRef error2 = NULL; + + SecDbItemSelect(q, dbt, &error2, NULL, ^bool(const SecDbAttr *attr) { + return CFDictionaryGetValue(q->q_item, attr->name); + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + CFErrorRef error3 = NULL; + secinfo("syncbubble", "migrating item"); + + SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, updateAttributes, NULL); + if (new_item == NULL) + return; + + SecDbItemClearRowId(new_item, NULL); + + if (!SecDbItemSetKeybag(new_item, device_keybag_handle, NULL)) { + CFRelease(new_item); + return; + } + + if (!SecDbItemInsert(new_item, dbt, &error3)) { + secnotice("syncbubble", "migration failed with %@ for item %@", error3, new_item); + } + CFRelease(new_item); + CFReleaseNull(error3); + }); + CFReleaseNull(error2); + + return (bool)true; + }); + }); + } + res = true; + +fail: + CFReleaseNull(syncBubbleView); + CFReleaseNull(activeUserView); + CFReleaseNull(updateAttributes); + if (q) + query_destroy(q, NULL); + + return res; +} + +static struct SyncBubbleRule PCSItems[] = { + { + .attribute = CFSTR("agrp"), + .value = CFSTR("com.apple.ProtectedCloudStorage"), + } +}; +static struct SyncBubbleRule NSURLSesssiond[] = { + { + .attribute = CFSTR("agrp"), + .value = CFSTR("com.apple.nsurlsessiond"), + } +}; +static struct SyncBubbleRule AccountsdItems[] = { + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.AppleAccount.token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.AppleAccount.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.AppleAccount.rpassword"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.idms.token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.idms.continuation-key"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.CloudKit.token"), + }, +}; + +static struct SyncBubbleRule MobileMailItems[] = { + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.IMAP.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.SMTP.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Exchange.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Hotmail.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Google.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Google.oauth-token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Google.oath-refresh-token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Yahoo.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Yahoo.oauth-token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Yahoo.oauth-token-nosync"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.Yahoo.oath-refresh-token"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.IMAPNotes.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.IMAPMail.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.126.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.163.password"), + }, + { + .attribute = CFSTR("svce"), + .value = CFSTR("com.apple.account.aol.password"), + }, +}; + +static bool +ArrayContains(CFArrayRef array, CFStringRef service) +{ + return CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), service); +} + +bool +_SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClient *client, CFErrorRef *error) +{ + bool copyCloudAuthToken = false; + bool copyMobileMail = false; + bool res = true; + bool copyPCS = false; + bool onlyDelete = false; + bool copyNSURLSesssion = false; + + if (!client->inMultiUser) + return false; + + secnotice("syncbubble", "migration for uid %d uid for services %@", (int)uid, services); + +#if TARGET_OS_SIMULATOR + // no delete in sim +#elif TARGET_OS_IOS + if (uid != (uid_t)client->activeUser) + onlyDelete = true; +#else +#error "no sync bubble on other platforms" +#endif + + /* + * First select that services to copy/delete + */ + + if (ArrayContains(services, CFSTR("com.apple.bird.usermanager.sync")) + || ArrayContains(services, CFSTR("com.apple.cloudphotod.sync")) + || ArrayContains(services, CFSTR("com.apple.cloudphotod.syncstakeholder")) + || ArrayContains(services, CFSTR("com.apple.cloudd.usermanager.sync"))) + { + copyCloudAuthToken = true; + copyPCS = true; + } + + if (ArrayContains(services, CFSTR("com.apple.nsurlsessiond.usermanager.sync"))) + { + copyCloudAuthToken = true; + copyNSURLSesssion = true; + } + + if (ArrayContains(services, CFSTR("com.apple.syncdefaultsd.usermanager.sync"))) { + copyCloudAuthToken = true; + } + if (ArrayContains(services, CFSTR("com.apple.mailq.sync")) || ArrayContains(services, CFSTR("com.apple.mailq.sync.xpc"))) { + copyCloudAuthToken = true; + copyMobileMail = true; + copyPCS = true; + } + + /* + * The actually copy/delete the items selected + */ + + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, inet_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); + require(res, fail); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, genp_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); + require(res, fail); + + /* mail */ + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyMobileMail, genp_class(), MobileMailItems, sizeof(MobileMailItems)/sizeof(MobileMailItems[0]), error); + require(res, fail); + + /* accountsd */ + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyCloudAuthToken, genp_class(), AccountsdItems, sizeof(AccountsdItems)/sizeof(AccountsdItems[0]), error); + require(res, fail); + + /* nsurlsessiond */ + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyNSURLSesssion, inet_class(), NSURLSesssiond, sizeof(NSURLSesssiond)/sizeof(NSURLSesssiond[0]), error); + require(res, fail); + +fail: + return res; +} + +/* + * Migrate from user keychain to system keychain when switching to edu mode + */ + +bool +_SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error) +{ + __block bool ok = true; + + /* + * we are not in multi user yet, about to switch, otherwise we would + * check that for client->inMultiuser here + */ + + kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + CFDataRef systemUUID = SecMUSRGetSystemKeychainUUID(); + + const SecDbSchema *newSchema = current_schema(); + SecDbClass const *const *kcClass; + + for (kcClass = newSchema->classes; *kcClass != NULL; kcClass++) { + CFErrorRef localError = NULL; + Query *q = NULL; + + if (!((*kcClass)->itemclass)) { + continue; + } + + q = query_create(*kcClass, SecMUSRGetSingleUserKeychainUUID(), NULL, error); + if (q == NULL) + continue; + + ok &= SecDbItemSelect(q, dbt, error, ^bool(const SecDbAttr *attr) { + return (attr->flags & kSecDbInFlag) != 0; + }, ^bool(const SecDbAttr *attr) { + // No filtering please. + return false; + }, ^bool(CFMutableStringRef sql, bool *needWhere) { + SecDbAppendWhereOrAnd(sql, needWhere); + CFStringAppendFormat(sql, NULL, CFSTR("musr = ?")); + return true; + }, ^bool(sqlite3_stmt *stmt, int col) { + return SecDbBindObject(stmt, col++, SecMUSRGetSingleUserKeychainUUID(), error); + }, ^(SecDbItemRef item, bool *stop) { + CFErrorRef itemError = NULL; + + if (!SecDbItemSetValueWithName(item, kSecAttrMultiUser, systemUUID, &itemError)) { + secerror("item: %@ update musr to system failed: %@", item, itemError); + ok = false; + goto out; + } + + if (!SecDbItemDoUpdate(item, item, dbt, &itemError, ^bool (const SecDbAttr *attr) { + return attr->kind == kSecDbRowIdAttr; + })) { + secerror("item: %@ insert during UPDATE: %@", item, itemError); + ok = false; + goto out; + } + + out: + SecErrorPropagate(itemError, error); + }); + + if (q) + query_destroy(q, &localError); + + } + return (bool)true; + }); + }); + + return ok; +} + +/* + * Delete account from local usage + */ + +bool +_SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error) +{ + return kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { + CFDataRef musrView = NULL, syncBubbleView = NULL; + bool ok = false; + + syncBubbleView = SecMUSRCreateSyncBubbleUserUUID(uid); + require(syncBubbleView, fail); + + musrView = SecMUSRCreateActiveUserUUID(uid); + require(musrView, fail); + + require(ok = SecServerDeleteAllForUser(dbt, syncBubbleView, false, error), fail); + require(ok = SecServerDeleteAllForUser(dbt, musrView, false, error), fail); + + fail: + CFReleaseNull(syncBubbleView); + CFReleaseNull(musrView); + return ok; + }); +} + + +#endif /* TARGET_OS_IOS */ + +CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) { + const void *keys[] = { + kSecClass, + kSecReturnData, + kSecMatchLimit, + kSecAttrSubject + }, + *values[] = { + kSecClassCertificate, + kCFBooleanTrue, + kSecMatchLimitAll, + normalizedIssuer + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, + NULL, NULL); + CFTypeRef results = NULL; + SecurityClient client = { + .task = NULL, + .accessGroups = accessGroups, + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + }; + + (void)_SecItemCopyMatching(query, &client, &results, error); + CFRelease(query); + return results; +} + +bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) { + const void *keys[] = { + kSecClass, + kSecMatchLimit, + kSecAttrIssuer, + kSecAttrSerialNumber + }, + *values[] = { + kSecClassCertificate, + kSecMatchLimitOne, + normalizedIssuer, + serialNumber + }; + SecurityClient client = { + .task = NULL, + .accessGroups = accessGroups, + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); + CFTypeRef results = NULL; + bool ok = _SecItemCopyMatching(query, &client, &results, error); + CFReleaseSafe(query); + CFReleaseSafe(results); + if (!ok) { + return false; + } + return true; +} diff --git a/keychain/securityd/SecItemServer.h b/keychain/securityd/SecItemServer.h new file mode 100644 index 00000000..91fcda27 --- /dev/null +++ b/keychain/securityd/SecItemServer.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecItemServer + The functions provided in SecItemServer.h provide an interface to + the backend for SecItem APIs in the server. +*/ + +#ifndef _SECURITYD_SECITEMSERVER_H_ +#define _SECURITYD_SECITEMSERVER_H_ + +#include +#include "keychain/SecureObjectSync/SOSCircle.h" +#include "keychain/securityd/SecDbQuery.h" +#include "utilities/SecDb.h" +#include +#include "sec/ipc/securityd_client.h" + + +__BEGIN_DECLS + +bool _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *result, CFErrorRef *error); +bool _SecItemCopyMatching(CFDictionaryRef query, SecurityClient *client, CFTypeRef *result, CFErrorRef *error); +bool _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, SecurityClient *client, CFErrorRef *error); +bool _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error); +bool _SecItemDeleteAll(CFErrorRef *error); +bool _SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error); + +bool _SecServerRestoreKeychain(CFErrorRef *error); +bool _SecServerMigrateKeychain(int32_t handle_in, CFDataRef data_in, int32_t *handle_out, CFDataRef *data_out, CFErrorRef *error); +CFDataRef _SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error); +bool _SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error); +CFStringRef _SecServerBackupCopyUUID(CFDataRef backup, CFErrorRef *error); + +bool _SecServerBackupKeybagAdd(SecurityClient *client, CFDataRef passcode, CFDataRef *identifier, CFDataRef *pathinfo, CFErrorRef *error); +bool _SecServerBackupKeybagDelete(CFDictionaryRef attributes, bool deleteAll, CFErrorRef *error); + +bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error); + +CF_RETURNS_RETAINED CFArrayRef _SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error); +CF_RETURNS_RETAINED CFDictionaryRef _SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error); + +int SecServerKeychainTakeOverBackupFD(CFStringRef backupName, CFErrorRef *error); + +bool _SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error); + +#if TARGET_OS_IOS +bool _SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error); +bool _SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClient *client, CFErrorRef *error); +bool _SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error); +#endif + +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE +bool _SecAddSharedWebCredential(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error); +bool _SecCopySharedWebCredential(CFDictionaryRef query, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error); +#endif /* TARGET_OS_IOS */ + +// Hack to log objects from inside SOS code +void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object); + +SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error); +SecDbRef SecKeychainDbInitialize(SecDbRef db); + +bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)); +bool kc_with_dbt_non_item_tables(bool writeAndRead, CFErrorRef* error, bool (^perform)(SecDbConnectionRef dbt)); // can be used when only tables which don't store 'items' are accessed - avoids invoking SecItemDataSourceFactoryGetDefault() +bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)); + + +/* For whitebox testing only */ +void SecKeychainDbReset(dispatch_block_t inbetween); + + +SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void); + +/* FIXME: there is a specific type for keybag handle (keybag_handle_t) + but it's not defined for simulator so we just use an int32_t */ +void SecItemServerSetKeychainKeybag(int32_t keybag); +void SecItemServerResetKeychainKeybag(void); + +void SecItemServerSetKeychainChangedNotification(const char *notification_name); + +CFStringRef __SecKeychainCopyPath(void); + +bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error); +bool _SecServerRollKeysGlue(bool force, CFErrorRef *error); + + +/* initial sync */ +#define SecServerInitialSyncCredentialFlagTLK (1 << 0) +#define SecServerInitialSyncCredentialFlagPCS (1 << 1) +#define SecServerInitialSyncCredentialFlagPCSNonCurrent (1 << 2) +#define SecServerInitialSyncCredentialFlagBluetoothMigration (1 << 3) + +CFArrayRef _SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error); +bool _SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error); + +CF_RETURNS_RETAINED CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error); +bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error); + +bool SecKeychainDbGetVersion(SecDbConnectionRef dbt, int *version, CFErrorRef *error); + + +// Should all be blocks called from SecItemDb +bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item); +bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client); +bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); +void SecKeychainChanged(void); + +__END_DECLS + +#endif /* _SECURITYD_SECITEMSERVER_H_ */ diff --git a/keychain/securityd/SecKeybagSupport.c b/keychain/securityd/SecKeybagSupport.c new file mode 100644 index 00000000..d526c73f --- /dev/null +++ b/keychain/securityd/SecKeybagSupport.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecKeybagSupport.c - CoreFoundation-based constants and functions for + access to Security items (certificates, keys, identities, and + passwords.) + */ + +#include "keychain/securityd/SecKeybagSupport.h" +#include + +#include "keychain/securityd/SecItemServer.h" + +#if USE_KEYSTORE +#include +#include +#include +#include +#include +#else /* !USE_KEYSTORE */ +#include +#endif /* USE_KEYSTORE */ + +#include +#include + +#include "OSX/utilities/SecAKSWrappers.h" + +/* g_keychain_handle is the keybag handle used for encrypting item in the keychain. + For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */ +#if USE_KEYSTORE +#if TARGET_OS_OSX +keybag_handle_t g_keychain_keybag = session_keybag_handle; +#else +keybag_handle_t g_keychain_keybag = device_keybag_handle; +#endif +#else /* !USE_KEYSTORE */ +keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ +#endif /* USE_KEYSTORE */ + +const CFStringRef kSecKSKeyData1 = CFSTR("d1"); +const CFStringRef kSecKSKeyData2 = CFSTR("d2"); + +void SecItemServerSetKeychainKeybag(int32_t keybag) +{ + g_keychain_keybag=keybag; +} + +void SecItemServerResetKeychainKeybag(void) +{ +#if USE_KEYSTORE +#if TARGET_OS_OSX + g_keychain_keybag = session_keybag_handle; +#else + g_keychain_keybag = device_keybag_handle; +#endif +#else /* !USE_KEYSTORE */ + g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ +#endif /* USE_KEYSTORE */ +} + +/* Wrap takes a 128 - 256 bit key as input and returns output of + inputsize + 64 bits. + In bytes this means that a + 16 byte (128 bit) key returns a 24 byte wrapped key + 24 byte (192 bit) key returns a 32 byte wrapped key + 32 byte (256 bit) key returns a 40 byte wrapped key */ +bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, + keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) { +#if USE_KEYSTORE + kern_return_t kernResult = kAKSReturnBadArgument; + + int dest_len = (int)CFDataGetLength(dest); + if (CFEqual(operation, kAKSKeyOpEncrypt)) { + kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class); + } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { + kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len); + } + + if (kernResult != KERN_SUCCESS) { + if ((kernResult == kAKSReturnNoPermission) || (kernResult == kAKSReturnNotPrivileged)) { + const char *substatus = ""; + if (keyclass == key_class_ck || keyclass == key_class_cku) + substatus = " (hibernation?)"; + /* Access to item attempted while keychain is locked. */ + return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked%s."), + kernResult, operation, keyclass, keybag, substatus); + } else if (kernResult == kAKSReturnNotFound) { + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), kernResult, operation, keyclass, keybag); + } else if (kernResult == kAKSReturnError || kernResult == kAKSReturnDecodeError) { + /* Item can't be decrypted on this device, ever, so drop the item. */ + return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), + kernResult, operation, keyclass, keybag); + } else { + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"), + kernResult, operation, keyclass, keybag); + } + } + else + CFDataSetLength(dest, dest_len); + return true; +#else /* !USE_KEYSTORE */ + + uint32_t dest_len = (uint32_t)CFDataGetLength(dest); + if (CFEqual(operation, kAKSKeyOpEncrypt)) { + /* The no encryption case. */ + if (dest_len >= textLength + 8) { + memcpy(CFDataGetMutableBytePtr(dest), source, textLength); + memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8); + CFDataSetLength(dest, textLength + 8); + *actual_class = keyclass; + } else + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass); + } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { + if (dest_len + 8 >= textLength) { + memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8); + CFDataSetLength(dest, textLength - 8); + } else + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass); + } + return true; +#endif /* USE_KEYSTORE */ +} + +#if USE_KEYSTORE +bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) { + if (error == NULL) + return false; + + if (*error && CFErrorGetCode(*error) != errSecAuthNeeded) { + // If we already had an error there, just leave it, no access_control specific error is needed here. + return false; + } + + // Create new error instance which adds new access control data appended to existing + CFMutableDictionaryRef user_info; + if (*error) { + CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error); + user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info); + CFRelease(old_user_info); + CFReleaseNull(*error); + } else { + user_info = CFDictionaryCreateMutableForCFTypes(NULL); + } + + if (access_control_data) { + CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded); + CFMutableArrayRef acls; + CFArrayRef old_acls = CFDictionaryGetValue(user_info, key); + if (old_acls) + acls = CFArrayCreateMutableCopy(NULL, 0, old_acls); + else + acls = CFArrayCreateMutableForCFTypes(NULL); + + CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL); + CFArrayAppendValue(acls, pair); + CFRelease(pair); + + CFDictionarySetValue(user_info, key, acls); + CFRelease(key); + CFRelease(acls); + + *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info); + } + else + *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL); + + CFReleaseSafe(user_info); + return false; +} + +static bool merge_der_in_to_data(const void *ed_blob, size_t ed_blob_len, const void *key_blob, size_t key_blob_len, CFMutableDataRef mergedData) +{ + bool ok = false; + CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull); + CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull); + + if (ed_data && key_data) { + CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL); + + CFDataSetLength(mergedData, 0); + CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL); + if (der_data) { + CFDataAppend(mergedData, der_data); + CFRelease(der_data); + ok = CFDataGetLength(mergedData) > 0; + } + CFRelease(result_dict); + } + + CFReleaseSafe(ed_data); + CFReleaseSafe(key_data); + return ok; +} + +bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data) +{ + bool ok = false; + CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1); + CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2); + + if (tmp_ed_data && tmp_key_data && + CFDataGetTypeID() == CFGetTypeID(tmp_ed_data) && + CFDataGetTypeID() == CFGetTypeID(tmp_key_data)) { + *ed_data = CFRetain(tmp_ed_data); + *key_data = CFRetain(tmp_key_data); + ok = true; + } + + return ok; +} + +bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error) +{ + const char *operation_string = ""; + if (CFEqual(operation, kAKSKeyOpDecrypt)) { + operation_string = "decrypt"; + } else if (CFEqual(operation, kAKSKeyOpEncrypt)) { + operation_string = "encrypt"; + } if (CFEqual(operation, kAKSKeyOpDelete)) { + operation_string = "delete"; + } + + if (aks_return == kAKSReturnNoPermission) { + /* Keychain is locked. */ + SecError(errSecInteractionNotAllowed, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."), + aks_return, operation_string, keyclass, keybag); + } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) { + if (aks_return == kAKSReturnBadPassword) { + ACMContextRef acm_context_ref = NULL; + acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data)); + if (acm_context_ref) { + ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext); + ACMContextDelete(acm_context_ref, false); + } + } + + /* Item needed authentication. */ + ks_access_control_needed_error(error, access_control_data, operation); + } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid || aks_return == kAKSReturnDecodeError) { + /* Item can't be decrypted on this device, ever, so drop the item. */ + SecError(errSecDecode, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), + aks_return, operation_string, keyclass, keybag); + + } else if (aks_return == kAKSReturnNotFound) { + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), aks_return, operation, keyclass, keybag); + } else { + SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"), + aks_return, operation_string, keyclass, keybag); + } + + return false; +} + +bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source, + CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, + SecAccessControlRef access_control, CFErrorRef *error) { + void *params = NULL, *der = NULL; + size_t params_len = 0, der_len = 0; + CFDataRef access_control_data = SecAccessControlCopyData(access_control); + int aks_return = kAKSReturnSuccess; + aks_ref_key_t key_handle = NULL; + + /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ + bool ok = false; + if (!acm_context || !SecAccessControlIsBound(access_control)) { + require_quiet(ok = ks_access_control_needed_error(error, access_control_data, SecAccessControlIsBound(access_control) ? kAKSKeyOpEncrypt : CFSTR("")), out); + } + + aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); + require_noerr_action_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out, + create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); + require_noerr_action_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out, + create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); + size_t key_blob_len; + const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len); + require_action_quiet(key_blob, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to invalid key data, so drop the item."), + aks_return, "encrypt", keyclass, keybag)); + + require_action_quiet(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out, + SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to merge failed, so drop the item."), + aks_return, "encrypt", keyclass, keybag)); + + ok = true; + +out: + if (key_handle) + aks_ref_key_free(&key_handle); + if(params) + free(params); + if(der) + free(der); + CFReleaseSafe(access_control_data); + return ok; +} + +bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest, + CFDataRef acm_context, CFDataRef caller_access_groups, + SecAccessControlRef access_control, CFErrorRef *error) { + void *params = NULL, *der = NULL; + const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; + size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; + CFDataRef access_control_data = SecAccessControlCopyData(access_control); + int aks_return = kAKSReturnSuccess; + + /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ + bool ok = false; + if (!acm_context) { + require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); + } + + aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); + require_noerr_action_quiet(aks_return = aks_ref_key_decrypt(ref_key, params, params_len, CFDataGetBytePtr(encrypted_data), CFDataGetLength(encrypted_data), &der, &der_len), out, + create_cferror_from_aks(aks_return, kAKSKeyOpDecrypt, 0, 0, access_control_data, acm_context, error)); + require_action_quiet(der, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to invalid der data, so drop the item."), + aks_return, "decrypt")); + + CFPropertyListRef decoded_data = NULL; + der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len); + require_action_quiet(decoded_data, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."), + aks_return, "decrypt")); + if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) { + CFDataSetLength(dest, 0); + CFDataAppend(dest, decoded_data); + CFRelease(decoded_data); + } + else { + CFRelease(decoded_data); + require_action_quiet(false, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to wrong data, so drop the item."), + aks_return, "decrypt")); + } + + ok = true; + +out: + if(params) + free(params); + if(der) + free(der); + CFReleaseSafe(access_control_data); + return ok; +} + +bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, + CFDataRef acm_context, CFDataRef caller_access_groups, + SecAccessControlRef access_control, CFErrorRef *error) { + void *params = NULL; + CFDataRef access_control_data = NULL; + int aks_return = kAKSReturnSuccess; + bool ok = false; + + nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true); + + /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ + if (!acm_context) { + require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); + } + + access_control_data = SecAccessControlCopyData(access_control); + const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; + size_t params_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; + aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); + require_noerr_action_quiet(aks_return = aks_ref_key_delete(ref_key, params, params_len), out, + create_cferror_from_aks(aks_return, kAKSKeyOpDelete, 0, 0, access_control_data, acm_context, error)); + + ok = true; + +out: + if(params) + free(params); + CFReleaseSafe(access_control_data); + return ok; +} + +const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error) { + int aks_return = aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key); + if (aks_return == kAKSReturnBadArgument) { + SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob because bad data (bag: %"PRId32")"), keybag); + return NULL; + // As of this writing the only other error code is kAKSReturnInternalError but we don't want to rely on that + } else if (aks_return != kAKSReturnSuccess) { + SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob: %x (bag: %"PRId32")"), aks_return, keybag); + return NULL; + } + return aks_ref_key_get_external_data(*ref_key, external_data_len); +} +#endif + +bool use_hwaes(void) { +#if !TARGET_OS_BRIDGE + static bool use_hwaes; + static dispatch_once_t check_once; + dispatch_once(&check_once, ^{ + use_hwaes = hwaes_key_available(); + if (use_hwaes) { + secinfo("aks", "using hwaes key"); + } else { + secerror("unable to access hwaes key"); + } + }); + return use_hwaes; +#else + return false; +#endif // TARGET_OS_BRIDGE +} + +bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) { +#if USE_KEYSTORE + kern_return_t kernResult; + if (!asData(keybag, error)) return false; + kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle); + if (kernResult) + return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag); + + if (password) { + kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password)); + if (kernResult) { + aks_unload_bag(*handle); + return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed")); + } + } + return true; +#else /* !USE_KEYSTORE */ + *handle = KEYBAG_NONE; + return true; +#endif /* USE_KEYSTORE */ +} + +bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) { +#if USE_KEYSTORE + IOReturn kernResult = aks_unload_bag(keybag); + if (kernResult) { + return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed")); + } +#endif /* USE_KEYSTORE */ + return true; +} + diff --git a/keychain/securityd/SecKeybagSupport.h b/keychain/securityd/SecKeybagSupport.h new file mode 100644 index 00000000..b2b6aa28 --- /dev/null +++ b/keychain/securityd/SecKeybagSupport.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecKeybagSupport.h - The thing that does the stuff with the gibli. + */ + +#ifndef _SECURITYD_SECKEYBAGSUPPORT_H_ +#define _SECURITYD_SECKEYBAGSUPPORT_H_ + +#include +#include "utilities/SecAKSWrappers.h" +#include +#include + +#ifndef USE_KEYSTORE +// Use keystore (real or mock) on all platforms, except bridge +#define USE_KEYSTORE !TARGET_OS_BRIDGE +#endif + +#if __has_include() +#include +#endif + +#if USE_KEYSTORE +#include +#endif /* USE_KEYSTORE */ + +__BEGIN_DECLS + + +/* KEYBAG_NONE is private to security and have special meaning. + They should not collide with AppleKeyStore constants, but are only referenced + in here. + */ +#define KEYBAG_NONE (-1) /* Set q_keybag to KEYBAG_NONE to obtain cleartext data. */ +#define KEYBAG_DEVICE (g_keychain_keybag) /* actual keybag used to encrypt items */ +extern keybag_handle_t g_keychain_keybag; + +bool use_hwaes(void); + +bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, + keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, + CFMutableDataRef dest, CFErrorRef *error); +#if USE_KEYSTORE +bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source, + CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, + SecAccessControlRef access_control, CFErrorRef *error); +bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest, + CFDataRef acm_context, CFDataRef caller_access_groups, + SecAccessControlRef access_control, CFErrorRef *error); +bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, + CFDataRef acm_context, CFDataRef caller_access_groups, + SecAccessControlRef access_control, CFErrorRef *error); +const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, + aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error); +bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data); + +bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation); +bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error); +#endif +bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error); +bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error); + +__END_DECLS + +#endif /* _SECURITYD_SECKEYBAGSUPPORT_H_ */ diff --git a/keychain/securityd/SecLogSettingsServer.h b/keychain/securityd/SecLogSettingsServer.h new file mode 100644 index 00000000..21e886c4 --- /dev/null +++ b/keychain/securityd/SecLogSettingsServer.h @@ -0,0 +1,20 @@ +// +// SecLogSettingsServer.h +// sec +// +// + +#ifndef _SECURITY_SECLOGSETTINGSSERVER_H_ +#define _SECURITY_SECLOGSETTINGSSERVER_H_ + +#include + +__BEGIN_DECLS + +CFPropertyListRef SecCopyLogSettings_Server(CFErrorRef* error); +bool SecSetXPCLogSettings_Server(CFTypeRef type, CFErrorRef* error); +bool SecSetCircleLogSettings_Server(CFTypeRef type, CFErrorRef* error); + +__END_DECLS + +#endif diff --git a/keychain/securityd/SecLogSettingsServer.m b/keychain/securityd/SecLogSettingsServer.m new file mode 100644 index 00000000..4a15049c --- /dev/null +++ b/keychain/securityd/SecLogSettingsServer.m @@ -0,0 +1,49 @@ +// +// SecLogSettingsServer.c +// sec +// +// + +#include "keychain/securityd/SecLogSettingsServer.h" +#include "keychain/SecureObjectSync/SOSAccountPriv.h" +#include +#include +#include "keychain/SecureObjectSync/SOSTransportCircle.h" +#include +#include +#include + +CFPropertyListRef +SecCopyLogSettings_Server(CFErrorRef* error) +{ + return CopyCurrentScopePlist(); +} + +bool +SecSetXPCLogSettings_Server(CFTypeRef type, CFErrorRef* error) +{ + bool success = false; + if (isString(type)) { + ApplyScopeListForID(type, kScopeIDXPC); + success = true; + } else if (isDictionary(type)) { + ApplyScopeDictionaryForID(type, kScopeIDXPC); + success = true; + } else { + success = SecError(errSecParam, error, CFSTR("Unsupported CFType")); + } + + return success; +} + +bool +SecSetCircleLogSettings_Server(CFTypeRef type, CFErrorRef* error) +{ + bool success = false; + SOSAccount* account = (__bridge SOSAccount*)SOSKeychainAccountGetSharedAccount(); + if (account) { + success = SOSAccountPostDebugScope(account, type, error); + } + return success; +} + diff --git a/keychain/securityd/SecOTRRemote.h b/keychain/securityd/SecOTRRemote.h new file mode 100644 index 00000000..44775958 --- /dev/null +++ b/keychain/securityd/SecOTRRemote.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef sec_SecOTRRemote_h +#define sec_SecOTRRemote_h + +#include + +CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error); +CFDataRef _SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error); +bool _SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error); + +#endif diff --git a/keychain/securityd/SecOTRRemote.m b/keychain/securityd/SecOTRRemote.m new file mode 100644 index 00000000..cef0caf1 --- /dev/null +++ b/keychain/securityd/SecOTRRemote.m @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "AssertMacros.h" +#include +#include "SecOTRRemote.h" +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SOSCloudCircleServer.h" + +#include "SOSAccountPriv.h" + +#import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" + +CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error) { + SOSDataSourceFactoryRef ds = SecItemDataSourceFactoryGetDefault(); + + SOSAccount* privateAccount = NULL; + SOSAccount* publicAccount = NULL; + CFStringRef publicKeyString = NULL; + SecKeyRef privateKeyRef = NULL; + SecKeyRef publicKeyRef = NULL; + SecOTRFullIdentityRef privateIdentity = NULL; + SecOTRPublicIdentityRef publicIdentity = NULL; + CFDataRef result = NULL; + SecOTRSessionRef ourSession = NULL; + + require_quiet(ds, fail); + require_quiet(publicPeerId, fail); + + if (privateAccountData) { + NSError* ns_error = nil; + privateAccount = [SOSAccount accountFromData:(__bridge NSData*) privateAccountData factory:ds error:&ns_error]; + if (error && *error == NULL && !privateAccount) { + *error = (CFErrorRef) CFBridgingRetain(ns_error); + } + } else { + privateAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); + } + + require_quiet(privateAccount, fail); + + privateKeyRef = SOSAccountCopyDeviceKey(privateAccount, error); + require_quiet(privateKeyRef, fail); + + privateIdentity = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, privateKeyRef, error); + require_quiet(privateIdentity, fail); + CFReleaseNull(privateKeyRef); + + publicKeyString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, publicPeerId, kCFStringEncodingUTF8); + require_quiet(publicKeyString, fail); + + if (publicAccountData) { + NSError* ns_error = nil; + publicAccount = [SOSAccount accountFromData:(__bridge NSData*) publicAccountData factory:ds error:&ns_error]; + if (error && *error == NULL && !publicAccount) { + *error = (CFErrorRef) CFBridgingRetain(ns_error); + } + } else { + publicAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); + } + + require_quiet(publicAccount, fail); + + publicKeyRef = [publicAccount.trust copyPublicKeyForPeer:publicKeyString err:error]; + + if(!publicKeyRef){ + if(!ds){ + CFReleaseNull(ourSession); + CFReleaseNull(publicKeyString); + privateAccount= nil; + publicAccount = nil; + CFReleaseNull(privateKeyRef); + CFReleaseNull(publicKeyRef); + CFReleaseNull(publicIdentity); + CFReleaseNull(privateIdentity); + return result; + } + } + publicIdentity = SecOTRPublicIdentityCreateFromSecKeyRef(kCFAllocatorDefault, publicKeyRef, error); + require_quiet(publicIdentity, fail); + + CFReleaseNull(publicKeyRef); + + ourSession = SecOTRSessionCreateFromID(kCFAllocatorDefault, privateIdentity, publicIdentity); + + CFMutableDataRef exportSession = CFDataCreateMutable(kCFAllocatorDefault, 0); + SecOTRSAppendSerialization(ourSession, exportSession); + + result = exportSession; + exportSession = NULL; + +fail: + CFReleaseNull(ourSession); + CFReleaseNull(publicKeyString); + privateAccount= nil; + publicAccount = nil; + CFReleaseNull(privateKeyRef); + CFReleaseNull(publicKeyRef); + CFReleaseNull(publicIdentity); + CFReleaseNull(privateIdentity); + return result; +} + +CFDataRef _SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) { + return SecOTRSessionCreateRemote_internal(NULL, publicPeerId, NULL, error); +} + +bool _SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) { + + bool result = false; + SecOTRSessionRef session = SecOTRSessionCreateFromData(kCFAllocatorDefault, sessionData); + require_quiet(session, done); + + CFMutableDataRef negotiationResponse = CFDataCreateMutable(kCFAllocatorDefault, 0); + + if (inputPacket) { + SecOTRSProcessPacket(session, inputPacket, negotiationResponse); + } else { + SecOTRSAppendStartPacket(session, negotiationResponse); + } + + CFMutableDataRef outputSession = CFDataCreateMutable(kCFAllocatorDefault, 0); + + SecOTRSAppendSerialization(session, outputSession); + *outputSessionData = outputSession; + + *outputPacket = negotiationResponse; + + *readyForMessages = SecOTRSGetIsReadyForMessages(session); + CFReleaseNull(session); + + result = true; + +done: + return result; +} + diff --git a/keychain/securityd/com.apple.secd.sb b/keychain/securityd/com.apple.secd.sb new file mode 100644 index 00000000..21f50f45 --- /dev/null +++ b/keychain/securityd/com.apple.secd.sb @@ -0,0 +1,87 @@ +(version 1) + +(deny default) + +(import "system.sb") + +(allow file-read* file-write* + (subpath "/private/var/db/mds") + (regex #"^/private/var/folders/[^/]+/[^/]+/T(/|$)") + (regex (string-append "^" (regex-quote (param "_HOME")) #"/Library/Keychains(/|$)"))) + +(allow file-read* + (literal (string-append (param "_HOME") "/Library/Preferences/com.apple.imessage.bag.plist")) + (literal (string-append (param "_HOME") "/Library/Preferences/com.apple.facetime.bag.plist"))) + + +;;;;;; will be fully fixed in 29465717 +(allow file-read* (subpath "/")) + +(allow user-preference-read + (preference-domain ".GlobalPreferences")) +(allow user-preference-read + (preference-domain "com.apple.security")) +(allow user-preference-read + (preference-domain "com.apple.imessage.bag")) +(allow user-preference-read + (preference-domain "com.apple.facetime.bag")) +(allow user-preference-read user-preference-write + (preference-domain "com.apple.security.sosaccount")) + +(allow distributed-notification-post) + +(allow iokit-open + (iokit-user-client-class "AppleKeyStoreUserClient") + (iokit-user-client-class "AppleAPFSUserClient") + (iokit-user-client-class "RootDomainUserClient")) + + +(allow file-read* + (literal "/usr/libexec/secd") + (literal "/Library/Preferences/com.apple.security.plist") + (literal "/Library/Preferences/.GlobalPreferences.plist") + (literal "/AppleInternal") + (literal "/usr/libexec")) + +(allow mach-lookup + (global-name "com.apple.system.opendirectoryd.api") + (global-name "com.apple.SystemConfiguration.configd") + (global-name "com.apple.security.cloudkeychainproxy3") + (global-name "com.apple.accountsd.accountmanager") + (global-name "com.apple.CoreServices.coreservicesd") + (global-name "com.apple.distributed_notifications@Uv3") + (global-name "com.apple.ak.auth.xpc") + (global-name "com.apple.cdp.daemon") + (global-name "com.apple.cloudd") + (global-name "com.apple.apsd") + (global-name "com.apple.analyticsd") + (global-name "com.apple.symptom_diagnostics") + (global-name "com.apple.ak.anisette.xpc") + (global-name "com.apple.corefollowup.agent") + (global-name "com.apple.windowserver.active") + (global-name "com.apple.powerlog.plxpclogger.xpc") + (global-name "com.apple.SecureBackupDaemon") +) + +;; Used to send logs for MoiC. +(allow mach-lookup + (global-name "com.apple.imagent.desktop.auth")) + +(allow iokit-get-properties (iokit-registry-entry-class "IOPlatformExpertDevice")) + +(allow ipc-posix-shm + (ipc-posix-name "com.apple.AppleDatabaseChanged")) + +(allow network-outbound) +(allow system-socket) + +;; to be deleted once SecTrustEvaluate and SecTrustCopyKey can avoid touching legacy cert and keychain stack +(allow file-read* file-write* + (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsDirectory\.db$") + (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsObject\.db$") + (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mds\.lock$")) +(allow mach-lookup + (global-name "com.apple.SecurityServer")) + +(allow system-fsctl (fsctl-command afpfsByteRangeLock2FSCTL)) + diff --git a/keychain/securityd/entitlements.plist b/keychain/securityd/entitlements.plist new file mode 100644 index 00000000..02625012 --- /dev/null +++ b/keychain/securityd/entitlements.plist @@ -0,0 +1,96 @@ + + + + + com.apple.private.dark-wake-push + + com.apple.private.accounts.allaccounts + + com.apple.private.aps-connection-initiate + + aps-connection-initiate + + com.apple.developer.aps-environment + serverPreferred + aps-environment + serverPreferred + com.apple.aps-environment + serverPreferred + com.apple.private.cloudkit.setEnvironment + + com.apple.developer.icloud-container-identifiers + + iCloud.com.apple.security.keychain + + com.apple.developer.icloud-services + + CloudKit + + com.apple.developer.icloud-container-environment + Production + com.apple.private.cloudkit.systemService + + com.apple.private.cloudkit.buddyAccess + + com.apple.private.cloudkit.allowUnverifiedAccount + + com.apple.private.cloudkit.supportservice + + com.apple.private.appleaccount.app-hidden-from-icloud-settings + + com.apple.private.tcc.allow + + kTCCServiceLiverpool + + com.apple.application-identifier + com.apple.securityd + application-identifier + com.apple.securityd + com.apple.keystore.access-keychain-keys + + com.apple.keystore.lockassertion + + com.apple.private.associated-domains + + com.apple.private.necp.match + + com.apple.private.network.socket-delegate + + com.apple.mkb.usersession.info + + com.apple.private.applecredentialmanager.allow + + com.apple.private.imcore.imagent + + com.apple.private.MobileGestalt.AllowedProtectedKeys + + SerialNumber + + seatbelt-profiles + + securityd + + com.apple.private.sqlite.sqlite-encryption + + com.apple.accounts.appleaccount.fullaccess + + com.apple.authkit.client.private + + com.apple.private.trustedpeershelper.client + + com.apple.private.imcore.imremoteurlconnection + + com.apple.private.ids.remoteurlconnection + + com.apple.private.imcore.remoteurlconnection + + com.apple.securebackupd.access + + com.apple.CloudKeychainProxy.client + + com.apple.security.network.client + + com.apple.symptom_diagnostics.report + + + diff --git a/keychain/securityd/iCloudTrace.c b/keychain/securityd/iCloudTrace.c new file mode 100644 index 00000000..9d00ef33 --- /dev/null +++ b/keychain/securityd/iCloudTrace.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include "iCloudTrace.h" +#include +#include +#include +#include +#include "keychain/securityd/SecItemServer.h" +#include +#include +#if TARGET_OS_OSX +#include +#endif +#include +#include + diff --git a/keychain/securityd/iCloudTrace.h b/keychain/securityd/iCloudTrace.h new file mode 100644 index 00000000..594a5b87 --- /dev/null +++ b/keychain/securityd/iCloudTrace.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef sec_iCloudTrace_h +#define sec_iCloudTrace_h +#include + +#endif diff --git a/keychain/securityd/spi.c b/keychain/securityd/spi.c new file mode 100644 index 00000000..80b10d3f --- /dev/null +++ b/keychain/securityd/spi.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if TARGET_DARWINOS +#undef OCTAGON +#undef SECUREOBJECTSYNC +#undef SHAREDWEBCREDENTIALS +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfour-char-constants" + +#include "keychain/securityd/spi.h" +#include "ipc/SecdWatchdog.h" +#include "ipc/server_security_helpers.h" +#include "ipc/securityd_client.h" +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" +#include +#include +#include +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecOTRRemote.h" +#include "keychain/securityd/SecLogSettingsServer.h" + +#include +#include "utilities/iOSforOSX.h" +#include "utilities/SecFileLocations.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/trustd_spi.h" + +#pragma clang diagnostic pop + +static struct securityd securityd_spi = { + .sec_item_add = _SecItemAdd, + .sec_item_copy_matching = _SecItemCopyMatching, + .sec_item_update = _SecItemUpdate, + .sec_item_delete = _SecItemDelete, + .sec_item_delete_all = _SecItemDeleteAll, + .sec_keychain_backup = _SecServerKeychainCreateBackup, + .sec_keychain_restore = _SecServerKeychainRestore, + .sec_item_copy_parent_certificates = _SecItemCopyParentCertificates, + .sec_item_certificate_exists = _SecItemCertificateExists, + .sec_roll_keys = _SecServerRollKeysGlue, + .sec_item_update_token_items = _SecItemUpdateTokenItems, + .sec_delete_items_with_access_groups = _SecItemServerDeleteAllWithAccessGroups, +#if SHAREDWEBCREDENTIALS + .sec_add_shared_web_credential = _SecAddSharedWebCredential, + .sec_copy_shared_web_credential = _SecCopySharedWebCredential, +#endif +#if SECUREOBJECTSYNC + .sec_keychain_backup_syncable = _SecServerBackupSyncable, + .sec_keychain_restore_syncable = _SecServerRestoreSyncable, + .sec_item_backup_copy_names = SecServerItemBackupCopyNames, + .sec_item_backup_handoff_fd = SecServerItemBackupHandoffFD, + .sec_item_backup_set_confirmed_manifest = SecServerItemBackupSetConfirmedManifest, + .sec_item_backup_restore = SecServerItemBackupRestore, + .sec_otr_session_create_remote = _SecOTRSessionCreateRemote, + .sec_otr_session_process_packet_remote = _SecOTRSessionProcessPacketRemote, + .soscc_TryUserCredentials = SOSCCTryUserCredentials_Server, + .soscc_SetUserCredentials = SOSCCSetUserCredentials_Server, + .soscc_SetUserCredentialsAndDSID = SOSCCSetUserCredentialsAndDSID_Server, + .soscc_SetUserCredentialsAndDSIDWithAnalytics = SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server, + .soscc_CanAuthenticate = SOSCCCanAuthenticate_Server, + .soscc_PurgeUserCredentials = SOSCCPurgeUserCredentials_Server, + .soscc_ThisDeviceIsInCircle = SOSCCThisDeviceIsInCircle_Server, + .soscc_RequestToJoinCircle = SOSCCRequestToJoinCircle_Server, + .soscc_RequestToJoinCircleAfterRestore = SOSCCRequestToJoinCircleAfterRestore_Server, + .soscc_RequestToJoinCircleAfterRestoreWithAnalytics = SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server, + .soscc_RequestEnsureFreshParameters = SOSCCRequestEnsureFreshParameters_Server, + .soscc_GetAllTheRings = SOSCCGetAllTheRings_Server, + .soscc_ApplyToARing = SOSCCApplyToARing_Server, + .soscc_WithdrawlFromARing = SOSCCWithdrawlFromARing_Server, + .soscc_EnableRing = SOSCCEnableRing_Server, + .soscc_RingStatus = SOSCCRingStatus_Server, + .soscc_SetToNew = SOSCCAccountSetToNew_Server, + .soscc_ResetToOffering = SOSCCResetToOffering_Server, + .soscc_ResetToEmpty = SOSCCResetToEmpty_Server, + .soscc_ResetToEmptyWithAnalytics = SOSCCResetToEmptyWithAnalytics_Server, + .soscc_View = SOSCCView_Server, + .soscc_ViewSet = SOSCCViewSet_Server, + .soscc_ViewSetWithAnalytics = SOSCCViewSetWithAnalytics_Server, + .soscc_RemoveThisDeviceFromCircle = SOSCCRemoveThisDeviceFromCircle_Server, + .soscc_RemoveThisDeviceFromCircleWithAnalytics = SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server, + .soscc_RemovePeersFromCircle = SOSCCRemovePeersFromCircle_Server, + .soscc_RemovePeersFromCircleWithAnalytics = SOSCCRemovePeersFromCircleWithAnalytics_Server, + .soscc_LoggedOutOfAccount = SOSCCLoggedOutOfAccount_Server, + .soscc_BailFromCircle = SOSCCBailFromCircle_Server, + .soscc_AcceptApplicants = SOSCCAcceptApplicants_Server, + .soscc_RejectApplicants = SOSCCRejectApplicants_Server, + .soscc_CopyApplicantPeerInfo = SOSCCCopyApplicantPeerInfo_Server, + .soscc_CopyGenerationPeerInfo = SOSCCCopyGenerationPeerInfo_Server, + .soscc_CopyValidPeerPeerInfo = SOSCCCopyValidPeerPeerInfo_Server, + .soscc_ValidateUserPublic = SOSCCValidateUserPublic_Server, + .soscc_CopyNotValidPeerPeerInfo = SOSCCCopyNotValidPeerPeerInfo_Server, + .soscc_CopyRetirementPeerInfo = SOSCCCopyRetirementPeerInfo_Server, + .soscc_CopyViewUnawarePeerInfo = SOSCCCopyViewUnawarePeerInfo_Server, + .soscc_CopyEngineState = SOSCCCopyEngineState_Server, + .soscc_CopyPeerInfo = SOSCCCopyPeerPeerInfo_Server, + .soscc_CopyConcurringPeerInfo = SOSCCCopyConcurringPeerPeerInfo_Server, + .soscc_ProcessSyncWithPeers = SOSCCProcessSyncWithPeers_Server, + .soscc_ProcessSyncWithAllPeers = SOSCCProcessSyncWithAllPeers_Server, + .soscc_EnsurePeerRegistration = SOSCCProcessEnsurePeerRegistration_Server, + .sec_keychain_sync_update_message = _SecServerKeychainSyncUpdateMessage, + .sec_get_log_settings = SecCopyLogSettings_Server, + .sec_set_xpc_log_settings = SecSetXPCLogSettings_Server, + .sec_set_circle_log_settings = SecSetCircleLogSettings_Server, + .soscc_CopyMyPeerInfo = SOSCCCopyMyPeerInfo_Server, + .soscc_SetLastDepartureReason = SOSCCSetLastDepartureReason_Server, + .soscc_SetNewPublicBackupKey = SOSCCSetNewPublicBackupKey_Server, + .soscc_RegisterSingleRecoverySecret = SOSCCRegisterSingleRecoverySecret_Server, + .soscc_WaitForInitialSync = SOSCCWaitForInitialSync_Server, + .soscc_WaitForInitialSyncWithAnalytics = SOSCCWaitForInitialSyncWithAnalytics_Server, + .soscc_CopyYetToSyncViewsList = SOSCCCopyYetToSyncViewsList_Server, + .soscc_SetEscrowRecords = SOSCCSetEscrowRecord_Server, + .soscc_CopyEscrowRecords = SOSCCCopyEscrowRecord_Server, + .sosbskb_WrapToBackupSliceKeyBagForView = SOSWrapToBackupSliceKeyBagForView_Server, + .soscc_CopyAccountState = SOSCCCopyAccountState_Server, + .soscc_DeleteAccountState = SOSCCDeleteAccountState_Server, + .soscc_CopyEngineData = SOSCCCopyEngineData_Server, + .soscc_DeleteEngineState = SOSCCDeleteEngineState_Server, + .soscc_AccountHasPublicKey = SOSCCAccountHasPublicKey_Server, + .soscc_AccountIsNew = SOSCCAccountIsNew_Server, + .soscc_IsThisDeviceLastBackup = SOSCCkSecXPCOpIsThisDeviceLastBackup_Server, + .soscc_SOSCCPeersHaveViewsEnabled = SOSCCPeersHaveViewsEnabled_Server, + .soscc_RegisterRecoveryPublicKey = SOSCCRegisterRecoveryPublicKey_Server, + .soscc_CopyRecoveryPublicKey = SOSCCCopyRecoveryPublicKey_Server, + .soscc_CopyBackupInformation = SOSCCCopyBackupInformation_Server, + .soscc_SOSCCMessageFromPeerIsPending = SOSCCMessageFromPeerIsPending_Server, + .soscc_SOSCCSendToPeerIsPending = SOSCCSendToPeerIsPending_Server, +#endif /* SECUREOBJECTSYNC */ +}; + +#if SECD_SERVER && SECUREOBJECTSYNC +static CFTypeRef +delayedSOSSharedObject(void) +{ + return SOSKeychainAccountGetSharedAccount(); +} +#endif + +void securityd_init_local_spi(void) { + gSecurityd = &securityd_spi; +#if SECD_SERVER && SECUREOBJECTSYNC + // We're the server: we need to handle this locally. Bring them up and set them in the global object. + securityd_spi.soscc_status = delayedSOSSharedObject; +#endif + // You're trying to bring up a (non-trustd) 'securityd'. Create the local handler for securityd XPCs. + securityd_spi.secd_xpc_server = SecCreateLocalCFSecuritydXPCServer(); +} + +void securityd_init_server(void) { + securityd_init_local_spi(); + + // Lazy initialization is no good; bring up the keychain on start + // If you want to not do this, you'll need to check the APSConnection Mach mailbox for messages here instead (good luck) + CFErrorRef cferror = nil; + bool keychainAlive = kc_with_dbt(false, &cferror, ^bool(SecDbConnectionRef dbt) { + secnotice("keychain", "Keychain initialized!"); + return true; + }); + if(!keychainAlive || cferror) { + secerror("Couldn't bring up keychain: %@", cferror); + } + CFReleaseNull(cferror); + + SecdLoadWatchDog(); +} + +void securityd_init(CFURLRef home_path) { + if (home_path) { + SetCustomHomeURL(home_path); + } + + securityd_init_server(); +#ifdef LIBTRUSTD + trustd_init_server(); +#endif +} diff --git a/keychain/securityd/spi.h b/keychain/securityd/spi.h new file mode 100644 index 00000000..efe159fe --- /dev/null +++ b/keychain/securityd/spi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _SECURITYD_SPI_H_ +#define _SECURITYD_SPI_H_ + +#include "utilities/SecCFError.h" +#include +#include + +__BEGIN_DECLS + +/* Calling this function initializes the spi interface in the library to call + directly into the backend. It uses home_dir for root of files if specified. + This function only initializes the trust spi interface if libtrustd is linked + by the caller and LIBTRUSTD=1 is specified. */ +void securityd_init(CFURLRef home_dir); + +// Don't call either of these functions unless you are really securityd +void securityd_init_server(void); +void securityd_init_local_spi(void); + +__END_DECLS + +#endif /* _SECURITYD_SPI_H_ */ diff --git a/keychain/tpctl/main.swift b/keychain/tpctl/main.swift index 4ea34015..4f20f4b7 100644 --- a/keychain/tpctl/main.swift +++ b/keychain/tpctl/main.swift @@ -652,7 +652,7 @@ for command in commands { case .reset: os_log("resetting (%@, %@)", log: tplogDebug, type: .default, container, context) - tpHelper.reset(withContainer: container, context: context) { error in + tpHelper.reset(withContainer: container, context: context, resetReason: .userInitiatedReset) { error in guard error == nil else { print("Error during reset:", error!) return diff --git a/libsecurity_smime/lib/cmssiginfo.c b/libsecurity_smime/lib/cmssiginfo.c index 18ab6d45..c0d70ea9 100644 --- a/libsecurity_smime/lib/cmssiginfo.c +++ b/libsecurity_smime/lib/cmssiginfo.c @@ -62,6 +62,8 @@ #include #include +#include + #define HIDIGIT(v) (((v) / 10) + '0') #define LODIGIT(v) (((v) % 10) + '0') @@ -77,61 +79,18 @@ static OSStatus DER_UTCTimeToCFDate(const SecAsn1Item * utcTime, CFAbsoluteTime *date) { - char *string = (char *)utcTime->Data; - int year, month, mday, hour, minute, second, hourOff, minOff; - - /* Verify time is formatted properly and capture information */ - second = 0; - hourOff = 0; - minOff = 0; - CAPTURE(year,string+0,loser); - if (year < 50) { - /* ASSUME that year # is in the 2000's, not the 1900's */ - year += 2000; - } else { - year += 1900; - } - CAPTURE(month,string+2,loser); - if ((month == 0) || (month > 12)) goto loser; - CAPTURE(mday,string+4,loser); - if ((mday == 0) || (mday > 31)) goto loser; - CAPTURE(hour,string+6,loser); - if (hour > 23) goto loser; - CAPTURE(minute,string+8,loser); - if (minute > 59) goto loser; - if (ISDIGIT(string[10])) { - CAPTURE(second,string+10,loser); - if (second > 59) goto loser; - string += 2; - } - if (string[10] == '+') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - } else if (string[10] == '-') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - hourOff = -hourOff; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - minOff = -minOff; - } else if (string[10] != 'Z') { - goto loser; + CFErrorRef error = NULL; + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + CFAbsoluteTime result = SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME, utcTime->Data, utcTime->Length, &error); + if (error) { + CFReleaseNull(error); + return SECFailure; } - if (hourOff == 0 && minOff == 0) { - *date = CFAbsoluteTimeForGregorianZuluMoment(year, month, mday, hour, minute, second); - } else { - CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, (hourOff * 60 + minOff) * 60); - *date = CFAbsoluteTimeForGregorianMoment(tz, year, month, mday, hour, minute, second); - CFReleaseSafe(tz); + if (date) { + *date = result; } - return SECSuccess; - -loser: - return SECFailure; } static OSStatus @@ -141,20 +100,24 @@ DER_CFDateToUTCTime(CFAbsoluteTime date, SecAsn1Item * utcTime) utcTime->Length = 13; utcTime->Data = d = PORT_Alloc(13); - if (!utcTime->Data) - return SECFailure; + if (!utcTime->Data) { + return SECFailure; + } __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; __block bool result; SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second); }); - if (!result) + if (!result) { return SECFailure; + } - /* UTC time does not handle the years before 1950 */ - if (year < 1950) + /* UTC time does not handle the years before 1950 or after 2049 */ + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + if (year < 1950 || year > 2049) { return SECFailure; + } /* remove the century since it's added to the year by the CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */ diff --git a/secdtests/main.m b/secdtests/main.m index 822f2429..67e14ff3 100644 --- a/secdtests/main.m +++ b/secdtests/main.m @@ -16,7 +16,7 @@ #include "keychain/ckks/CKKS.h" -#include +#include "keychain/securityd/spi.h" int main(int argc, char * const *argv) { diff --git a/secdtests/testlist.h b/secdtests/testlist.h index 65e1aef4..8294cc74 100644 --- a/secdtests/testlist.h +++ b/secdtests/testlist.h @@ -1,2 +1,2 @@ /* Don't preent multiple inclusions of this file */ -#include +#include "keychain/securityd/Regressions/secd_regressions.h" diff --git a/secdxctests/KeychainAPITests.m b/secdxctests/KeychainAPITests.m index d2cdeec2..5c54545b 100644 --- a/secdxctests/KeychainAPITests.m +++ b/secdxctests/KeychainAPITests.m @@ -164,6 +164,8 @@ static void SecDbTestCorruptionHandler(void) } - (void)testCorruptionHandler { + __security_simulatecrash_enable(false); + SecDbCorruptionExitHandler = SecDbTestCorruptionHandler; sema = dispatch_semaphore_create(0); @@ -204,6 +206,8 @@ static void SecDbTestCorruptionHandler(void) } - (void)testRecoverFromCorruption { + __security_simulatecrash_enable(false); + // Setup does a reset, but that doesn't create the db yet so let's sneak in first __block struct stat before = {}; WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *filename) { diff --git a/secdxctests/KeychainCryptoTests.m b/secdxctests/KeychainCryptoTests.m index 1cd6e95e..bdf33b1b 100644 --- a/secdxctests/KeychainCryptoTests.m +++ b/secdxctests/KeychainCryptoTests.m @@ -430,6 +430,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testKeychainCorruptionAddOverCorruptedEntry { + __security_simulatecrash_enable(false); + CFTypeRef foundItem = NULL; NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding], @@ -460,6 +462,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testKeychainCorruptionUpdateCorruptedEntry { + __security_simulatecrash_enable(false); + CFTypeRef foundItem = NULL; NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding], @@ -594,6 +598,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testRecoverFromBadMetadataKey { + __security_simulatecrash_enable(false); + // Disable caching, so we can change AKS encrypt/decrypt id mockSecDbKeychainMetadataKeyStore = OCMClassMock([SecDbKeychainMetadataKeyStore class]); OCMStub([mockSecDbKeychainMetadataKeyStore cachingEnabled]).andReturn(false); diff --git a/secdxctests/KeychainXCTest.m b/secdxctests/KeychainXCTest.m index d763f70b..bab2a47c 100644 --- a/secdxctests/KeychainXCTest.m +++ b/secdxctests/KeychainXCTest.m @@ -132,6 +132,8 @@ - (void)setUp { + __security_simulatecrash_enable(true); + [super setUp]; self.lockState = LockStateUnlocked; diff --git a/securityd/etc/com.apple.securityd.sb b/securityd/etc/com.apple.securityd.sb index a6145ad0..c91b48fb 100644 --- a/securityd/etc/com.apple.securityd.sb +++ b/securityd/etc/com.apple.securityd.sb @@ -6,20 +6,20 @@ ;;; (version 1) -(allow (with report) default) -(allow (with report) file-map-executable process-info* nvram*) -(allow (with report) dynamic-code-generation) - +(deny default) +(deny file-map-executable process-info* nvram*) +(deny dynamic-code-generation) (deny mach-priv-host-port) (import "system.sb") (import "com.apple.corefoundation.sb") (corefoundation) -(allow file-read-metadata) -;; We inspect all the binaries -(allow file-read* - (subpath "/")) +;; We inspect all the binaries, +;; resolve symlinks, realpath(3), and equivalents, +;; read preference files in-process +(allow file-read*) + (allow file-write* (subpath "/private/var/db/mds")) (allow file-ioctl (literal "/dev/auditsessions")) diff --git a/sslViewer/sslEcdsa.cpp b/sslViewer/sslEcdsa.cpp index cb231ba5..b45ae859 100644 --- a/sslViewer/sslEcdsa.cpp +++ b/sslViewer/sslEcdsa.cpp @@ -27,7 +27,7 @@ #include #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif diff --git a/sslViewer/sslServer.cpp b/sslViewer/sslServer.cpp index 33b2bb64..fefc0898 100644 --- a/sslViewer/sslServer.cpp +++ b/sslViewer/sslServer.cpp @@ -48,7 +48,7 @@ #include "SecurityTool/sharedTool/print_cert.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif /* Set true when PR-3074739 is merged to TOT */ diff --git a/tests/SecDbBackupTests/SecDbBackupTests.m b/tests/SecDbBackupTests/SecDbBackupTests.m index 6c51b3d9..cb8d0e72 100644 --- a/tests/SecDbBackupTests/SecDbBackupTests.m +++ b/tests/SecDbBackupTests/SecDbBackupTests.m @@ -6,7 +6,7 @@ // #import -#import "securityd/SecDbBackupManager.h" +#import "keychain/securityd/SecDbBackupManager.h" #if !SECDB_BACKUPS_ENABLED @@ -18,7 +18,7 @@ #else // SECDB_BACKUPS_ENABLED -#import "securityd/SecDbBackupManager_Internal.h" +#import "keychain/securityd/SecDbBackupManager_Internal.h" #import "CKKS.h" #import diff --git a/tests/TrustTests/DaemonTests/LoggingServerTests.m b/tests/TrustTests/DaemonTests/LoggingServerTests.m index a577e8ee..6f7b6f53 100644 --- a/tests/TrustTests/DaemonTests/LoggingServerTests.m +++ b/tests/TrustTests/DaemonTests/LoggingServerTests.m @@ -8,7 +8,7 @@ #include #import -#import "../../../OSX/sec/securityd/SecTrustLoggingServer.h" +#import "trust/trustd/SecTrustLoggingServer.h" @interface LoggingServerTests : XCTestCase @end diff --git a/tests/TrustTests/EvaluationTests/CTTests.m b/tests/TrustTests/EvaluationTests/CTTests.m index d7e1fc91..7d058ee7 100644 --- a/tests/TrustTests/EvaluationTests/CTTests.m +++ b/tests/TrustTests/EvaluationTests/CTTests.m @@ -31,7 +31,7 @@ #include #include #include -#include +#include "trust/trustd/OTATrustUtilities.h" #if !TARGET_OS_BRIDGE #import @@ -1739,9 +1739,9 @@ errOut: CFReleaseNull(trust); } -// test apple subCA after date without CT passes +// test apple subCA after date without CT fails - (void) testAppleSubCAException { - SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, livability = NULL; + SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, deprecatedSSLServer = NULL; SecTrustRef trust = NULL; SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("bbasile-test.scv.apple.com")); NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:576000000.0]; // April 3, 2019 at 9:00:00 AM PDT @@ -1751,16 +1751,48 @@ errOut: errOut, fail("failed to create geotrust root")); require_action(appleISTCA8G1 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA8G1"], errOut, fail("failed to create apple IST CA")); - require_action(livability = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"deprecatedSSLServer"], + require_action(deprecatedSSLServer = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"deprecatedSSLServer"], errOut, fail("failed to create deprecated SSL Server cert")); - certs = @[ (__bridge id)livability, (__bridge id)appleISTCA8G1 ]; + certs = @[ (__bridge id)deprecatedSSLServer, (__bridge id)appleISTCA8G1 ]; enforcement_anchors = @[ (__bridge id)geoTrustRoot ]; require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); - ok(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert failed"); +#if !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert passed"); +#endif + +errOut: + CFReleaseNull(geoTrustRoot); + CFReleaseNull(appleISTCA8G1); + CFReleaseNull(deprecatedSSLServer); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + +- (void) testBasejumper { + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, deprecatedSSLServer = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("basejumper.apple.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:576000000.0]; // April 3, 2019 at 9:00:00 AM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot"], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA2_Baltimore"], + errOut, fail("failed to create apple IST CA")); + require_action(deprecatedSSLServer = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"basejumper"], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)deprecatedSSLServer, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper cert failed"); #if !TARGET_OS_BRIDGE // bridgeOS doesn't ever enforce CT @@ -1768,7 +1800,7 @@ errOut: CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanTrue, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert succeeded with allowlist disabled"); + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper succeeded with allowlist disabled"); CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanFalse, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); @@ -1776,20 +1808,20 @@ errOut: CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistApple"), kCFBooleanTrue, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert succeeded with Apple allowlist disabled"); + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper succeeded with Apple allowlist disabled"); CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistApple"), kCFBooleanFalse, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); #endif // !TARGET_OS_BRIDGE errOut: - CFReleaseNull(geoTrustRoot); - CFReleaseNull(appleISTCA8G1); - CFReleaseNull(livability); + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(deprecatedSSLServer); CFReleaseNull(policy); CFReleaseNull(trust); } -// test google subCA after date without CT passes +// test google subCA after date without CT fails - (void) testGoogleSubCAException { SecCertificateRef globalSignRoot = NULL, googleIAG3 = NULL, google = NULL; SecTrustRef trust = NULL; @@ -1810,26 +1842,9 @@ errOut: require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); - ok(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert failed"); - #if !TARGET_OS_BRIDGE - // bridgeOS doesn't ever enforce CT - // Test with generic CT allowlist disable - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanTrue, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert succeeded with allowlist disabled"); - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanFalse, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - - // Test with Google allowlist disable - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistGoogle"), kCFBooleanTrue, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert succeeded with Goole allowlist disabled"); - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistGoogle"), kCFBooleanFalse, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); -#endif // !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert passed"); +#endif errOut: CFReleaseNull(globalSignRoot); @@ -1838,4 +1853,45 @@ errOut: CFReleaseNull(policy); CFReleaseNull(trust); } + +// If pinning is disabled, pinned hostnames should continue to be exempt from CT +- (void) testSystemwidePinningDisable { + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, pinnedNonCT = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("iphonesubmissions.apple.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:580000000.0]; // May 19, 2019 at 4:06:40 PM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot"], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA2_Baltimore"], + errOut, fail("failed to create apple IST CA")); + require_action(pinnedNonCT = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"iphonesubmissions"], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)pinnedNonCT, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "pinned non-CT cert failed"); + + // Test with pinning disabled + [defaults setBool:YES forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + SecTrustSetNeedsEvaluation(trust); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "pinned non-CT failed with pinning disabled"); + [defaults setBool:NO forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + +errOut: + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(pinnedNonCT); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + @end diff --git a/tests/TrustTests/EvaluationTests/PolicyTests.m b/tests/TrustTests/EvaluationTests/PolicyTests.m index 121f7414..e844ab74 100644 --- a/tests/TrustTests/EvaluationTests/PolicyTests.m +++ b/tests/TrustTests/EvaluationTests/PolicyTests.m @@ -54,6 +54,7 @@ #include #include #include +#include #import "TrustEvaluationTestCase.h" #include "../TestMacroConversions.h" @@ -96,4 +97,49 @@ const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies- }]; } +- (void)testPinningDisable +{ + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, pinnedNonCT = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("caldav.icloud.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:580000000.0]; // May 19, 2019 at 4:06:40 PM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"AppleISTCA2G1-Baltimore" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create apple IST CA")); + require_action(pinnedNonCT = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"caldav" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)pinnedNonCT, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetPinningPolicyName(trust, kSecPolicyNameAppleAMPService), errOut, fail("failed to set policy name")); +#if !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "pinning against wrong profile succeeded"); +#endif + + // Test with pinning disabled + [defaults setBool:YES forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + SecTrustSetNeedsEvaluation(trust); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "failed to disable pinning"); + [defaults setBool:NO forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + +errOut: + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(pinnedNonCT); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + @end diff --git a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h index 00311bcd..14836b9f 100644 --- a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h +++ b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h @@ -29,22 +29,28 @@ #include #include "../TrustEvaluationTestHelpers.h" +NS_ASSUME_NONNULL_BEGIN + @interface TrustEvaluationTestCase : XCTestCase -- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef _Nonnull)cert trustSettings:(id _Nonnull)trustSettings; // returns a persistent ref for call to removeTrustSettings, takes a dictionary or array of trust settings -- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef _Nonnull)cert; // returns a persistent ref for call to removeTrustSettings -- (void)removeTrustSettingsForCert:(SecCertificateRef _Nonnull)cert persistentRef:(id _Nullable)persistentRef; -- (void)setTestRootAsSystem:(const uint8_t* _Nonnull)sha256hash; // this is expected to be a 32-byte array +- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef)cert trustSettings:(id)trustSettings; // returns a persistent ref for call to removeTrustSettings, takes a dictionary or array of trust settings +- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef)cert; // returns a persistent ref for call to removeTrustSettings +- (void)removeTrustSettingsForCert:(SecCertificateRef)cert persistentRef:(id _Nullable)persistentRef; +- (void)setTestRootAsSystem:(const uint8_t*)sha256hash; // this is expected to be a 32-byte array - (void)removeTestRootAsSystem; // ported from regressionBase -- (void)runCertificateTestForDirectory:(SecPolicyRef _Nonnull)policy subDirectory:(NSString * _Nonnull)resourceSubDirectory verifyDate:(NSDate* _Nonnull)date; +- (void)runCertificateTestForDirectory:(SecPolicyRef)policy subDirectory:(NSString *)resourceSubDirectory verifyDate:(NSDate*)date; + +- (id _Nullable) CF_RETURNS_RETAINED SecCertificateCreateFromResource:(NSString * )name subdirectory:(NSString *)dir; @end /* Use this interface to get a SecCertificateRef that has the same CFTypeID * as used by the Security framework */ CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * _Nonnull der_bytes, CFIndex der_length); +SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * der_bytes, CFIndex der_length); CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef _Nonnull cert); +SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef cert); + +NS_ASSUME_NONNULL_END #endif /* _TRUSTTESTS_EVALUATION_TESTCASE_H_ */ diff --git a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m index 72596ab5..76dfe001 100644 --- a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m +++ b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m @@ -22,7 +22,7 @@ * */ #import -#include "OSX/trustd/trustd_spi.h" +#include "trust/trustd/trustd_spi.h" #include #include #include @@ -171,14 +171,24 @@ const CFStringRef kTestSystemRootKey = CFSTR("TestSystemRoot"); CFPreferencesAppSynchronize(kSecurityPreferencesDomain); } +- (id _Nullable) CF_RETURNS_RETAINED SecCertificateCreateFromResource:(NSString *)name + subdirectory:(NSString *)dir +{ + NSURL *url = [[NSBundle bundleForClass:[self class]] URLForResource:name withExtension:@".cer" + subdirectory:dir]; + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData); + return (__bridge id)cert; +} + /* MARK: run test methods from regressionBase */ - (void)runOneLeafTest:(SecPolicyRef)policy - anchors:(NSArray *)anchors - intermediates:(NSArray *)intermediates - leafPath:(NSString *)path - expectedResult:(bool)expectedResult - expectations:(NSObject *)expectations - verifyDate:(NSDate *)date + anchors:(NSArray *)anchors + intermediates:(NSArray *)intermediates + leafPath:(NSString *)path + expectedResult:(bool)expectedResult + expectations:(NSObject *)expectations + verifyDate:(NSDate *)date { NSString* fileName = [path lastPathComponent]; NSString *reason = NULL; diff --git a/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m b/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m index 8e8e0b70..2e5c8dea 100644 --- a/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m +++ b/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m @@ -32,7 +32,7 @@ #include #include "OSX/sec/Security/SecFramework.h" #include "OSX/utilities/SecCFWrappers.h" -#include +#include "trust/trustd/OTATrustUtilities.h" #include #include #include diff --git a/tests/secdmockaks/mockaksKeychain.m b/tests/secdmockaks/mockaksKeychain.m index 120d8fa0..27662ddd 100644 --- a/tests/secdmockaks/mockaksKeychain.m +++ b/tests/secdmockaks/mockaksKeychain.m @@ -136,6 +136,9 @@ - (void)testSecItemServerDeleteAll { + [self addAccessGroup:@"com.apple.bluetooth"]; + [self addAccessGroup:@"lockdown-identities"]; + // BT root key, should not be deleted NSMutableDictionary* bt = [@{ (id)kSecClass : (id)kSecClassGenericPassword, diff --git a/tests/secdmockaks/mockaksxcbase.h b/tests/secdmockaks/mockaksxcbase.h index 63ec0791..0ca77a31 100644 --- a/tests/secdmockaks/mockaksxcbase.h +++ b/tests/secdmockaks/mockaksxcbase.h @@ -14,6 +14,8 @@ - (NSString*)createKeychainDirectoryWithSubPath:(NSString*)subpath; +- (void)addAccessGroup:(NSString *)accessGroup; + @end #endif /* mockaksxcbase_h */ diff --git a/tests/secdmockaks/mockaksxcbase.m b/tests/secdmockaks/mockaksxcbase.m index 3d111f3e..22dfdc0a 100644 --- a/tests/secdmockaks/mockaksxcbase.m +++ b/tests/secdmockaks/mockaksxcbase.m @@ -11,6 +11,7 @@ #import "SecItemPriv.h" #import "SecItemServer.h" #import "spi.h" +#include #import #import #import @@ -23,12 +24,21 @@ NSString* homeDirUUID; +@interface mockaksxcbase () +@property NSArray* originalAccessGroups; +@property NSMutableArray* currentAccessGroups; +@end + + @implementation mockaksxcbase + (void)setUp { [super setUp]; + securityd_init_local_spi(); + securityd_init(NULL); + SecCKKSDisable(); /* * Disable all of SOS syncing since that triggers retains of database @@ -43,6 +53,12 @@ NSString* homeDirUUID; homeDirUUID = [[NSUUID UUID] UUIDString]; } +- (void)addAccessGroup:(NSString *)accessGroup +{ + [self.currentAccessGroups addObject:accessGroup]; + SecAccessGroupsSetCurrent((__bridge CFArrayRef)self.currentAccessGroups); +} + - (NSString*)createKeychainDirectoryWithSubPath:(NSString*)suffix { NSError* error; @@ -62,6 +78,8 @@ NSString* homeDirUUID; - (void)setUp { [super setUp]; + self.originalAccessGroups = (__bridge NSArray *)SecAccessGroupsGetCurrent(); + self.currentAccessGroups = [self.originalAccessGroups mutableCopy]; NSString* testName = [self.name componentsSeparatedByString:@" "][1]; testName = [testName stringByReplacingOccurrencesOfString:@"]" withString:@""]; @@ -71,20 +89,24 @@ NSString* homeDirUUID; [self createKeychainDirectory]; SetCustomHomeURLString((__bridge CFStringRef) self.testHomeDirectory); - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - securityd_init(NULL); - }); SecKeychainDbReset(NULL); // Actually load the database. kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { return false; }); } +- (void)tearDown +{ + SecAccessGroupsSetCurrent((__bridge CFArrayRef)self.originalAccessGroups); + [super tearDown]; +} + + (void)tearDown { SetCustomHomeURLString(NULL); SecKeychainDbReset(NULL); } + + @end diff --git a/trust/SecCertificate.h b/trust/SecCertificate.h deleted file mode 100644 index fcadd01d..00000000 --- a/trust/SecCertificate.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecCertificate - The functions provided in SecCertificate.h implement and manage a - particular type of keychain item that represents a X.509 public key - certificate. You can store a certificate in a keychain, but a - certificate can also be a transient object. - - You can use a certificate as a keychain item in most functions. -*/ - -#ifndef _SECURITY_SECCERTIFICATE_H_ -#define _SECURITY_SECCERTIFICATE_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#if SEC_OS_OSX -#define _SECURITY_VERSION_GREATER_THAN_57610_ - -#include -#include -#endif // SEC_OS_OSX - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @function SecCertificateGetTypeID - @abstract Returns the type identifier of SecCertificate instances. - @result The CFTypeID of SecCertificate instances. - */ -CFTypeID SecCertificateGetTypeID(void) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecCertificateCreateWithData - @abstract Create a certificate given it's DER representation as a CFData. - @param allocator CFAllocator to allocate the certificate with. - @param data DER encoded X.509 certificate. - @result Return NULL if the passed-in data is not a valid DER-encoded - X.509 certificate, return a SecCertificateRef otherwise. - */ -__nullable -SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef __nullable allocator, CFDataRef data) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecCertificateCopyData - @abstract Return the DER representation of an X.509 certificate. - @param certificate SecCertificate object created with - SecCertificateCreateWithData(). - @result DER encoded X.509 certificate. - */ -CFDataRef SecCertificateCopyData(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecCertificateCopySubjectSummary - @abstract Return a simple string which hopefully represents a human - understandable summary. - @param certificate A reference to the certificate from which to derive - the subject summary string. - @discussion All the data in this string comes from the certificate itself - and thus it's in whatever language the certificate itself is in. - @result A CFStringRef which the caller should CFRelease() once it's no - longer needed. - */ -__nullable -CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecCertificateCopyCommonName - @abstract Retrieves the common name of the subject of a given certificate. - @param certificate A reference to the certificate from which to retrieve the common name. - @param commonName On return, a reference to the common name. Your code must release this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion All the data in this string comes from the certificate itself, and thus it's in whatever language the certificate itself is in. - Note that the certificate's common name field may not be present, or may be inadequate to describe the certificate; for display purposes, - you should consider using SecCertificateCopySubjectSummary instead of this function. - */ -OSStatus SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef * __nonnull CF_RETURNS_RETAINED commonName) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_10_3); - -/*! - @function SecCertificateCopyEmailAddresses - @abstract Returns an array of zero or more email addresses for the subject of a given certificate. - @param certificate A reference to the certificate from which to retrieve the email addresses. - @param emailAddresses On return, an array of zero or more CFStringRef elements corresponding to each email address found. - Your code must release this array reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef * __nonnull CF_RETURNS_RETAINED emailAddresses) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_10_3); - -/*! - @function SecCertificateCopyNormalizedIssuerSequence - @abstract Return the certificate's normalized issuer - @param certificate The certificate from which to get values - @discussion The issuer is a sequence in the format used by SecItemCopyMatching. The content returned is a DER-encoded X.509 distinguished name. For a display version of the issuer, call SecCertificateCopyValues. The caller must CFRelease the value returned. - */ -__nullable -CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12_4, __IPHONE_10_3); - -/*! - @function SecCertificateCopyNormalizedSubjectSequence - @abstract Return the certificate's normalized subject - @param certificate The certificate from which to get values - @discussion The subject is a sequence in the format used by SecItemCopyMatching. The content returned is a DER-encoded X.509 distinguished name. For a display version of the subject, call SecCertificateCopyValues. The caller must CFRelease the value returned. - */ -__nullable -CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12_4, __IPHONE_10_3); - -/*! - @function SecCertificateCopyKey - @abstract Retrieves the public key for a given certificate. - @param certificate A reference to the certificate from which to retrieve the public key. - @result A reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. If the public key has an encoding issue or uses an unsupported algorithm, the returned reference will be null. - @discussion RSA and ECDSA public keys are supported. All other public key algorithms are unsupported. - */ -__nullable CF_RETURNS_RETAINED -SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate) - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); - -#if TARGET_OS_IPHONE -/*! - @function SecCertificateCopyPublicKey - @abstract Retrieves the public key for a given certificate. - @param certificate A reference to the certificate from which to retrieve the public key. - @result A reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. - @discussion NOTE: Deprecated in iOS 12.0; use SecCertificateCopyKey instead for cross-platform availability. - */ -__nullable -SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate) - API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", ios(10.3, 12.0)) API_UNAVAILABLE(macos, iosmac); -#endif - -#if TARGET_OS_OSX -/*! - @function SecCertificateCopyPublicKey - @abstract Retrieves the public key for a given certificate. - @param certificate A reference to the certificate from which to retrieve the public key. - @param key On return, a reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion NOTE: Deprecated in macOS 10.14; use SecCertificateCopyKey instead for cross-platform availability. - */ -OSStatus SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef * __nonnull CF_RETURNS_RETAINED key) - API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", macos(10.3, 10.14)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); -#endif - -/*! - @function SecCertificateCopySerialNumberData - @abstract Return the certificate's serial number. - @param certificate The certificate from which to get values. - @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. - @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. - */ -__nullable -CFDataRef SecCertificateCopySerialNumberData(SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); - -#if TARGET_OS_IPHONE -/*! - @function SecCertificateCopySerialNumber - @abstract Return the certificate's serial number. - @param certificate The certificate from which to get values. - @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in iOS 11.0; use SecCertificateCopySerialNumberData instead for cross-platform availability. - */ -__nullable -CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate) - API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", ios(10.3, 11.0)) API_UNAVAILABLE(macos, iosmac); -#endif - -#if TARGET_OS_OSX -/*! - @function SecCertificateCopySerialNumber - @abstract Return the certificate's serial number. - @param certificate The certificate from which to get values. - @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. - @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in macOS 10.13; use SecCertificateCopySerialNumberData instead for cross-platform availability. - */ -__nullable -CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) - API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", macos(10.7, 10.13)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); -#endif - -/* - * Legacy functions (OS X only) - */ -#if SEC_OS_OSX -/*! - @enum CertificateItemAttributes - @abstract Indicates the type of a certificate item attribute. - @constant kSecSubjectItemAttr Indicates a DER-encoded subject distinguished name. - @constant kSecIssuerItemAttr Indicates a DER-encoded issuer distinguished name. - @constant kSecSerialNumberItemAttr Indicates a DER-encoded certificate serial number (without the tag and length). - @constant kSecPublicKeyHashItemAttr Indicates a public key hash. - @constant kSecSubjectKeyIdentifierItemAttr Indicates a subject key identifier. - @constant kSecCertTypeItemAttr Indicates a certificate type. - @constant kSecCertEncodingItemAttr Indicates a certificate encoding. -*/ -enum -{ - kSecSubjectItemAttr = 'subj', - kSecIssuerItemAttr = 'issu', - kSecSerialNumberItemAttr = 'snbr', - kSecPublicKeyHashItemAttr = 'hpky', - kSecSubjectKeyIdentifierItemAttr = 'skid', - kSecCertTypeItemAttr = 'ctyp', - kSecCertEncodingItemAttr = 'cenc' -} /*DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER*/; - -#pragma mark ---- Certificate Operations ---- - -/*! - @function SecCertificateCreateFromData - @abstract Creates a certificate based on the input data, type, and encoding. - @param data A pointer to the certificate data. - @param type The certificate type as defined in cssmtype.h. - @param encoding The certificate encoding as defined in cssmtype.h. - @param certificate On return, a reference to the newly created certificate. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7 Please use the SecCertificateCreateWithData API instead. -*/ -OSStatus SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificate) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateAddToKeychain - @abstract Adds a certificate to the specified keychain. - @param certificate A reference to a certificate. - @param keychain A reference to the keychain in which to add the certificate. Pass NULL to add the certificate to the default keychain. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is successful only if the certificate was created using the SecCertificateCreateFromData or - SecCertificateCreateWithData functions, and the certificate has not yet been added to the specified keychain. -*/ -OSStatus SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef __nullable keychain) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); - -/*! - @function SecCertificateGetData - @abstract Retrieves the data for a given certificate. - @param certificate A reference to the certificate from which to retrieve the data. - @param data On return, the CSSM_DATA structure pointed to by data is filled in. You must allocate the space for a CSSM_DATA structure before calling this function. This data pointer is only guaranteed to remain valid as long as the certificate remains unchanged and valid. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyData API instead. -*/ -OSStatus SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateGetType - @abstract Retrieves the type for a given certificate. - @param certificate A reference to the certificate from which to obtain the type. - @param certificateType On return, the certificate type of the certificate. Certificate types are defined in cssmtype.h. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. -*/ -OSStatus SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateGetSubject - @abstract Retrieves the subject name for a given certificate. - @param certificate A reference to the certificate from which to obtain the subject name. - @param subject On return, a pointer to a CSSM_X509_NAME struct which contains the subject's X.509 name (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Prior to Mac OS X 10.5, this function did not return any output in the subject parameter. Your code should check the returned pointer value (in addition to the function result) before attempting to use it. - For example: - const CSSM_X509_NAME *subject = NULL; - OSStatus status = SecCertificateGetSubject(certificate, &subject); - if ( (status == errSecSuccess) && (subject != NULL) ) { - // subject is valid - } - This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. -*/ -OSStatus SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME * __nullable * __nonnull subject) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateGetIssuer - @abstract Retrieves the issuer name for a given certificate. - @param certificate A reference to the certificate from which to obtain the issuer name. - @param issuer On return, a pointer to a CSSM_X509_NAME struct which contains the issuer's X.509 name (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Prior to Mac OS X 10.5, this function did not return any output in the issuer parameter. Your code should check the returned pointer value (in addition to the function result) before attempting to use it. - For example: - const CSSM_X509_NAME *issuer = NULL; - OSStatus status = SecCertificateGetIssuer(certificate, &issuer); - if ( (status == errSecSuccess) && (issuer != NULL) ) { - // issuer is valid - } - This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. -*/ -OSStatus SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME * __nullable * __nonnull issuer) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateGetCLHandle - @abstract Retrieves the certificate library handle for a given certificate. - @param certificate A reference to the certificate from which to obtain the certificate library handle. - @param clHandle On return, the certificate library handle of the given certificate. This handle remains valid at least as long as the certificate does. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. -*/ -OSStatus SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateGetAlgorithmID - @abstract Retrieves the algorithm identifier for a given certificate. - @param certificate A reference to the certificate from which to retrieve the algorithm identifier. - @param algid On return, a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER struct which identifies the algorithm for this certificate (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. - @result A result code. See "Security Error Codes" (SecBase.h). - discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. -*/ -OSStatus SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER * __nullable * __nonnull algid) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateCopyPreference - @abstract Returns the preferred certificate for the specified name and key usage. If a preferred certificate does not exist for the specified name and key usage, NULL is returned. - @param name A string containing an email address (RFC822) or other name for which a preferred certificate is requested. - @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to ignore this parameter. - @param certificate On return, a reference to the preferred certificate, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will typically be used to obtain the preferred encryption certificate for an email recipient. - This API is deprecated in 10.7. Please use the SecCertificateCopyPreferred API instead. -*/ -OSStatus SecCertificateCopyPreference(CFStringRef name, uint32 keyUsage, SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificate) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateCopyPreferred - @abstract Returns the preferred certificate for the specified name and key usage. If a preferred certificate does not exist for the specified name and key usage, NULL is returned. - @param name A string containing an email address (RFC822) or other name for which a preferred certificate is requested. - @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) - @result On return, a reference to the preferred certificate, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. - @discussion This function will typically be used to obtain the preferred encryption certificate for an email recipient. If a preferred certificate has not been set - for the supplied name, the returned reference will be NULL. Your code should then perform a search for possible certificates, using the SecItemCopyMatching API. - */ -__nullable -SecCertificateRef SecCertificateCopyPreferred(CFStringRef name, CFArrayRef __nullable keyUsage) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecCertificateSetPreference - @abstract Sets the preferred certificate for a specified name, key usage, and date. - @param certificate A reference to the certificate which will be preferred. - @param name A string containing an email address (RFC822) or other name for which a preferred certificate will be associated. - @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to avoid specifying a particular key usage. - @param date (optional) A date reference. If supplied, the preferred certificate will be changed only if this date is later than the currently saved setting. Pass NULL if this preference should not be restricted by date. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will typically be used to set the preferred encryption certificate for an email recipient, either manually (when encrypting email to a recipient) or automatically upon receipt of encrypted email. - This API is deprecated in 10.7. Plese use the SecCertificateSetPreferred API instead. -*/ -OSStatus SecCertificateSetPreference(SecCertificateRef certificate, CFStringRef name, uint32 keyUsage, CFDateRef __nullable date) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/*! - @function SecCertificateSetPreferred - @abstract Sets the preferred certificate for a specified name and optional key usage. - @param certificate A reference to the preferred certificate. If NULL is passed, any existing preference for the specified name is cleared instead. - @param name A string containing an email address (RFC822) or other name for which a preferred certificate will be associated. - @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will typically be used to set the preferred encryption certificate for an email recipient, either manually (when encrypting email to a recipient) - or automatically upon receipt of encrypted email. -*/ -OSStatus SecCertificateSetPreferred(SecCertificateRef __nullable certificate, CFStringRef name, CFArrayRef __nullable keyUsage) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @typedef SecKeyUsage - @abstract Flags to indicate key usages in the KeyUsage extension of a certificate - @constant kSecKeyUsageUnspecified No KeyUsage extension in certificate. - @constant kSecKeyUsageDigitalSignature DigitalSignature bit set in KeyUsage extension. - @constant kSecKeyUsageNonRepudiation NonRepudiation bit set in KeyUsage extension. - @constant kSecKeyUsageContentCommitment ContentCommitment bit set in KeyUsage extension. - @constant kSecKeyUsageKeyEncipherment KeyEncipherment bit set in KeyUsage extension. - @constant kSecKeyUsageDataEncipherment DataEncipherment bit set in KeyUsage extension. - @constant kSecKeyUsageKeyAgreement KeyAgreement bit set in KeyUsage extension. - @constant kSecKeyUsageKeyCertSign KeyCertSign bit set in KeyUsage extension. - @constant kSecKeyUsageCRLSign CRLSign bit set in KeyUsage extension. - @constant kSecKeyUsageEncipherOnly EncipherOnly bit set in KeyUsage extension. - @constant kSecKeyUsageDecipherOnly DecipherOnly bit set in KeyUsage extension. - @constant kSecKeyUsageCritical KeyUsage extension is marked critical. - @constant kSecKeyUsageAll For masking purposes, all SecKeyUsage values. - */ -typedef CF_OPTIONS(uint32_t, SecKeyUsage) { - kSecKeyUsageUnspecified = 0u, - kSecKeyUsageDigitalSignature = 1u << 0, - kSecKeyUsageNonRepudiation = 1u << 1, - kSecKeyUsageContentCommitment= 1u << 1, - kSecKeyUsageKeyEncipherment = 1u << 2, - kSecKeyUsageDataEncipherment = 1u << 3, - kSecKeyUsageKeyAgreement = 1u << 4, - kSecKeyUsageKeyCertSign = 1u << 5, - kSecKeyUsageCRLSign = 1u << 6, - kSecKeyUsageEncipherOnly = 1u << 7, - kSecKeyUsageDecipherOnly = 1u << 8, - kSecKeyUsageCritical = 1u << 31, - kSecKeyUsageAll = 0x7FFFFFFFu -}; - -/*! - @enum kSecPropertyKey - @abstract Constants used to access dictionary entries returned by SecCertificateCopyValues - @constant kSecPropertyKeyType The type of the entry - @constant kSecPropertyKeyLabel The label of the entry - @constant kSecPropertyKeyLocalizedLabel The localized label of the entry - @constant kSecPropertyKeyValue The value of the entry - */ - -extern const CFStringRef kSecPropertyKeyType __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyKeyLabel __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyKeyLocalizedLabel __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyKeyValue __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @enum kSecPropertyType - @abstract Public Constants for property list values returned by SecCertificateCopyValues - @discussion Note that kSecPropertyTypeTitle and kSecPropertyTypeError are defined in SecTrust.h -*/ -extern const CFStringRef kSecPropertyTypeWarning __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeSuccess __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeSection __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeData __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeString __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeURL __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeDate __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPropertyTypeArray API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0)); -extern const CFStringRef kSecPropertyTypeNumber API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0)); - -/*! - @function SecCertificateCopyValues - @abstract Creates a dictionary that represents a certificate's contents. - @param certificate The certificate from which to get values - @param keys An array of string OID values, or NULL. If present, this is - the subset of values from the certificate to return. If NULL, - all values will be returned. Only OIDs that are top level keys - in the returned dictionary can be specified. Unknown OIDs are - ignored. - @param error An optional pointer to a CFErrorRef. This value is - set if an error occurred. If not NULL the caller is - responsible for releasing the CFErrorRef. - @discussion The keys array will contain all of the keys used in the - returned dictionary. The top level keys in the returned - dictionary are OIDs, many of which are found in SecCertificateOIDs.h. - Each entry that is returned is itself a dictionary with four - entries, whose keys are kSecPropertyKeyType, kSecPropertyKeyLabel, - kSecPropertyKeyLocalizedLabel, kSecPropertyKeyValue. The label - entries may contain a descriptive (localized) string, or an - OID string. The kSecPropertyKeyType describes the type in the - value entry. The value entry may be any CFType, although it - is usually a CFStringRef, CFArrayRef or a CFDictionaryRef. -*/ -__nullable -CFDictionaryRef SecCertificateCopyValues(SecCertificateRef certificate, CFArrayRef __nullable keys, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecCertificateCopyLongDescription - @abstract Return the long description of a certificate - @param alloc The CFAllocator which should be used to allocate - memory for the dictionary and its storage for values. This - parameter may be NULL in which case the current default - CFAllocator is used. If this reference is not a valid - CFAllocator, the behavior is undefined. - @param certificate The certificate from which to retrieve the long description - @param error An optional pointer to a CFErrorRef. This value is - set if an error occurred. If not NULL the caller is - responsible for releasing the CFErrorRef. - @result A CFStringRef of the long description or NULL. If NULL and the error - parameter is supplied the error will be returned in the error parameter - @discussion Note that the format of this string may change in the future -*/ - -__nullable -CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef __nullable alloc, SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecCertificateCopyShortDescription - @abstract Return the short description of a certificate - @param alloc The CFAllocator which should be used to allocate - memory for the dictionary and its storage for values. This - parameter may be NULL in which case the current default - CFAllocator is used. If this reference is not a valid - CFAllocator, the behavior is undefined. - @param certificate The certificate from which to retrieve the short description - @param error An optional pointer to a CFErrorRef. This value is - set if an error occurred. If not NULL the caller is - responsible for releasing the CFErrorRef. - @result A CFStringRef of the short description or NULL. If NULL and the error - parameter is supplied the error will be returned in the error parameter - @discussion Note that the format of this string may change in the future -*/ - -__nullable -CFStringRef SecCertificateCopyShortDescription(CFAllocatorRef __nullable alloc, SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecCertificateCopyNormalizedIssuerContent - @abstract Return the certificate's normalized issuer - @param certificate The certificate from which to get values - @param error An optional pointer to a CFErrorRef. This value is - set if an error occurred. If not NULL the caller is - responsible for releasing the CFErrorRef. - @discussion The issuer is a sequence in the format used by - SecItemCopyMatching. The content returned is a DER-encoded - X.509 distinguished name. For a display version of the issuer, - call SecCertificateCopyValues. The caller must CFRelease - the value returned. -*/ - -__nullable -CFDataRef SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyNormalizedIssuerContent is deprecated. Use SecCertificateCopyNormalizedIssuerSequence instead."); - -/*! - @function SecCertificateCopyNormalizedSubjectContent - @abstract Return the certificate's normalized subject - @param certificate The certificate from which to get values - @param error An optional pointer to a CFErrorRef. This value is - set if an error occurred. If not NULL the caller is - responsible for releasing the CFErrorRef. - @discussion The subject is a sequence in the format used by - SecItemCopyMatching. The content returned is a DER-encoded - X.509 distinguished name. For a display version of the subject, - call SecCertificateCopyValues. The caller must CFRelease - the value returned. -*/ - -__nullable -CFDataRef SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyNormalizedSubjectContent is deprecated. Use SecCertificateCopyNormalizedSubjectSequence instead."); - - -#endif /* SEC_OS_OSX */ - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECCERTIFICATE_H_ */ diff --git a/trust/SecCertificatePriv.h b/trust/SecCertificatePriv.h deleted file mode 100644 index 3fa2fe4e..00000000 --- a/trust/SecCertificatePriv.h +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Copyright (c) 2002-2004,2006-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecCertificatePriv - The functions provided in SecCertificatePriv.h implement and manage a particular - type of keychain item that represents a certificate. You can store a - certificate in a keychain, but a certificate can also be a transient - object. - - You can use a certificate as a keychain item in most functions. - Certificates are able to compute their parent certificates, and much more. -*/ - -#ifndef _SECURITY_SECCERTIFICATEPRIV_H_ -#define _SECURITY_SECCERTIFICATEPRIV_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -__BEGIN_DECLS - -#if SEC_OS_IPHONE -typedef CF_OPTIONS(uint32_t, SecKeyUsage) { - kSecKeyUsageUnspecified = 0u, - kSecKeyUsageDigitalSignature = 1u << 0, - kSecKeyUsageNonRepudiation = 1u << 1, - kSecKeyUsageContentCommitment= 1u << 1, - kSecKeyUsageKeyEncipherment = 1u << 2, - kSecKeyUsageDataEncipherment = 1u << 3, - kSecKeyUsageKeyAgreement = 1u << 4, - kSecKeyUsageKeyCertSign = 1u << 5, - kSecKeyUsageCRLSign = 1u << 6, - kSecKeyUsageEncipherOnly = 1u << 7, - kSecKeyUsageDecipherOnly = 1u << 8, - kSecKeyUsageCritical = 1u << 31, - kSecKeyUsageAll = 0x7FFFFFFFu -}; -#endif /* SEC_OS_IPHONE */ - -typedef CF_ENUM(uint32_t, SecCertificateEscrowRootType) { - kSecCertificateBaselineEscrowRoot = 0, - kSecCertificateProductionEscrowRoot = 1, - kSecCertificateBaselinePCSEscrowRoot = 2, - kSecCertificateProductionPCSEscrowRoot = 3, - kSecCertificateBaselineEscrowBackupRoot = 4, // v100 and v101 - kSecCertificateProductionEscrowBackupRoot = 5, - kSecCertificateBaselineEscrowEnrollmentRoot = 6, // v101 only - kSecCertificateProductionEscrowEnrollmentRoot = 7, -}; - -/* The names of the files that contain the escrow certificates */ -extern const CFStringRef kSecCertificateProductionEscrowKey; -extern const CFStringRef kSecCertificateProductionPCSEscrowKey; -extern const CFStringRef kSecCertificateEscrowFileName; - -/* Return a certificate for the DER representation of this certificate. - Return NULL if the passed-in data is not a valid DER-encoded X.509 - certificate. */ -SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, - const UInt8 *bytes, CFIndex length) -__SEC_MAC_AND_IOS_UNKNOWN; -//__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_UNKNOWN); - -/* Returns a certificate from a pem blob. - Return NULL if the passed-in data is not a valid DER-encoded X.509 - certificate. */ -SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator, CFDataRef pem_certificate) -__SEC_MAC_AND_IOS_UNKNOWN; -//__OSX_AVAILABLE_STARTING(__MAC_10_12, __SEC_IPHONE_UNKNOWN); - -/* Return the length of the DER representation of this certificate. */ -CFIndex SecCertificateGetLength(SecCertificateRef certificate); - -/* Return the bytes of the DER representation of this certificate. */ -const UInt8 *SecCertificateGetBytePtr(SecCertificateRef certificate); - -/* Return the SHA-1 hash of this certificate. */ -CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the SHA-256 hash of this certificate. */ -CFDataRef SecCertificateCopySHA256Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the SHA-1 hash of the public key in this certificate. */ -CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the SHA-1 hash of the SubjectPublicKeyInfo sequence in this certificate. */ -CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the SHA-256 hash of the SubjectPublicKeyInfo sequence in this certificate. */ -CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return an array of CFStringRefs representing the dns addresses in the - certificate if any. */ -CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return an array of CFStringRefs representing the NTPrincipalNames in the - certificate if any. */ -CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Create a unified SecCertificateRef from a legacy keychain item and its data. */ -SecCertificateRef SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator, - CFDataRef der_certificate, CFTypeRef keychainItem) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Set a legacy item instance for a unified SecCertificateRef. */ -OSStatus SecCertificateSetKeychainItem(SecCertificateRef certificate, CFTypeRef keychain_item) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return a keychain item reference, given a unified SecCertificateRef. - Note: On OSX, for this function to succeed, the provided certificate must have been - created by SecCertificateCreateWithKeychainItem, otherwise NULL is returned. - */ -CFTypeRef SecCertificateCopyKeychainItem(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/*! - @function SecCertificateCopyIssuerSummary - @abstract Return a simple string which hopefully represents a human understandable issuer. - @param certificate SecCertificate object created with SecCertificateCreateWithData(). - @discussion All the data in this string comes from the certificate itself - and thus it's in whatever language the certificate itself is in. - @result A CFStringRef which the caller should CFRelease() once it's no longer needed. - */ -CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate); - -/* Return a string formatted according to RFC 2253 representing the complete - subject of certificate. */ -CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate); - -CFMutableArrayRef SecCertificateCopySummaryProperties( - SecCertificateRef certificate, CFAbsoluteTime verifyTime) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the content of a DER encoded X.501 name (without the tag and length - fields) for the receiving certificates issuer. */ -CFDataRef SecCertificateGetNormalizedIssuerContent(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the content of a DER encoded X.501 name (without the tag and length - fields) for the receiving certificates subject. */ -CFDataRef SecCertificateGetNormalizedSubjectContent(SecCertificateRef certificate) - __SEC_MAC_AND_IOS_UNKNOWN; - -/* Return the DER encoded issuer sequence for the certificate's issuer. */ -CFDataRef SecCertificateCopyIssuerSequence(SecCertificateRef certificate); - -/* Return the DER encoded subject sequence for the certificate's subject. */ -CFDataRef SecCertificateCopySubjectSequence(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the ip addresses in the - certificate if any. */ -CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the email addresses in the - certificate if any. */ -CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the common names in the - certificates subject if any. */ -CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the organization in the - certificate's subject if any. */ -CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the organizational unit in the - certificate's subject if any. */ -CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate); - -/* Return an array of CFStringRefs representing the country in the - certificate's subject if any. */ -CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate); - -/* Return a string with the company name of an ev leaf certificate. */ -CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate); - -/* X.509 Certificate Version: 1, 2 or 3. */ -CFIndex SecCertificateVersion(SecCertificateRef certificate); - -SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate); - -/* Returns an array of CFDataRefs for all extended key usage oids or NULL */ -CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate); - -/*! - @function SecCertificateIsValid - @abstract Check certificate validity on a given date. - @param certificate A certificate reference. - @result Returns true if the specified date falls within the certificate's validity period, false otherwise. - */ -bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); - -/*! - @function SecCertificateNotValidBefore - @abstract Obtain the starting date of the given certificate. - @param certificate A certificate reference. - @result Returns the absolute time at which the given certificate becomes valid, - or 0 if this value could not be obtained. - */ -CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); - -/*! - @function SecCertificateNotValidAfter - @abstract Obtain the expiration date of the given certificate. - @param certificate A certificate reference. - @result Returns the absolute time at which the given certificate expires, - or 0 if this value could not be obtained. - */ -CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); - -/*! - @function SecCertificateIsSelfSigned - @abstract Determine if the given certificate is self-signed. - @param certRef A certificate reference. - @param isSelfSigned Will be set to true on return if the certificate is self-signed, false otherwise. - @result A result code. Returns errSecSuccess if the certificate's status can be determined. - */ -OSStatus SecCertificateIsSelfSigned(SecCertificateRef certRef, Boolean *isSelfSigned) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_9_0); - -/*! - @function SecCertificateIsSelfSignedCA - @abstract Determine if the given certificate is self-signed and has a basic - constraints extension indicating it is a certificate authority. - @param certificate A certificate reference. - @result Returns true if the certificate is self-signed and has a basic - constraints extension indicating it is a certificate authority, otherwise false. - */ -bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); - -/*! - @function SecCertificateIsCA - @abstract Determine if the given certificate has a basic - constraints extension indicating it is a certificate authority. - @param certificate A certificate reference. - @result Returns true if the certificate has a basic constraints - extension indicating it is a certificate authority, otherwise false. - */ -bool SecCertificateIsCA(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); - - -/* Append certificate to xpc_certificates. */ -bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error); - -/* Decode certificate from xpc_certificates[index] as encoded by SecCertificateAppendToXPCArray(). */ -SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error); - -/* Return an xpc_array of data from an array of SecCertificateRefs. */ -xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error); - -/* Return an array of SecCertificateRefs from a xpc_object array of datas. */ -CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error); - -/*! - @function SecCertificateCopyEscrowRoots - @abstract Retrieve the array of valid escrow certificates for a given root type. - @param escrowRootType An enumerated type indicating which root type to return. - @result An array of zero or more escrow certificates matching the provided type. - */ -CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/* Return an attribute dictionary used to store this item in a keychain. */ -CFDictionaryRef SecCertificateCopyAttributeDictionary(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/* - * Enumerated constants for signature hash algorithms. - */ -typedef CF_ENUM(uint32_t, SecSignatureHashAlgorithm){ - kSecSignatureHashAlgorithmUnknown = 0, - kSecSignatureHashAlgorithmMD2 = 1, - kSecSignatureHashAlgorithmMD4 = 2, - kSecSignatureHashAlgorithmMD5 = 3, - kSecSignatureHashAlgorithmSHA1 = 4, - kSecSignatureHashAlgorithmSHA224 = 5, - kSecSignatureHashAlgorithmSHA256 = 6, - kSecSignatureHashAlgorithmSHA384 = 7, - kSecSignatureHashAlgorithmSHA512 = 8 -}; - -/*! - @function SecCertificateGetSignatureHashAlgorithm - @abstract Determine the hash algorithm used in a certificate's signature. - @param certificate A certificate reference. - @result Returns an enumerated value indicating the signature hash algorithm - used in a certificate. If the hash algorithm is unsupported or cannot be - obtained (e.g. because the supplied certificate reference is invalid), a - value of 0 (kSecSignatureHashAlgorithmUnknown) is returned. - */ -SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @function SecCertificateCopyProperties - @abstract Return a property array for this trust certificate. - @param certificate A reference to the certificate to evaluate. - @result A property array. It is the caller's responsability to CFRelease - the returned array when it is no longer needed. - See SecTrustCopySummaryPropertiesAtIndex on how to intepret this array. - Unlike that function call this function returns a detailed description - of the certificate in question. - */ -CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate); - -/* Returns an array of CFDataRefs for all embedded SCTs */ -CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); - -/* Return the precert TBSCertificate DER data - used for Certificate Transparency */ -CFDataRef SecCertificateCopyPrecertTBS(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); - -/* Returns a dictionary of dictionaries for system-trusted CT logs, indexed by the LogID */ -CFDictionaryRef SecCertificateCopyTrustedCTLogs(void) - __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_13_0); - -/* Returns a dictionary for the CT log matching the provided - * key ID, or NULL if no matching log is found. - * And by keyID we mean LogID as specified in RFC 6962. - */ -CFDictionaryRef SecCertificateCopyCTLogForKeyID(CFDataRef keyID) - __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_13_0); - -/* Return the auth capabilities bitmask from the iAP marker extension */ -CF_RETURNS_RETAINED CFDataRef SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -typedef CF_ENUM(uint32_t, SeciAuthVersion) { - kSeciAuthInvalid = 0, - kSeciAuthVersion1 = 1, /* unused */ - kSeciAuthVersion2 = 2, - kSeciAuthVersion3 = 3, - kSeciAuthVersionSW = 4, -} __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/* Return the iAuth version indicated by the certificate. This function does - * not guarantee that the certificate is valid, so the caller must still call - * SecTrustEvaluate to guarantee that the certificate was properly issued */ -SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/* Return the normalized name or NULL if it fails to parse */ -CFDataRef SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name) - __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); - -/* Returns the Subject Key ID extension from the certificate or NULL if none */ -CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); - -/* Returns an array of SecCertificateRefs containing the iPhone Device CA and - * its parent certificates. This interface is meant as a workaround and should - * not be used without consulting the Security team. */ -CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) - __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); - -typedef CF_ENUM(uint32_t, SeciAPSWAuthCapabilitiesType) { - kSeciAPSWAuthGeneralCapabilities = 0, - kSeciAPSWAuthAirPlayCapabilities = 1, - kSeciAPSWAuthHomeKitCapabilities = 2, -} __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); - -/* Return the iAP SW Auth capabilities bitmask from the specificed - * SeciAPSWAuthCapabilitiesType type marker extensions. */ -CF_RETURNS_RETAINED -CFDataRef SecCertificateCopyiAPSWAuthCapabilities(SecCertificateRef certificate, - SeciAPSWAuthCapabilitiesType type) - __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); - -/*! - @function SecCertificateCopyExtensionValue - @abstract Return the value in an extension of a certificate. - @param certificate A reference to the certificate containing the desired extension - @param extensionOID A CFData containing the binary value of ObjectIdentifier of the - desired extension or a CFString containing the decimal value of the ObjectIdentifier. - @param isCritical On return, a boolean value representing whether the extension was critical. - @result If an extension exists in the certificate with the extensionOID, the returned CFData - is the (unparsed) Value of the extension. - @discussion If the certificate has multiple extensions with the same extension OID, the first - extension with the input OID is returned. - */ -CF_RETURNS_RETAINED -CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, - CFTypeRef extensionOID, bool *isCritical) - __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); - -/* Return an array of CFURLRefs each of which is an ocspResponder for this - certificate. */ -CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - - -/* Return the component type string in a component certificate. */ -CF_RETURNS_RETAINED -CFStringRef SecCertificateCopyComponentType(SecCertificateRef certificate) - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate, CFAbsoluteTime *time, CFErrorRef * CF_RETURNS_RETAINED error); - -/* - * Legacy functions (OS X only) - */ -#if SEC_OS_OSX -#include -#include - -/* Given a unified SecCertificateRef, return a copy with a legacy - C++ ItemImpl-based Certificate instance. Only for internal use; - legacy references cannot be used by SecCertificate API functions. */ -SecCertificateRef SecCertificateCreateItemImplInstance(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); - -/* Inverse of above; convert legacy Certificate instance to new ref. */ -SecCertificateRef SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); - - -/* Convenience function to determine type of certificate instance. */ -Boolean SecCertificateIsItemImplInstance(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); - -/* Given a legacy C++ ItemImpl-based Certificate instance obtained with - SecCertificateCreateItemImplInstance, return its clHandle pointer. - Only for internal use. */ -OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); - -/* Deprecated; use SecCertificateCopyCommonName() instead. */ -OSStatus SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_5, __IPHONE_NA, __IPHONE_NA, "SecCertificateGetCommonName is deprecated. Use SecCertificateCopyCommonName instead."); - -/* Deprecated; use SecCertificateCopyEmailAddresses() instead. */ -/* This should have been Copy instead of Get since the returned address is not autoreleased. */ -OSStatus SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_5, __IPHONE_NA, __IPHONE_NA, "SecCertificateGetEmailAddress is deprecated. Use SecCertificateCopyEmailAddresses instead."); - -/* - * Private API to infer a display name for a SecCertificateRef which - * may or may not be in a keychain. - */ -OSStatus SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label); - -/* - * Subset of the above, useful for both certs and CRLs. - * Infer printable label for a given an CSSM_X509_NAME. Returns NULL - * if no appropriate printable name found. - */ -const CSSM_DATA *SecInferLabelFromX509Name( - const CSSM_X509_NAME *x509Name) - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/* Accessors for fields in the cached certificate */ - -/*! - @function SecCertificateCopyFieldValues - @abstract Retrieves the values for a particular field in a given certificate. - @param certificate A valid SecCertificateRef to the certificate. - @param field Pointer to the OID whose values should be returned. - @param fieldValues On return, a zero terminated list of CSSM_DATA_PTR's. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Return a zero terminated list of CSSM_DATA_PTR's with the - values of the field specified by field. Caller must call - SecCertificateReleaseFieldValues to free the storage allocated by this call. -*/ -OSStatus SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyFieldValues is deprecated. Use SecCertificateCopyValues instead."); - -/*! - @function SecCertificateReleaseFieldValues - @abstract Release the storage associated with the values returned by SecCertificateCopyFieldValues. - @param certificate A valid SecCertificateRef to the certificate. - @param field Pointer to the OID whose values were returned by SecCertificateCopyFieldValues. - @param fieldValues Pointer to a zero terminated list of CSSM_DATA_PTR's. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Release the storage associated with the values returned by SecCertificateCopyFieldValues. -*/ -OSStatus SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateReleaseFieldValues is deprecated. Use SecCertificateCopyValues instead."); - -/*! - @function SecCertificateCopyFirstFieldValue - @abstract Return a CSSM_DATA_PTR with the value of the first field specified by field. - @param certificate A valid SecCertificateRef to the certificate. - @param field Pointer to the OID whose value should be returned. - @param fieldValue On return, a CSSM_DATA_PTR to the field data. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Return a CSSM_DATA_PTR with the value of the first field specified by field. Caller must call - SecCertificateReleaseFieldValue to free the storage allocated by this call. -*/ -OSStatus SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyFirstFieldValue is deprecated. Use SecCertificateCopyValues instead."); - -/*! - @function SecCertificateReleaseFirstFieldValue - @abstract Release the storage associated with the values returned by SecCertificateCopyFirstFieldValue. - @param certificate A valid SecCertificateRef to the certificate. - @param field Pointer to the OID whose values were returned by SecCertificateCopyFieldValue. - @param fieldValue The field data to release. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Release the storage associated with the values returned by SecCertificateCopyFieldValue. -*/ -OSStatus SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateReleaseFirstFieldValue is deprecated. Use SecCertificateCopyValues instead."); - -/*! - @function SecCertificateCopySubjectComponent - @abstract Retrieves a component of the subject distinguished name of a given certificate. - @param certificate A reference to the certificate from which to retrieve the common name. - @param component A component oid naming the component desired. See . - @param result On return, a reference to the string form of the component, if present in the subject. - Your code must release this reference by calling the CFRelease function. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, - CFStringRef *result) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopySubjectComponent is deprecated. Use SecCertificateCopyCommonNames,SecCertificateCopyOrganization,SecCertificateCopyOrganizationalUnit, etc. instead."); - -/* Convenience functions for searching. - */ -OSStatus SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, - const CSSM_DATA *serialNumber, SecCertificateRef *certificate) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindByIssuerAndSN is deprecated. Use SecItemCopyMatching instead."); - -OSStatus SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, - SecCertificateRef *certificate) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindBySubjectKeyID is deprecated. Use SecItemCopyMatching instead."); - -OSStatus SecCertificateFindByEmail(CFTypeRef keychainOrArray, const char *emailAddress, - SecCertificateRef *certificate) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindByEmail is deprecated. Use SecItemCopyMatching instead."); - -/* These should go to SecKeychainSearchPriv.h. */ -OSStatus SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, - const CSSM_DATA *serialNumber, SecKeychainSearchRef *searchRef) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByIssuerAndSN is deprecated. Use SecItemCopyMatching instead."); - -OSStatus SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray, CFDataRef issuer, - CFDataRef serialNumber, SecKeychainSearchRef *searchRef) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByIssuerAndSN_CF is deprecated. Use SecItemCopyMatching instead."); - -OSStatus SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, - SecKeychainSearchRef *searchRef) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateBySubjectKeyID is deprecated. Use SecItemCopyMatching instead."); - -OSStatus SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray, const char *emailAddress, - SecKeychainSearchRef *searchRef) - __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByEmail is deprecated. Use SecItemCopyMatching instead."); - -/* Convenience function for generating digests; should be moved elsewhere. */ -CSSM_RETURN SecDigestGetData(CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA); - -/* Return true iff certificate is valid as of verifyTime. */ -/* DEPRECATED: Use SecCertificateIsValid instead. */ -bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecCertificateCopyPublicKeySHA1DigestFromCertificateData - @abstract Returns the SHA1 hash of the public key of a certificate or NULL - @param allocator CFAllocator to allocate the certificate with. - @param der_certificate DER encoded X.509 certificate. - @result SHA1 hash of the public key of a certificate or NULL -*/ -CFDataRef SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator, - CFDataRef der_certificate) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_13_2, __IPHONE_NA, __IPHONE_NA); // Likely incorrect. - -#endif /* SEC_OS_OSX */ - -__END_DECLS - -#endif /* !_SECURITY_SECCERTIFICATEPRIV_H_ */ diff --git a/trust/SecCertificateRequest.h b/trust/SecCertificateRequest.h deleted file mode 100644 index ba33965e..00000000 --- a/trust/SecCertificateRequest.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecCertificateRequest - SecCertificateRequest implements a way to issue a certificate request to a - certificate authority. -*/ - -#ifndef _SECURITY_SECCERTIFICATEREQUEST_H_ -#define _SECURITY_SECCERTIFICATEREQUEST_H_ - -#include -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN - -extern const CFStringRef kSecOidCommonName; -extern const CFStringRef kSecOidCountryName; -extern const CFStringRef kSecOidStateProvinceName; -extern const CFStringRef kSecOidLocalityName; -extern const CFStringRef kSecOidOrganization; -extern const CFStringRef kSecOidOrganizationalUnit; - -extern const unsigned char SecASN1PrintableString; -extern const unsigned char SecASN1UTF8String; - -/* - Parameter keys for certificate request generation: - @param kSecCSRChallengePassword CFStringRef - conversion to PrintableString or UTF8String needs to be possible. - @param kSecCertificateKeyUsage CFNumberRef - with key usage mask using kSecKeyUsage constants. - @param kSecSubjectAltName CFDictionaryRef - with keys defined below. - @param kSecCSRBasicContraintsPathLen CFNumberRef - if set will include basic constraints and mark it as - a CA cert. If 0 <= number < 256, specifies path length, otherwise - path length will be omitted. Basic contraints will always be - marked critical. - @param kSecCertificateExtensions CFDictionaryRef - if set all keys (strings with oids in dotted notation) will be added - as extensions with accompanying value in binary (CFDataRef) or - appropriate string (CFStringRef) type (based on used character set). - @param kSecCertificateExtensionsEncoded CFDictionaryRef - if set all keys (strings with oids in dotted notation) will be added - as extensions with accompanying value. It is assumed that the value - is a CFDataRef and is already properly encoded. This value will be - placed straight into the extension value OCTET STRING. - @param kSecCMSSignHashAlgorithm CFStringRef - (Declared in SecCMS.h) - if set, determines the hash algorithm used to create the signing - request or certificate. If this parameter is omitted, the default - hash algorithm will be used (SHA1 for RSA and SHA256 for ECDSA). - Supported digest algorithm strings are defined in - SecCMS.h, e.g. kSecCMSHashingAlgorithmSHA256;. -*/ -extern const CFStringRef kSecCSRChallengePassword; -extern const CFStringRef kSecSubjectAltName; -extern const CFStringRef kSecCertificateKeyUsage; -extern const CFStringRef kSecCSRBasicContraintsPathLen; -extern const CFStringRef kSecCertificateExtensions; -extern const CFStringRef kSecCertificateExtensionsEncoded; - -/* - Keys for kSecSubjectAltName dictionaries: - @param kSecSubjectAltNameDNSName CFArrayRef or CFStringRef - The value for this key is either a CFStringRef containing a single DNS name, - or a CFArrayRef of CFStringRefs, each containing a single DNS Name. - @param kkSecSubjectAltNameEmailAddress CFArrayRef or CFStringRef - The value for this key is either a CFStringRef containing a single email - address (RFC 822 Name), or a CFArrayRef of CFStringRefs, each containing a - single email address. - @param kSecSubjectAltNameURI CFArrayRef or CFStringRef - The value for this key is either a CFStringRef containing a single URI, - or a CFArrayRef of CFStringRefs, each containing a single URI. - @param kSecSubjectAltNameNTPrincipalName CFStringRef - The value for this key is a CFStringRef containing the NTPrincipalName. -*/ -extern const CFStringRef kSecSubjectAltNameDNSName; -extern const CFStringRef kSecSubjectAltNameEmailAddress; -extern const CFStringRef kSecSubjectAltNameURI; -extern const CFStringRef kSecSubjectAltNameNTPrincipalName; - -typedef struct { - CFTypeRef oid; /* kSecOid constant or CFDataRef with oid */ - unsigned char type; /* currently only SecASN1PrintableString or SecASN1UTF8String */ - CFTypeRef value; /* CFStringRef -> ASCII, UTF8, CFDataRef -> binary */ -} SecATV; - -typedef SecATV *SecRDN; - -/* - @function SecGenerateCertificateRequestWithParameters - @abstract Return a newly generated CSR for subject and keypair. - @param subject RDNs in the subject - @param paramters Parameters for the CSR generation. See above. - @param publicKey Public key - @param privateKey Private key - @result On success, a newly allocated CSR, otherwise NULL - -Example for subject: - SecATV cn[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("test") }, {} }; - SecATV c[] = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} }; - SecATV o[] = { { kSecOidOrganization, SecASN1PrintableString, CFSTR("Apple Inc.") }, {} }; - SecRDN atvs[] = { cn, c, o, NULL }; -*/ -CF_RETURNS_RETAINED _Nullable -CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN _Nonnull * _Nonnull subject, - CFDictionaryRef _Nullable parameters, SecKeyRef _Nullable publicKey, SecKeyRef privateKey) CF_RETURNS_RETAINED; - -/* - @function SecGenerateCertificateRequest - @abstract Return a newly generated CSR for subject and keypair. - @param subject RDNs in the subject in array format - @param paramters Parameters for the CSR generation. See above. - @param publicKey Public key - @param privateKey Private key - @result On success, a newly allocated CSR, otherwise NULL - @discussion The subject array contains an array of the RDNS. Each RDN is - itself an array of ATVs. Each ATV is an array of length two containing - first the OID and then the value. - -Example for subject (in Objective-C for ease of reading): - NSArray *subject = @[ - @[@[(__bridge NSString*)kSecOidCommonName, @"test"]] - @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], - @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc"]], - ]; - */ -CF_RETURNS_RETAINED _Nullable -CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, - CFDictionaryRef _Nullable parameters, SecKeyRef _Nullable publicKey, SecKeyRef privateKey) CF_RETURNS_RETAINED; - -/* - @function SecVerifyCertificateRequest - @abstract validate a CSR and return contained information to certify - @param publicKey (optional/out) SecKeyRef public key to certify - @param challenge (optional/out) CFStringRef enclosed challenge - @param subject (optional/out) encoded subject RDNs - @param extensions (optional/out) encoded extensions -*/ -bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef CF_RETURNS_RETAINED * _Nullable publicKey, - CFStringRef CF_RETURNS_RETAINED _Nullable * _Nullable challenge, - CFDataRef CF_RETURNS_RETAINED _Nullable * _Nullable subject, - CFDataRef CF_RETURNS_RETAINED _Nullable * _Nullable extensions); - - -/* - @function SecGenerateSelfSignedCertificate - @abstract Return a newly generated certificate for subject and keypair. - @param subject RDNs in the subject in array format - @param paramters Parameters for the CSR generation. See above. - @param publicKey Public key (NOTE: This is unused) - @param privateKey Private key - @result On success, a newly allocated certificate, otherwise NULL - @discussion The subject array contains an array of the RDNS. Each RDN is - itself an array of ATVs. Each ATV is an array of length two containing - first the OID and then the value. - - Example for subject (in Objective-C for ease of reading): - NSArray *subject = @[ - @[@[(__bridge NSString*)kSecOidCommonName, @"test"]] - @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], - @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc"]], - ]; - */ -CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, - SecKeyRef _Nullable publicKey, SecKeyRef privateKey); - -/* - @function SecIdentitySignCertificate - @param issuer issuer's identity (certificate/private key pair) - @param serialno serial number for the issued certificate - @param publicKey public key for the issued certificate - @param subject subject name for the issued certificate - @param extensions extensions for the issued certificate - @param hashingAlgorithm hash algorithm to use for signature - @result On success, a newly allocated certificate, otherwise NULL - @discussion This call can be used in combination with SecVerifyCertificateRequest - to generate a signed certifcate from a CSR after verifying it. The outputs - of SecVerifyCertificateRequest may be passed as inputs to this function. - - The subject may be an array, as specified in SecCertificateGenerateRequest, - or a data containing an encoded subject sequence, as specified by RFC 5280. - - Supported digest algorithm strings are defined in SecCMS.h, e.g. - kSecCMSHashingAlgorithmSHA256. - */ -CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno, - SecKeyRef publicKey, CFTypeRef subject, CFTypeRef _Nullable extensions); - -CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecIdentitySignCertificateWithAlgorithm(SecIdentityRef issuer, CFDataRef serialno, - SecKeyRef publicKey, CFTypeRef subject, CFTypeRef _Nullable extensions, CFStringRef _Nullable hashingAlgorithm); - -/* PRIVATE */ - -CF_RETURNS_RETAINED _Nullable -CFDataRef SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate, CFArrayRef subject); - -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* _SECURITY_SECCERTIFICATEREQUEST_H_ */ diff --git a/trust/SecPolicy.h b/trust/SecPolicy.h deleted file mode 100644 index 59e95b54..00000000 --- a/trust/SecPolicy.h +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecPolicy - The functions provided in SecPolicy.h provide an interface to various - X.509 certificate trust policies. - */ - -#ifndef _SECURITY_SECPOLICY_H_ -#define _SECURITY_SECPOLICY_H_ - -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @enum Policy Constants - @discussion Predefined constants used to specify a policy. - @constant kSecPolicyAppleX509Basic - @constant kSecPolicyAppleSSL - @constant kSecPolicyAppleSMIME - @constant kSecPolicyAppleEAP - @constant kSecPolicyAppleiChat - @constant kSecPolicyAppleIPsec - @constant kSecPolicyApplePKINITClient - @constant kSecPolicyApplePKINITServer - @constant kSecPolicyAppleCodeSigning - @constant kSecPolicyMacAppStoreReceipt - @constant kSecPolicyAppleIDValidation - @constant kSecPolicyAppleTimeStamping - @constant kSecPolicyAppleRevocation - @constant kSecPolicyApplePassbookSigning - @constant kSecPolicyApplePayIssuerEncryption - */ -extern const CFStringRef kSecPolicyAppleX509Basic - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleSSL - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleSMIME - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleEAP - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleIPsec - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -#if TARGET_OS_OSX -extern const CFStringRef kSecPolicyAppleiChat - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); -#endif -extern const CFStringRef kSecPolicyApplePKINITClient - API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); -extern const CFStringRef kSecPolicyApplePKINITServer - API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); -extern const CFStringRef kSecPolicyAppleCodeSigning - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyMacAppStoreReceipt - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleIDValidation - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleTimeStamping - __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleRevocation - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyApplePassbookSigning - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyApplePayIssuerEncryption - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @enum Policy Value Constants - @abstract Predefined property key constants used to get or set values in - a dictionary for a policy instance. - @discussion - All policies will have the following read-only value: - kSecPolicyOid (the policy object identifier) - - Additional policy values which your code can optionally set: - kSecPolicyName (name which must be matched) - kSecPolicyClient (evaluate for client, rather than server) - kSecPolicyRevocationFlags (only valid for a revocation policy) - kSecPolicyTeamIdentifier (only valid for a Passbook signing policy) - - @constant kSecPolicyOid Specifies the policy OID (value is a CFStringRef) - @constant kSecPolicyName Specifies a CFStringRef (or CFArrayRef of same) - containing a name which must be matched in the certificate to satisfy - this policy. For SSL/TLS, EAP, and IPSec policies, this specifies the - server name which must match the common name of the certificate. - For S/MIME, this specifies the RFC822 email address. For Passbook - signing, this specifies the pass signer. - @constant kSecPolicyClient Specifies a CFBooleanRef value that indicates - this evaluation should be for a client certificate. If not set (or - false), the policy evaluates the certificate as a server certificate. - @constant kSecPolicyRevocationFlags Specifies a CFNumberRef that holds a - kCFNumberCFIndexType bitmask value. See "Revocation Policy Constants" - for a description of individual bits in this value. - @constant kSecPolicyTeamIdentifier Specifies a CFStringRef containing a - team identifier which must be matched in the certificate to satisfy - this policy. For the Passbook signing policy, this string must match - the Organizational Unit field of the certificate subject. - */ -extern const CFStringRef kSecPolicyOid - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyName - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyClient - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPolicyRevocationFlags - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyTeamIdentifier - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - - -/*! - @function SecPolicyGetTypeID - @abstract Returns the type identifier of SecPolicy instances. - @result The CFTypeID of SecPolicy instances. - */ -CFTypeID SecPolicyGetTypeID(void) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecPolicyCopyProperties - @abstract Returns a dictionary of this policy's properties. - @param policyRef A policy reference. - @result A properties dictionary. See "Policy Value Constants" for a list - of currently defined property keys. It is the caller's responsibility to - CFRelease this reference when it is no longer needed. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function returns the properties for a policy, as set by the - policy's construction function or by a prior call to SecPolicySetProperties. - */ -__nullable -CFDictionaryRef SecPolicyCopyProperties(SecPolicyRef policyRef) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); - -/*! - @function SecPolicyCreateBasicX509 - @abstract Returns a policy object for the default X.509 policy. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -SecPolicyRef SecPolicyCreateBasicX509(void) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecPolicyCreateSSL - @abstract Returns a policy object for evaluating SSL certificate chains. - @param server Passing true for this parameter creates a policy for SSL - server certificates. - @param hostname (Optional) If present, the policy will require the specified - hostname to match the hostname in the leaf certificate. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef __nullable hostname) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @enum Revocation Policy Constants - @abstract Predefined constants which allow you to specify how revocation - checking will be performed for a trust evaluation. - @constant kSecRevocationOCSPMethod If this flag is set, perform revocation - checking using OCSP (Online Certificate Status Protocol). - @constant kSecRevocationCRLMethod If this flag is set, perform revocation - checking using the CRL (Certificate Revocation List) method. - @constant kSecRevocationPreferCRL If this flag is set, then CRL revocation - checking will be preferred over OCSP (by default, OCSP is preferred.) - Note that this flag only matters if both revocation methods are specified. - @constant kSecRevocationRequirePositiveResponse If this flag is set, then - the policy will fail unless a verified positive response is obtained. If - the flag is not set, revocation checking is done on a "best attempt" basis, - where failure to reach the server is not considered fatal. - @constant kSecRevocationNetworkAccessDisabled If this flag is set, then - no network access is performed; only locally cached replies are consulted. - This constant disallows network access for both revocation checks and - intermediate CA issuer fetching. - @constant kSecRevocationUseAnyAvailableMethod Specifies that either - OCSP or CRL may be used, depending on the method(s) specified in the - certificate and the value of kSecRevocationPreferCRL. - */ -CF_ENUM(CFOptionFlags) { - kSecRevocationOCSPMethod = (1 << 0), - kSecRevocationCRLMethod = (1 << 1), - kSecRevocationPreferCRL = (1 << 2), - kSecRevocationRequirePositiveResponse = (1 << 3), - kSecRevocationNetworkAccessDisabled = (1 << 4), - kSecRevocationUseAnyAvailableMethod = (kSecRevocationOCSPMethod | - kSecRevocationCRLMethod) -}; - -/*! - @function SecPolicyCreateRevocation - @abstract Returns a policy object for checking revocation of certificates. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - @param revocationFlags Flags to specify revocation checking options. - @discussion Use this function to create a revocation policy with behavior - specified by revocationFlags. See the "Revocation Policy Constants" section - for a description of these flags. Note: it is usually not necessary to - create a revocation policy yourself unless you wish to override default - system behavior (e.g. to force a particular method, or to disable - revocation checking entirely.) - */ -__nullable -SecPolicyRef SecPolicyCreateRevocation(CFOptionFlags revocationFlags) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecPolicyCreateWithProperties - @abstract Returns a policy object based on an object identifier for the - policy type. See the "Policy Constants" section for a list of defined - policy object identifiers. - @param policyIdentifier The identifier for the desired policy type. - @param properties (Optional) A properties dictionary. See "Policy Value - Constants" for a list of currently defined property keys. - @result The returned policy reference, or NULL if the policy could not be - created. - */ -__nullable -SecPolicyRef SecPolicyCreateWithProperties(CFTypeRef policyIdentifier, - CFDictionaryRef __nullable properties) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -/* - * Legacy functions (OS X only) - */ -#if TARGET_OS_OSX -#include - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @enum Policy Value Constants (OS X) - @discussion Predefined property key constants used to get or set values in - a dictionary for a policy instance. - - Some policy values may specify CFBooleanRef key usage constraints: - kSecPolicyKU_DigitalSignature - kSecPolicyKU_NonRepudiation - kSecPolicyKU_KeyEncipherment - kSecPolicyKU_DataEncipherment - kSecPolicyKU_KeyAgreement - kSecPolicyKU_KeyCertSign - kSecPolicyKU_CRLSign - kSecPolicyKU_EncipherOnly - kSecPolicyKU_DecipherOnly - - kSecPolicyKU policy values define certificate-level key purposes, - in contrast to the key-level definitions in SecItem.h - - For example, a key in a certificate might be acceptable to use for - signing a CRL, but not for signing another certificate. In either - case, this key would have the ability to sign (i.e. kSecAttrCanSign - is true), but may only sign for specific purposes allowed by these - policy constants. Similarly, a public key might have the capability - to perform encryption or decryption, but the certificate in which it - resides might have a decipher-only certificate policy. - - These constants correspond to values defined in RFC 5280, section - 4.2.1.3 (Key Usage) which define the purpose of a key contained in a - certificate, in contrast to section 4.1.2.7 which define the uses that - a key is capable of. - - Note: these constants are not available on iOS. Your code should - avoid direct reliance on these values for making policy decisions - and use higher level policies where possible. - - @constant kSecPolicyKU_DigitalSignature Specifies that the certificate must - have a key usage that allows it to be used for signing. - @constant kSecPolicyKU_NonRepudiation Specifies that the certificate must - have a key usage that allows it to be used for non-repudiation. - @constant kSecPolicyKU_KeyEncipherment Specifies that the certificate must - have a key usage that allows it to be used for key encipherment. - @constant kSecPolicyKU_DataEncipherment Specifies that the certificate must - have a key usage that allows it to be used for data encipherment. - @constant kSecPolicyKU_KeyAgreement Specifies that the certificate must - have a key usage that allows it to be used for key agreement. - @constant kSecPolicyKU_KeyCertSign Specifies that the certificate must - have a key usage that allows it to be used for signing certificates. - @constant kSecPolicyKU_CRLSign Specifies that the certificate must - have a key usage that allows it to be used for signing CRLs. - @constant kSecPolicyKU_EncipherOnly Specifies that the certificate must - have a key usage that permits it to be used for encryption only. - @constant kSecPolicyKU_DecipherOnly Specifies that the certificate must - have a key usage that permits it to be used for decryption only. - */ -extern const CFStringRef kSecPolicyKU_DigitalSignature - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_NonRepudiation - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_KeyEncipherment - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_DataEncipherment - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_KeyAgreement - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_KeyCertSign - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_CRLSign - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_EncipherOnly - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); -extern const CFStringRef kSecPolicyKU_DecipherOnly - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecPolicyCreateWithOID - @abstract Returns a policy object based on an object identifier for the - policy type. See the "Policy Constants" section for a list of defined - policy object identifiers. - @param policyOID The OID of the desired policy. - @result The returned policy reference, or NULL if the policy could not be - created. - @discussion This function is deprecated in Mac OS X 10.9 and later; - use SecPolicyCreateWithProperties (or a more specific policy creation - function) instead. - */ -__nullable -SecPolicyRef SecPolicyCreateWithOID(CFTypeRef policyOID) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicyGetOID - @abstract Returns a policy's object identifier. - @param policyRef A policy reference. - @param oid On return, a pointer to the policy's object identifier. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later; - use SecPolicyCopyProperties instead. - */ -OSStatus SecPolicyGetOID(SecPolicyRef policyRef, CSSM_OID *oid) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicyGetValue - @abstract Returns a policy's value. - @param policyRef A policy reference. - @param value On return, a pointer to the policy's value. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later; - use SecPolicyCopyProperties instead. - */ -OSStatus SecPolicyGetValue(SecPolicyRef policyRef, CSSM_DATA *value) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicySetValue - @abstract Sets a policy's value. - @param policyRef A policy reference. - @param value The value to be set into the policy object, replacing any - previous value. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later. Policy - instances should be considered read-only; in cases where your code would - consider changing properties of a policy, it should instead create a new - policy instance with the desired properties. - */ -OSStatus SecPolicySetValue(SecPolicyRef policyRef, const CSSM_DATA *value) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicySetProperties - @abstract Sets a policy's properties. - @param policyRef A policy reference. - @param properties A properties dictionary. See "Policy Value Constants" - for a list of currently defined property keys. This dictionary replaces the - policy's existing properties, if any. Note that the policy OID (specified - by kSecPolicyOid) is a read-only property of the policy and cannot be set. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.9 and later. Policy - instances should be considered read-only; in cases where your code would - consider changing properties of a policy, it should instead create a new - policy instance with the desired properties. - */ -OSStatus SecPolicySetProperties(SecPolicyRef policyRef, - CFDictionaryRef properties) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicyGetTPHandle - @abstract Returns the CSSM trust policy handle for the given policy. - @param policyRef A policy reference. - @param tpHandle On return, a pointer to a value of type CSSM_TP_HANDLE. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later. - */ -OSStatus SecPolicyGetTPHandle(SecPolicyRef policyRef, CSSM_TP_HANDLE *tpHandle) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ - -__END_DECLS - -#endif /* !_SECURITY_SECPOLICY_H_ */ diff --git a/trust/SecPolicyPriv.h b/trust/SecPolicyPriv.h deleted file mode 100644 index 360e7faa..00000000 --- a/trust/SecPolicyPriv.h +++ /dev/null @@ -1,2018 +0,0 @@ -/* - * Copyright (c) 2003-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecPolicyPriv - The functions provided in SecPolicyPriv provide an interface to various - X.509 certificate trust policies. -*/ - -#ifndef _SECURITY_SECPOLICYPRIV_H_ -#define _SECURITY_SECPOLICYPRIV_H_ - -#include -#include -#include -#include -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @enum Policy Constants (Private) - @discussion Predefined constants used to specify a policy. - */ -extern const CFStringRef kSecPolicyAppleMobileStore - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleTestMobileStore - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleEscrowService - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleProfileSigner - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleQAProfileSigner - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecPolicyAppleServerAuthentication - __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); -extern const CFStringRef kSecPolicyAppleOTAPKISigner - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); -extern const CFStringRef kSecPolicyAppleTestOTAPKISigner - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); -extern const CFStringRef kSecPolicyAppleIDValidationRecordSigningPolicy - API_DEPRECATED_WITH_REPLACEMENT("kSecPolicyAppleIDValidationRecordSigning", ios(7.0,10.0), macos(10.9,10.12)); -extern const CFStringRef kSecPolicyAppleIDValidationRecordSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleSMPEncryption - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); -extern const CFStringRef kSecPolicyAppleTestSMPEncryption - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); -extern const CFStringRef kSecPolicyApplePCSEscrowService - __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); -extern const CFStringRef kSecPolicyApplePPQSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleTestPPQSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleSWUpdateSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyApplePackageSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleOSXProvisioningProfileSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleATVVPNProfileSigning - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecPolicyAppleAST2DiagnosticsServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); -extern const CFStringRef kSecPolicyAppleEscrowProxyServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleFMiPServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleMMCService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleGSService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyApplePPQService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleHomeKitServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiPhoneActivation - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiPhoneDeviceCertificate - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleFactoryDeviceCertificate - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiAP - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiTunesStoreURLBag - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiPhoneApplicationSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiPhoneProfileApplicationSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleiPhoneProvisioningProfileSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleLockdownPairing - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleURLBag - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleOTATasking - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleMobileAsset - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleIDAuthority - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleGenericApplePinned - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleGenericAppleSSLPinned - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleSoftwareSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleExternalDeveloper - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleOCSPSigner - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleIDSService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleIDSServiceContext - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyApplePushService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleLegacyPushService - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleTVOSApplicationSigning - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleUniqueDeviceIdentifierCertificate - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleEscrowProxyCompatibilityServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleMMCSCompatibilityServerAuth - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyAppleSecureIOStaticAsset - __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); -extern const CFStringRef kSecPolicyAppleWarsaw - __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); -extern const CFStringRef kSecPolicyAppleiCloudSetupServerAuth - __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); -extern const CFStringRef kSecPolicyAppleiCloudSetupCompatibilityServerAuth - __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); -extern const CFStringRef kSecPolicyAppleAppTransportSecurity - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleMobileSoftwareUpdate - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleMobileAssetDevelopment - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleMacOSProfileApplicationSigning - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleBasicAttestationSystem - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleBasicAttestationUser - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleiPhoneVPNApplicationSigning - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyAppleiAPSWAuth - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); -extern const CFStringRef kSecPolicyAppleDemoDigitalCatalog - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); -extern const CFStringRef kSecPolicyAppleAssetReceipt - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); -extern const CFStringRef kSecPolicyAppleDeveloperIDPlusTicket - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); -extern const CFStringRef kSecPolicyAppleComponentCertificate - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); -extern const CFStringRef kSecPolicyAppleKeyTransparency - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); -extern const CFStringRef kSecPolicyAppleLegacySSL - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -/*! - @enum Policy Name Constants (Private) - @discussion Predefined constants used to specify a SSL Pinning policy. - To be used with SecTrustSetPolicyName. - @constant kSecPolicyNameAppleAST2Service - @constant kSecPolicyNameAppleEscrowProxyService - @constant kSecPolicyNameAppleFMiPService - @constant kSecPolicyNameAppleGSService - @constant kSecPolicyNameAppleHomeKitService - @constant kSecPolicyNameAppleiCloudSetupService - @constant kSecPolicyNameAppleIDSService - @constant kSecPolicyNameAppleMMCSService - @constant kSecPolicyNameApplePPQService - @constant kSecPolicyNameApplePushService - @constant kSecPolicyNameAppleAIDCService - @constant kSecPolicyNameAppleMapsService - @constant kSecPolicyNameAppleHealthProviderService - @constant kSecPolicyNameAppleParsecService - @constant kSecPolicyNameAppleAMPService - @constant kSecPolicyNameAppleSiriService - */ -extern const CFStringRef kSecPolicyNameAppleAST2Service - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleEscrowProxyService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleFMiPService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleGSService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleHomeKitService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleiCloudSetupService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleIDSService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleMMCSService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameApplePPQService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameApplePushService - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); -extern const CFStringRef kSecPolicyNameAppleAIDCService - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); -extern const CFStringRef kSecPolicyNameAppleMapsService - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); -extern const CFStringRef kSecPolicyNameAppleHealthProviderService - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); -extern const CFStringRef kSecPolicyNameAppleParsecService - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); -extern const CFStringRef kSecPolicyNameAppleAMPService - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); -extern const CFStringRef kSecPolicyNameAppleSiriService - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -/*! - @enum Policy Value Constants - @abstract Predefined property key constants used to get or set values in - a dictionary for a policy instance. - @discussion - All policies will have the following read-only value: - kSecPolicyOid (the policy object identifier) - - Additional policy values which your code can optionally set: - kSecPolicyName (name which must be matched) - kSecPolicyClient (evaluate for client, rather than server) - kSecPolicyRevocationFlags (only valid for a revocation policy) - kSecPolicyRevocationFlags (only valid for a revocation policy) - kSecPolicyTeamIdentifier (only valid for a Passbook signing policy) - kSecPolicyContext (valid for policies below that take a context parameter) - kSecPolicyPolicyName (only valid for GenericApplePinned or - GenericAppleSSLPinned policies) - kSecPolicyIntermediateMarkerOid (only valid for GenericApplePinned or - GenericAppleSSLPinned policies) - kSecPolicyLeafMarkerOid (only valid for GenericApplePinned or - GenericAppleSSLPinned policies) - kSecPolicyRootDigest (only valid for the UniqueDeviceCertificate policy) - - @constant kSecPolicyContext Specifies a CFDictionaryRef with keys and values - specified by the particular SecPolicyCreate function. - @constant kSecPolicyPolicyName Specifies a CFStringRef of the name of the - desired policy result. - @constant kSecPolicyIntermediateMarkerOid Specifies a CFStringRef of the - marker OID (in decimal format) required in the intermediate certificate. - @constant kSecPolicyLeafMarkerOid Specifies a CFStringRef of the - marker OID (in decimal format) required in the leaf certificate. - @constant kSecPolicyRootDigest Specifies a CFDataRef of digest required to - match the SHA-256 of the root certificate. - */ -extern const CFStringRef kSecPolicyContext - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyPolicyName - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyIntermediateMarkerOid - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyLeafMarkerOid - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); -extern const CFStringRef kSecPolicyRootDigest - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/*! - @enum Revocation Policy Constants - @abstract Predefined constants which allow you to specify how revocation - checking will be performed for a trust evaluation. - @constant kSecRevocationOnlineCheck If this flag is set, perform an online - revocation check, ignoring cached revocation results. This flag will not force - an online check if an online check was done within the last 5 minutes. Online - checks are only applicable to OCSP; this constant will not force a fresh - CRL download. - @constant kSecRevocationCheckIfTrusted If this flag is set, perform network-based - revocation checks only if the chain has no other validation errors. This flag - overrides SecTrustSetNetworkFetchAllowed and kSecRevocationNetworkAccessDisabled - for revocation checking (but not for intermediate fetching). - Note that this flag's behavior is not default because revoked certs produce Fatal - trust results, whereas most checks produce Recoverable trust results. If we skip - revocation checks on untrusted chains, the user may be able to ignore the failures - of a revoked cert. - */ -CF_ENUM(CFOptionFlags) { - kSecRevocationOnlineCheck = (1 << 5), - kSecRevocationCheckIfTrusted = (1 << 6), -}; - -/*! - @function SecPolicyCreateApplePinned - @abstract Returns a policy object for verifying Apple certificates. - @param policyName A string that identifies the policy name. - @param intermediateMarkerOID A string containing the decimal representation of the - extension OID in the intermediate certificate. - @param leafMarkerOID A string containing the decimal representation of the extension OID - in the leaf certificate. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if the value true is set for the key - "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the - com.apple.security preferences for the user of the calling application. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID matching the intermediateMarkerOID - parameter. - * The leaf has a marker extension with OID matching the leafMarkerOID parameter. - * Revocation is checked via any available method. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePinned(CFStringRef policyName, - CFStringRef intermediateMarkerOID, CFStringRef leafMarkerOID) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyCreateAppleSSLPinned - @abstract Returns a policy object for verifying Apple SSL certificates. - @param policyName A string that identifies the service/policy name. - @param hostname hostname to verify the certificate name against. - @param intermediateMarkerOID A string containing the decimal representation of the - extension OID in the intermediate certificate. If NULL is passed, the default OID of - 1.2.840.113635.100.6.2.12 is checked. - @param leafMarkerOID A string containing the decimal representation of the extension OID - in the leaf certificate. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if the value true is set for the key - "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the - com.apple.security preferences for the user of the calling application. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID matching the intermediateMarkerOID - parameter, or 1.2.840.113635.100.6.2.12 if NULL is passed. - * The leaf has a marker extension with OID matching the leafMarkerOID parameter. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef hostname, - CFStringRef __nullable intermediateMarkerOID, CFStringRef leafMarkerOID) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyCreateiPhoneActivation - @abstract Returns a policy object for verifying iPhone Activation - certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "iPhone Activation". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneActivation(void); - -/*! - @function SecPolicyCreateiPhoneDeviceCertificate - @abstract Returns a policy object for verifying iPhone Device certificate - chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 4 certs in chain. - * The first intermediate has Common Name "Apple iPhone Device CA". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneDeviceCertificate(void); - -/*! - @function SecPolicyCreateFactoryDeviceCertificate - @abstract Returns a policy object for verifying Factory Device certificate - chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to the Factory Device CA. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateFactoryDeviceCertificate(void); - -/*! - @function SecPolicyCreateiAP - @abstract Returns a policy object for verifying iAP certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The leaf has notBefore date after 5/31/2006 midnight GMT. - * The leaf has Common Name beginning with "IPA_". - The intended use of this policy is that the caller pass in the - intermediates for iAP1 and iAP2 to SecTrustSetAnchorCertificates(). - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiAP(void); - -/*! - @function SecPolicyCreateiTunesStoreURLBag - @abstract Returns a policy object for verifying iTunes Store URL bag - certificates. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to the iTMS CA. - * There are exactly 2 certs in the chain. - * The leaf has Organization "Apple Inc.". - * The leaf has Common Name "iTunes Store URL Bag". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiTunesStoreURLBag(void); - -/*! - @function SecPolicyCreateEAP - @abstract Returns a policy object for verifying for 802.1x/EAP certificates. - @param server Passing true for this parameter create a policy for EAP - server certificates. - @param trustedServerNames Optional; if present, the hostname in the leaf - certificate must be in the trustedServerNames list. Note that contrary - to all other policies the trustedServerNames list entries can have wildcards - whilst the certificate cannot. This matches the existing deployments. - @discussion This policy uses the Basic X.509 policy with validity check but - disallowing network fetching. If trustedServerNames param is non-null, the - ExtendedKeyUsage extension, if present, of the leaf certificate is verified - to contain either the ServerAuth OID, if the server param is true or - ClientAuth OID, otherwise. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateEAP(Boolean server, CFArrayRef __nullable trustedServerNames); - -/*! - @function SecPolicyCreateIPSec - @abstract Returns a policy object for evaluating IPSec certificate chains. - @param server Passing true for this parameter create a policy for IPSec - server certificates. - @param hostname Optional; if present, the policy will require the specified - hostname or ip address to match the hostname in the leaf certificate. - @discussion This policy uses the Basic X.509 policy with validity check. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateIPSec(Boolean server, CFStringRef __nullable hostname); - -/*! - @function SecPolicyCreateAppleSWUpdateSigning - @abstract Returns a policy object for evaluating SW update signing certs. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate ExtendedKeyUsage Extension contains 1.2.840.113635.100.4.1. - * The leaf ExtendedKeyUsage extension contains 1.2.840.113635.100.4.1. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSWUpdateSigning(void); - -/*! - @function SecPolicyCreateApplePackageSigning - @abstract Returns a policy object for evaluating installer package signing certs. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The leaf KeyUsage extension has the digital signature bit set. - * The leaf ExtendedKeyUsage extension has the CodeSigning OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePackageSigning(void); - -/*! - @function SecPolicyCreateiPhoneApplicationSigning - @abstract Returns a policy object for evaluating signed application - signatures. This is for apps signed directly by the app store. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "Apple iPhone OS Application Signing". - * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.3 or OID - 1.2.840.113635.100.6.1.6. - * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID - or the CodeSigning OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void); - -/*! - @function SecPolicyCreateiPhoneVPNApplicationSigning - @abstract Returns a policy object for evaluating signed VPN application - signatures. This is for VPN plugins signed directly by the VPN team. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "Apple iPhone OS Application Signing". - * The leaf has a marker extension with 1.2.840.113635.100.6.1.6. - * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID - or the CodeSigning OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneVPNApplicationSigning(void) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateiPhoneProfileApplicationSigning - @abstract Returns a policy object for evaluating signed application - signatures. This policy is for certificates inside a UPP or regular - profile. - @discussion This policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1 (WWDR CA). - * The leaf has a marker extension with OID matching one of the following: - * 1.2.840.113635.100.6.1.2 ("iPhone Developer" leaf) - * 1.2.840.113635.100.6.1.4 ("iPhone Distribution" leaf) - * 1.2.840.113635.100.6.1.25.1 ("TestFlight" leaf) - * On internal releases, 1.2.840.113635.100.6.1.25.2 - * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneProfileApplicationSigning(void); - -/*! - @function SecPolicyCreateMacOSProfileApplicationSigning - @abstract Returns a policy object for evaluating signed application - signatures. This policy is for certificates inside a UPP or regular - profile. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The leaf has a marker extension with OID matching one of the following: - * 1.2.840.113635.100.6.1.7 ("3rd Party Mac Developer Application" leaf) - * 1.2.840.113635.100.6.1.12 ("Mac Developer" leaf) - * 1.2.840.113635.100.6.1.13 ("Developer ID Application" leaf) - * 1.2.840.113635.100.6.22 ("Software Signing" leaf - * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMacOSProfileApplicationSigning(void) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateiPhoneProvisioningProfileSigning - @abstract Returns a policy object for evaluating provisioning profile signatures. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "Apple iPhone OS Provisioning Profile Signing". - * If the device is not a production device and is running an internal - release, the leaf may have the Common Name "TEST Apple iPhone OS - Provisioning Profile Signing TEST". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiPhoneProvisioningProfileSigning(void); - -/*! - @function SecPolicyCreateAppleTVOSApplicationSigning - @abstract Returns a policy object for evaluating signed application - signatures. This is for apps signed directly by the Apple TV app store, - and allows for both the prod and the dev/test certs. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. - Test roots are never permitted. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. - * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID or - the CodeSigning OID. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.24 or OID - 1.2.840.113635.100.6.1.24.1. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleTVOSApplicationSigning(void); - -/*! - @function SecPolicyCreateOCSPSigner - @abstract Returns a policy object for evaluating ocsp response signers. - @discussion This policy uses the Basic X.509 policy with validity check and - requires the leaf to have an ExtendedKeyUsage of OCSPSigning. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateOCSPSigner(void); - - -enum { - kSecSignSMIMEUsage = (1 << 0), - kSecKeyEncryptSMIMEUsage = (1 << 1), - kSecDataEncryptSMIMEUsage = (1 << 2), - kSecKeyExchangeDecryptSMIMEUsage = (1 << 3), - kSecKeyExchangeEncryptSMIMEUsage = (1 << 4), - kSecKeyExchangeBothSMIMEUsage = (1 << 5), - kSecAnyEncryptSMIME = kSecKeyEncryptSMIMEUsage | kSecDataEncryptSMIMEUsage | - kSecKeyExchangeDecryptSMIMEUsage | kSecKeyExchangeEncryptSMIMEUsage, - kSecIgnoreExpirationSMIMEUsage = (1 << 6) -}; - -/*! - @function SecPolicyCreateSMIME - @abstract Returns a policy object for evaluating S/MIME certificate chains. - @param smimeUsage Pass the bitwise or of one or more kSecXXXSMIMEUsage - flags, to indicate the intended usage of this certificate. - @param email Optional; if present, the policy will require the specified - email to match the email in the leaf certificate. - @discussion This policy uses the Basic X.509 policy with validity check and - requires the leaf to have - * a KeyUsage matching the smimeUsage, - * an ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID or the - EmailProtection OID, and - * if the email param is specified, the email address in the RFC822Name in the - SubjectAlternativeName extension or in the Email Address field of the - Subject Name. - Note that temporal validity checking can be disabled with kSecIgnoreExpirationSMIMEUsage - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef __nullable email); - -/*! - @function SecPolicyCreateCodeSigning - @abstract Returns a policy object for evaluating code signing certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check and - requires the leaf to have - * a KeyUsage with both the DigitalSignature and NonRepudiation bits set, and - * an ExtendedKeyUsage with the AnyExtendedKeyUsage OID or the CodeSigning OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateCodeSigning(void); - -/*! - @function SecPolicyCreateLockdownPairing - @abstract basic x509 policy for checking lockdown pairing certificate chains. - @discussion This policy checks some of the Basic X.509 policy options with no - validity check. It explicitly allows for empty subjects. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateLockdownPairing(void); - -/*! - @function SecPolicyCreateURLBag - @abstract Returns a policy object for evaluating certificate chains for signing URL bags. - @discussion This policy uses the Basic X.509 policy with no validity check and requires - that the leaf has ExtendedKeyUsage extension with the CodeSigning OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateURLBag(void); - -/*! - @function SecPolicyCreateOTATasking - @abstract Returns a policy object for evaluating certificate chains for signing OTA Tasking. - @discussion This policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "OTA Task Signing". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateOTATasking(void); - -/*! - @function SecPolicyCreateMobileAsset - @abstract Returns a policy object for evaluating certificate chains for signing Mobile Assets. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple iPhone Certification Authority". - * The leaf has Common Name "Asset Manifest Signing". - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMobileAsset(void); - -/*! - @function SecPolicyCreateMobileAssetDevelopment - @abstract Returns a policy object for evaluating certificate chains for signing development - Mobile Assets. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.55.1. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMobileAssetDevelopment(void) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateAppleIDAuthorityPolicy - @abstract Returns a policy object for evaluating certificate chains for Apple ID Authority. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3 - or OID 1.2.840.113635.100.6.2.7. - * The leaf has a marker extension with OID 1.2.840.113635.100.4.7. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleIDAuthorityPolicy(void); - -/*! - @function SecPolicyCreateMacAppStoreReceipt - @abstract Returns a policy object for evaluating certificate chains for signing - Mac App Store Receipts. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. - * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.6.1. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.11.1. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMacAppStoreReceipt(void); - -/*! - @function SecPolicyCreatePassbookCardSigner - @abstract Returns a policy object for evaluating certificate chains for signing Passbook cards. - @param cardIssuer Required; must match name in marker extension. - @param teamIdentifier Optional; if present, the policy will require the specified - team ID to match the organizationalUnit field in the leaf certificate's subject. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.16 and containing the - cardIssuer. - * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.14. - * The leaf has a Organizational Unit matching the TeamID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreatePassbookCardSigner(CFStringRef cardIssuer, - CFStringRef __nullable teamIdentifier); - -/*! - @function SecPolicyCreateMobileStoreSigner - @abstract Returns a policy object for evaluating Mobile Store certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple System Integration 2 Certification Authority". - * The leaf has KeyUsage with the DigitalSignature bit set. - * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.12. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMobileStoreSigner(void); - -/*! - @function SecPolicyCreateTestMobileStoreSigner - @abstract Returns a policy object for evaluating Test Mobile Store certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple System Integration 2 Certification Authority". - * The leaf has KeyUsage with the DigitalSignature bit set. - * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.12.1. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateTestMobileStoreSigner(void); - -/*! - @function SecPolicyCreateEscrowServiceSigner - @abstract Returns a policy object for evaluating Escrow Service certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to the current Escrow Roots in the OTAPKI asset. - * There are exactly 2 certs in the chain. - * The leaf has KeyUsage with the KeyEncipherment bit set. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateEscrowServiceSigner(void); - -/*! - @function SecPolicyCreatePCSEscrowServiceSigner - @abstract Returns a policy object for evaluating PCS Escrow Service certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to the current PCS Escrow Roots in the OTAPKI asset. - * There are exactly 2 certs in the chain. - * The leaf has KeyUsage with the KeyEncipherment bit set. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreatePCSEscrowServiceSigner(void); - -/*! - @function SecPolicyCreateOSXProvisioningProfileSigning - @abstract Returns a policy object for evaluating certificate chains for signing OS X - Provisioning Profiles. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. - * The leaf has KeyUsage with the DigitalSignature bit set. - * The leaf has a marker extension with OID 1.2.840.113635.100.4.11. - * Revocation is checked via OCSP. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateOSXProvisioningProfileSigning(void); - -/*! - @function SecPolicyCreateConfigurationProfileSigner - @abstract Returns a policy object for evaluating certificate chains for signing - Configuration Profiles. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3. - * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.16. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateConfigurationProfileSigner(void); - -/*! - @function SecPolicyCreateQAConfigurationProfileSigner - @abstract Returns a policy object for evaluating certificate chains for signing - QA Configuration Profiles. On customer builds, this function returns the same - policy as SecPolicyCreateConfigurationProfileSigner. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3. - * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.17. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateQAConfigurationProfileSigner(void); - -/*! - @function SecPolicyCreateOTAPKISigner - @abstract Returns a policy object for evaluating OTA PKI certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to Apple PKI Settings CA. - * There are exactly 2 certs in the chain. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateOTAPKISigner(void) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); - -/*! - @function SecPolicyCreateTestOTAPKISigner - @abstract Returns a policy object for evaluating OTA PKI certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to Apple Test PKI Settings CA. - * There are exactly 2 certs in the chain. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateTestOTAPKISigner(void) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); - -/*! - @function SecPolicyCreateAppleIDValidationRecordSigningPolicy - @abstract Returns a policy object for evaluating certificate chains for signing - Apple ID Validation Records. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3 - or OID 1.2.840.113635.100.6.2.10. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.25. - * Revocation is checked via OCSP. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. -*/ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleIDValidationRecordSigningPolicy(void); - -/*! - @function SecPolicyCreateAppleSMPEncryption - @abstract Returns a policy object for evaluating SMP certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.13. - * The leaf has KeyUsage with the KeyEncipherment bit set. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.30. - * Revocation is checked via OCSP. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSMPEncryption(void); - -/*! - @function SecPolicyCreateTestAppleSMPEncryption - @abstract Returns a policy object for evaluating Test SMP certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to a Test Apple Root with ECC public key certificate. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Test Apple System Integration CA - ECC". - * The leaf has KeyUsage with the KeyEncipherment bit set. - * Revocation is checked via OCSP. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateTestAppleSMPEncryption(void); - -/*! - @function SecPolicyCreateApplePPQSigning - @abstract Returns a policy object for verifying production PPQ Signing certificates. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple System Integration 2 Certification - Authority". - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. - * The leaf has KeyUsage with the DigitalSignature bit set. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.38.2. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePPQSigning(void); - -/*! - @function SecPolicyCreateTestApplePPQSigning - @abstract Returns a policy object for verifying test PPQ Signing certificates. On - customer builds, this function returns the same policy as SecPolicyCreateApplePPQSigning. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple System Integration 2 Certification - Authority". - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. - * The leaf has KeyUsage with the DigitalSignature bit set. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.38.1. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateTestApplePPQSigning(void); - -/*! - @function SecPolicyCreateAppleIDSService - @abstract Ensure we're appropriately pinned to the IDS service (SSL + Apple restrictions) - @discussion This policy uses the SSL server policy. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef __nullable hostname); - -/*! - @function SecPolicyCreateAppleIDSServiceContext - @abstract Ensure we're appropriately pinned to the IDS service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATIDS" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted only on internal releases either using the context dictionary or with - defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.4.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.4.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleIDSServiceContext(CFStringRef hostname, CFDictionaryRef __nullable context); - -/*! - @function SecPolicyCreateApplePushService - @abstract Ensure we're appropriately pinned to the Apple Push service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATAPN" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted only on internal releases either using the context dictionary or with - defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.5.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.5.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePushService(CFStringRef hostname, CFDictionaryRef __nullable context); - -/*! - @function SecPolicyCreateApplePushServiceLegacy - @abstract Ensure we're appropriately pinned to the Push service (via Entrust) - @param hostname Required; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to an Entrust Intermediate. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePushServiceLegacy(CFStringRef hostname); - -/*! - @function SecPolicyCreateAppleMMCSService - @abstract Ensure we're appropriately pinned to the MMCS service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATMMCS" with value - Boolean true will allow Test Apple roots and test OIDs on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or, if - enabled, OID 1.2.840.113635.100.6.27.11.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleMMCSService(CFStringRef hostname, CFDictionaryRef __nullable context); - -/*! - @function SecPolicyCreateAppleCompatibilityMMCSService - @abstract Ensure we're appropriately pinned to the MMCS service using compatibility certs - @param hostname Required; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to the GeoTrust Global CA - * The intermediate has a subject public key info hash matching the public key of - the Apple IST CA G1 intermediate. - * The chain length is 3. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or - OID 1.2.840.113635.100.6.27.11.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleCompatibilityMMCSService(CFStringRef hostname) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/*! - @function SecPolicyCreateAppleGSService - @abstract Ensure we're appropriately pinned to the GS service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATGS" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted only on internal releases either using the context dictionary or with - defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.2. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleGSService(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @function SecPolicyCreateApplePPQService - @abstract Ensure we're appropriately pinned to the PPQ service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATPPQ" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted only on internal releases either using the context dictionary or with - defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.3.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.3.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePPQService(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @function SecPolicyCreateAppleAST2Service - @abstract Ensure we're appropriately pinned to the AST2 Diagnostic service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATAST2" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted either using the context dictionary or with defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.8.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.8.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleAST2Service(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); - -/*! - @function SecPolicyCreateAppleEscrowProxyService - @abstract Ensure we're appropriately pinned to the iCloud Escrow Proxy service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATEscrow" with value -Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check -and pinning options: - * The chain is anchored to any of the production Apple Root CAs via full certificate - comparison. Test Apple Root CAs are permitted only on internal releases either - using the context dictionary or with defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.7.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease -on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleEscrowProxyService(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/*! - @function SecPolicyCreateAppleCompatibilityEscrowProxyService - @abstract Ensure we're appropriately pinned to the iCloud Escrow Proxy service using compatibility certs - @param hostname Required; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to the GeoTrust Global CA - * The intermediate has a subject public key info hash matching the public key of - the Apple IST CA G1 intermediate. - * The chain length is 3. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or, - if UAT is enabled with a defaults write (internal devices only), - OID 1.2.840.113635.100.6.27.7.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleCompatibilityEscrowProxyService(CFStringRef hostname) -__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/*! - @function SecPolicyCreateAppleFMiPService - @abstract Ensure we're appropriately pinned to the Find My iPhone service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATFMiP" with value - Boolean true will allow Test Apple roots on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs via full certificate - comparison. Test Apple Root CAs are permitted only on internal releases either - using the context dictionary or with defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.6.2 or, - if Test Roots are allowed, OID 1.2.840.113635.100.6.27.6.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleFMiPService(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); - -/*! - @function SecPolicyCreateAppleSSLService - @abstract Ensure we're appropriately pinned to an Apple server (SSL + Apple restrictions) - @param hostname Optional; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.1 - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage, if any, with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSSLService(CFStringRef __nullable hostname); - -/*! - @function SecPolicyCreateAppleTimeStamping - @abstract Returns a policy object for evaluating time stamping certificate chains. - @discussion This policy uses the Basic X.509 policy with validity check - and requires the leaf has ExtendedKeyUsage with the TimeStamping OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleTimeStamping(void); - -/*! - @function SecPolicyCreateApplePayIssuerEncryption - @abstract Returns a policy object for evaluating Apple Pay Issuer Encryption certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has Common Name "Apple Worldwide Developer Relations CA - G2". - * The leaf has KeyUsage with the KeyEncipherment bit set. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.39. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateApplePayIssuerEncryption(void) - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @function SecPolicyCreateAppleATVVPNProfileSigning - @abstract Returns a policy object for evaluating Apple TV VPN Profile certificate chains. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs - are permitted only on internal releases. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.43. - * Revocation is checked via OCSP. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleATVVPNProfileSigning(void) - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); - -/*! - @function SecPolicyCreateAppleHomeKitServerAuth - @abstract Ensure we're appropriately pinned to the HomeKit service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs via full certificate - comparison. Test Apple Root CAs are permitted only on internal releases with defaults write. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.16 - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.9. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) - __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); - -/*! - @function SecPolicyCreateAppleExternalDeveloper - @abstract Returns a policy object for verifying Apple-issued external developer - certificates. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1 - (WWDR CA) or 1.2.840.113635.100.6.2.6 (Developer ID CA). - * The leaf has a marker extension with OID matching one of the following: - * 1.2.840.113635.100.6.1.2 ("iPhone Developer" leaf) - * 1.2.840.113635.100.6.1.4 ("iPhone Distribution" leaf) - * 1.2.840.113635.100.6.1.5 ("Safari Developer" leaf) - * 1.2.840.113635.100.6.1.7 ("3rd Party Mac Developer Application" leaf) - * 1.2.840.113635.100.6.1.8 ("3rd Party Mac Developer Installer" leaf) - * 1.2.840.113635.100.6.1.12 ("Mac Developer" leaf) - * 1.2.840.113635.100.6.1.13 ("Developer ID Application" leaf) - * 1.2.840.113635.100.6.1.14 ("Developer ID Installer" leaf) - * The leaf has an ExtendedKeyUsage OID matching one of the following: - * 1.3.6.1.5.5.7.3.3 (CodeSigning EKU) - * 1.2.840.113635.100.4.8 ("Safari Developer" EKU) - * 1.2.840.113635.100.4.9 ("3rd Party Mac Developer Installer" EKU) - * 1.2.840.113635.100.4.13 ("Developer ID Installer" EKU) - * Revocation is checked via any available method. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleExternalDeveloper(void) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyCreateAppleSoftwareSigning - @abstract Returns a policy object for verifying the Apple Software Signing certificate. - @discussion The resulting policy uses the Basic X.509 policy with no validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has the Common Name "Apple Code Signing Certification Authority". - * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.22. - * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (Code Signing). - * Revocation is checked via any available method. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSoftwareSigning(void) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyGetName - @abstract Returns a policy's name. - @param policy A policy reference. - @result A policy name. - */ -__nullable CFStringRef SecPolicyGetName(SecPolicyRef policy) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyGetOidString - @abstract Returns a policy's oid in string decimal format. - @param policy A policy reference. - @result A policy oid. - */ -CFStringRef SecPolicyGetOidString(SecPolicyRef policy) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyCreateAppleUniqueDeviceCertificate - @abstract Returns a policy object for verifying Unique Device Identifier Certificates. - @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. - @discussion The resulting policy uses the Basic X.509 policy with no validity check and - pinning options: - * The chain is anchored to the SEP Root CA. Internal releases allow the chain to be - anchored to the testRootHash input if the value true is set for the key - "ApplePinningAllowTestCertsUCRT" in the com.apple.security preferences for the user - of the calling application. - * There are exactly 3 certs in the chain. - * The intermediate has an extension with OID matching 1.2.840.113635.100.6.44 and value - of "ucrt". - * The leaf has a marker extension with OID matching 1.2.840.113635.100.10.1. - * RSA key sizes are disallowed. EC key sizes are P-256 or larger. -@result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleUniqueDeviceCertificate(CFDataRef __nullable testRootHash) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecPolicyCreateAppleWarsaw - @abstract Returns a policy object for verifying signed Warsaw assets. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.14. - * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.29. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleWarsaw(void) - __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); - -/*! - @function SecPolicyCreateAppleSecureIOStaticAsset - @abstract Returns a policy object for verifying signed static assets for Secure IO. - @discussion The resulting policy uses the Basic X.509 policy with no validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.10. - * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.50. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void) - __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); - -/*! - @function SecPolicyCreateAppleiCloudSetupService - @abstract Ensure we're appropriately pinned to the iCloud Setup service (SSL + Apple restrictions) - @param hostname Required; hostname to verify the certificate name against. - @param context Optional; if present, "AppleServerAuthenticationAllowUATiCloudSetup" with value - Boolean true will allow Test Apple roots and test OIDs on internal releases. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or, if - enabled, OID 1.2.840.113635.100.6.27.15.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - * Revocation is checked via any available method. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleiCloudSetupService(CFStringRef hostname, CFDictionaryRef __nullable context) - __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); - -/*! - @function SecPolicyCreateAppleCompatibilityiCloudSetupService - @abstract Ensure we're appropriately pinned to the iCloud Setup service using compatibility certs - @param hostname Required; hostname to verify the certificate name against. - @discussion This policy uses the Basic X.509 policy with validity check - and pinning options: - * The chain is anchored to the GeoTrust Global CA - * The intermediate has a subject public key info hash matching the public key of - the Apple IST CA G1 intermediate. - * The chain length is 3. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or - OID 1.2.840.113635.100.6.27.15.1. - * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName - extension or Common Name. - * The leaf is checked against the Black and Gray lists. - * The leaf has ExtendedKeyUsage with the ServerAuth OID. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleCompatibilityiCloudSetupService(CFStringRef hostname) - __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); - -/*! - @function SecPolicyCreateAppleAppTransportSecurity - @abstract Ensure all certs in the evaluation meet ATS minimums - @discussion This policy is meant to be used alongside an SSL policy in order to enforce App Transport Security certificate rules: - * All certificates use either RSA key sizes of 2048-bits or larger or EC key sizes of 256-bits or larger. - * All certificates use SHA-256 or better for signature hash algorithms. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleAppTransportSecurity(void) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateMobileSoftwareUpdate - @abstract Returns a policy object for evaluating certificate chains for signing Mobile Software Updates. - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.57.2, or on internal releases, - 1.2.840.113635.100.6.57.1. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateMobileSoftwareUpdate(void) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateAppleBasicAttestationSystem - @abstract Returns a policy object for verifying Basic Attestation Authority SCRT-attested certs - @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to the Basic Attestation System Root CA. - * There are exactly 3 certs in the chain. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleBasicAttestationSystem(CFDataRef __nullable testRootHash) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateAppleBasicAttestationUser - @abstract Returns a policy object for verifying Basic Attestation Authority UCRT-attested certs - @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to the Basic Attestation User Root CA. - * There are exactly 3 certs in the chain. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleBasicAttestationUser(CFDataRef __nullable testRootHash) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecPolicyCreateiAPSWAuth - @abstract Returns a policy object for verifying iAP Software Auth certificates - @discussion The resulting policy uses the Basic X.509 policy with no validity check - and pinning options: - * There are exactly 2 certs in the chain. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.59.1 - The intended use of this policy is that the caller pass in the - SW Auth root to SecTrustSetAnchorCertificates(). - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiAPSWAuth(void) - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); - -/*! - @function SecPolicyCreateDemoDigitalCatalog - @abstract Returns a policy object for evaluating certificate chains for signing Digital - Catalog manifests for Demo units. - @discussion This policy uses the Basic X.509 policy with validity check and - pinning options: - * There are exactly 3 certs in the chain. - * The intermediate has common name "DemoUnit CA" - * The leaf has a marker extension with OID 1.2.840.113635.100.6.60 - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateDemoDigitalCatalogSigning(void) - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); - -/*! - @function SecPolicyCreateAppleAssetReceipt - @abstract Returns a policy object for evaluating certificate chains for signing Asset Receipts - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. Internal releases allow - the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.61. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleAssetReceipt(void) - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); - -/*! - @function SecPolicyCreateAppleDeveloperIDPlustTicket - @abstract Returns a policy object for evaluating certificate chains for signing Developer ID+ Tickets - @discussion This policy uses the Basic X.509 policy with no validity check - and pinning options: - * The chain is anchored to any of the production Apple Root CAs. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.17. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.30. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleDeveloperIDPlusTicket(void) - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); - -/*! - @function SecPolicyCreateiAPSWAuthWithExpiration - @abstract Returns a policy object for verifying iAP Software Auth certificates - @param checkExpiration Determines whether the policy checks expiration on the certificates - @discussion The resulting policy uses the Basic X.509 policy and pinning options: - * There are exactly 2 certs in the chain. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.59.1 - The intended use of this policy is that the caller pass in the - SW Auth root to SecTrustSetAnchorCertificates(). - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateiAPSWAuthWithExpiration(bool checkExpiration) - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); - -/*! - @function SecPolicyCreateAppleFDRProvisioning - @abstract Returns a policy object for verifying FDR Provisioning certificates - @discussion The resulting policy uses the Basic X.509 policy with no validity check. - The intended use of this policy is that the caller pass in the FDR root to SecTrustSetAnchorCertificates(). - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleFDRProvisioning(void) - API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); - -/*! - @function SecPolicyCreateAppleComponentCertificate - @abstract Returns a policy object for verifying Component certs - @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. - @discussion The resulting policy uses the Basic X.509 policy with validity check and - pinning options: - * The chain is anchored to the Component Root CA. - * There are exactly 3 certs in the chain. - * The leaf and intermediate each have a marker extension with OID matching 1.2.840.113635.100.11.1 - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleComponentCertificate(CFDataRef __nullable testRootHash) - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -/*! - @function SecPolicyCreateAppleKeyTransparency - @abstract Returns a policy object for verifying Apple certificates. - @param applicationId A string that identifies the applicationId. - @discussion The resulting policy uses the Basic X.509 policy with no validity check and - pinning options: - * The chain is anchored to any of the production Apple Root CAs. - * There are exactly 3 certs in the chain. - * The intermediate has a marker extension with OID TBD. - * The leaf has a marker extension with OID 1.2.840.113635.100.6.69.1 and value - matching the applicationId. - * Revocation is checked via any available method. - * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. - @result A policy object. The caller is responsible for calling CFRelease on this when - it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateAppleKeyTransparency(CFStringRef applicationId) - API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -/*! - @function SecPolicyCreateLegacySSL - @abstract Returns a policy object for evaluating legacy SSL certificate chains that don't meet - SecPolicyCreateSSL. - @param server Passing true for this parameter creates a policy for SSL - server certificates. - @param hostname (Optional) If present, the policy will require the specified - hostname to match the hostname in the leaf certificate. - @result A policy object. The caller is responsible for calling CFRelease - on this when it is no longer needed. - @discussion Use of this policy will be audited. Passing false for the server parameter will - result in a SecPolicy object with the same requirements as SecPolicyCreateSSL with a false - server parameter (i.e. the client authentication verification performed by this policy is - identical to the client authentication verification performed by SecPolicyCreateSSL). - */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateLegacySSL(Boolean server, CFStringRef __nullable hostname) - SPI_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); - -/* - * Legacy functions (OS X only) - */ -#if TARGET_OS_OSX - -/*! - @function SecPolicyCopy - @abstract Returns a copy of a policy reference based on certificate type and OID. - @param certificateType A certificate type. - @param policyOID The OID of the policy you want to find. This is a required parameter. See oidsalg.h to see a list of policy OIDs. - @param policy The returned policy reference. This is a required parameter. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later; - to obtain a policy reference, use one of the SecPolicyCreate* functions in SecPolicy.h. - */ -OSStatus SecPolicyCopy(CSSM_CERT_TYPE certificateType, const CSSM_OID *policyOID, SecPolicyRef * __nonnull CF_RETURNS_RETAINED policy) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecPolicyCopyAll - @abstract Returns an array of all known policies based on certificate type. - @param certificateType A certificate type. This is a optional parameter. Pass CSSM_CERT_UNKNOWN if the certificate type is unknown. - @param policies The returned array of policies. This is a required parameter. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in Mac OS X 10.7 and later; - to obtain a policy reference, use one of the SecPolicyCreate* functions in SecPolicy.h. (Note: there is normally - no reason to iterate over multiple disjointed policies, except to provide a way to edit trust settings for each - policy, as is done in certain certificate UI views. In that specific case, your code should call SecPolicyCreateWithOID - for each desired policy from the list of supported OID constants in SecPolicy.h.) - */ -OSStatus SecPolicyCopyAll(CSSM_CERT_TYPE certificateType, CFArrayRef * __nonnull CF_RETURNS_RETAINED policies) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/* Given a unified SecPolicyRef, return a copy with a legacy - C++ ItemImpl-based Policy instance. Only for internal use; - legacy references cannot be used by SecPolicy API functions. */ -__nullable CF_RETURNS_RETAINED -SecPolicyRef SecPolicyCreateItemImplInstance(SecPolicyRef policy); - -/* Given a CSSM_OID pointer, return a string which can be passed - to SecPolicyCreateWithProperties. The return value can be NULL - if no supported policy was found for the OID argument. */ -__nullable -CFStringRef SecPolicyGetStringForOID(CSSM_OID* oid) - API_DEPRECATED("No longer supported", macos(10.5,10.14)); - -/*! - @function SecPolicyCreateAppleTimeStampingAndRevocationPolicies - @abstract Create timeStamping policy array from a given set of policies by applying identical revocation behavior - @param policyOrArray can be a SecPolicyRef or a CFArray of SecPolicyRef - @discussion This function is deprecated in macOS 10.13 and later. Your code should call SecPolicyCreateAppleTimeStamping - and SecPolicyCreateRevocation instead to obtain these policies, then insert them into an array as needed. - */ -__nullable CF_RETURNS_RETAINED -CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); - -#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ - -/* MARK: WARNING: The following constants and functions are for project use - * within the Security project and are subject to change without warning */ - -/*! - @enum Policy Check Keys - @discussion Keys that represent various checks that can be done in a trust - policy. Use outside of the Security project at your own peril. - */ -extern const CFStringRef kSecPolicyCheckAnchorApple; -extern const CFStringRef kSecPolicyCheckAnchorSHA1; -extern const CFStringRef kSecPolicyCheckAnchorSHA256; -extern const CFStringRef kSecPolicyCheckAnchorTrusted; -extern const CFStringRef kSecPolicyCheckBasicCertificateProcessing; -extern const CFStringRef kSecPolicyCheckBasicConstraints; -extern const CFStringRef kSecPolicyCheckBasicConstraintsCA; -extern const CFStringRef kSecPolicyCheckBasicConstraintsPathLen; -extern const CFStringRef kSecPolicyCheckBlackListedKey; -extern const CFStringRef kSecPolicyCheckBlackListedLeaf; -extern const CFStringRef kSecPolicyCheckCertificatePolicy; -extern const CFStringRef kSecPolicyCheckChainLength; -extern const CFStringRef kSecPolicyCheckCriticalExtensions; -extern const CFStringRef kSecPolicyCheckCTRequired; -extern const CFStringRef kSecPolicyCheckEAPTrustedServerNames; -extern const CFStringRef kSecPolicyCheckEmail; -extern const CFStringRef kSecPolicyCheckExtendedKeyUsage; -extern const CFStringRef kSecPolicyCheckExtendedValidation; -extern const CFStringRef kSecPolicyCheckGrayListedKey; -extern const CFStringRef kSecPolicyCheckGrayListedLeaf; -extern const CFStringRef kSecPolicyCheckIdLinkage; -extern const CFStringRef kSecPolicyCheckIntermediateCountry; -extern const CFStringRef kSecPolicyCheckIntermediateEKU; -extern const CFStringRef kSecPolicyCheckIntermediateMarkerOid; -extern const CFStringRef kSecPolicyCheckIntermediateMarkerOidWithoutValueCheck; -extern const CFStringRef kSecPolicyCheckIntermediateOrganization; -extern const CFStringRef kSecPolicyCheckIntermediateSPKISHA256; -extern const CFStringRef kSecPolicyCheckIssuerCommonName; -extern const CFStringRef kSecPolicyCheckIssuerPolicyConstraints; -extern const CFStringRef kSecPolicyCheckIssuerNameConstraints; -extern const CFStringRef kSecPolicyCheckKeySize; -extern const CFStringRef kSecPolicyCheckKeyUsage; -extern const CFStringRef kSecPolicyCheckLeafMarkerOid; -extern const CFStringRef kSecPolicyCheckLeafMarkerOidWithoutValueCheck; -extern const CFStringRef kSecPolicyCheckLeafMarkersProdAndQA; -extern const CFStringRef kSecPolicyCheckMissingIntermediate; -extern const CFStringRef kSecPolicyCheckNameConstraints; -extern const CFStringRef kSecPolicyCheckNoNetworkAccess; -extern const CFStringRef kSecPolicyCheckNonEmptySubject; -extern const CFStringRef kSecPolicyCheckNotValidBefore; -extern const CFStringRef kSecPolicyCheckPinningRequired; -extern const CFStringRef kSecPolicyCheckPolicyConstraints; -extern const CFStringRef kSecPolicyCheckRevocation; -extern const CFStringRef kSecPolicyCheckRevocationIfTrusted; -extern const CFStringRef kSecPolicyCheckRevocationOnline; -extern const CFStringRef kSecPolicyCheckRevocationResponseRequired; -extern const CFStringRef kSecPolicyCheckSSLHostname; -extern const CFStringRef kSecPolicyCheckServerAuthEKU; -extern const CFStringRef kSecPolicyCheckSignatureHashAlgorithms; -extern const CFStringRef kSecPolicyCheckSubjectCommonName; -extern const CFStringRef kSecPolicyCheckSubjectCommonNamePrefix; -extern const CFStringRef kSecPolicyCheckSubjectCommonNameTEST; -extern const CFStringRef kSecPolicyCheckSubjectOrganization; -extern const CFStringRef kSecPolicyCheckSubjectOrganizationalUnit; -extern const CFStringRef kSecPolicyCheckSystemTrustedCTRequired; -extern const CFStringRef kSecPolicyCheckSystemTrustedWeakHash; -extern const CFStringRef kSecPolicyCheckSystemTrustedWeakKey; -extern const CFStringRef kSecPolicyCheckTemporalValidity; -extern const CFStringRef kSecPolicyCheckUnparseableExtension; -extern const CFStringRef kSecPolicyCheckUsageConstraints; -extern const CFStringRef kSecPolicyCheckValidityPeriodMaximums; -extern const CFStringRef kSecPolicyCheckValidRoot; -extern const CFStringRef kSecPolicyCheckWeakKeySize; -extern const CFStringRef kSecPolicyCheckWeakSignature; - -/* Special option for checking Apple Anchors */ -extern const CFStringRef kSecPolicyAppleAnchorIncludeTestRoots; - -/* Special option for checking Prod and QA Markers */ -extern const CFStringRef kSecPolicyLeafMarkerProd; -extern const CFStringRef kSecPolicyLeafMarkerQA; - -/* Special option for checking Revocation */ -extern const CFStringRef kSecPolicyCheckRevocationOCSP; -extern const CFStringRef kSecPolicyCheckRevocationCRL; -extern const CFStringRef kSecPolicyCheckRevocationAny; - -/* Policy Names */ -extern const CFStringRef kSecPolicyNameX509Basic; -extern const CFStringRef kSecPolicyNameSSLServer; -extern const CFStringRef kSecPolicyNameSSLClient; -extern const CFStringRef kSecPolicyNameEAPServer; -extern const CFStringRef kSecPolicyNameEAPClient; -extern const CFStringRef kSecPolicyNameIPSecServer; -extern const CFStringRef kSecPolicyNameIPSecClient; -extern const CFStringRef kSecPolicyNameSMIME; -extern const CFStringRef kSecPolicyNameCodeSigning; -extern const CFStringRef kSecPolicyNameTimeStamping; -extern const CFStringRef kSecPolicyNameOCSPSigner; - -/* - * MARK: SecPolicyCheckCert functions - */ -bool SecPolicyCheckCertSSLHostname(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertEmail(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertTemporalValidity(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertWeakKeySize(SecCertificateRef cert, CFTypeRef __nullable pvcValue); -bool SecPolicyCheckCertKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertExtendedKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertSubjectCommonName(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertSubjectCommonNamePrefix(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertSubjectCommonNameTEST(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertSubjectOrganization(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertSubjectOrganizationalUnit(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertNotValidBefore(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertEAPTrustedServerNames(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertLeafMarkerOid(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertLeafMarkersProdAndQA(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef __nullable pvcValue); -bool SecPolicyCheckCertKeySize(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertWeakSignature(SecCertificateRef cert, CFTypeRef __nullable pvcValue); -bool SecPolicyCheckCertSignatureHashAlgorithms(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertCertificatePolicy(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertCriticalExtensions(SecCertificateRef cert, CFTypeRef __nullable pvcValue); -bool SecPolicyCheckCertSubjectCountry(SecCertificateRef cert, CFTypeRef pvcValue); -bool SecPolicyCheckCertUnparseableExtension(SecCertificateRef cert, CFTypeRef pvcValue); - -void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName); -__nullable CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFErrorRef *error); - -void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); - -bool SecDNSIsTLD(CFStringRef reference); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -__END_DECLS - -#endif /* !_SECURITY_SECPOLICYPRIV_H_ */ diff --git a/trust/SecTrust.h b/trust/SecTrust.h deleted file mode 100644 index a48083cd..00000000 --- a/trust/SecTrust.h +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecTrust - The functions and data types in SecTrust implement trust computation - and allow the caller to apply trust decisions to the evaluation. - */ - -#ifndef _SECURITY_SECTRUST_H_ -#define _SECURITY_SECTRUST_H_ - -#include -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @typedef SecTrustResultType - @abstract Specifies the trust result type. - @discussion SecTrustResultType results have two dimensions. They specify - both whether evaluation succeeded and whether this is because of a user - decision. The commonly expected result is kSecTrustResultUnspecified, - which indicates a positive result that wasn't decided by the user. The - common failure is kSecTrustResultRecoverableTrustFailure, which means a - negative result. kSecTrustResultProceed and kSecTrustResultDeny are the - positive and negative result respectively when decided by the user. User - decisions are persisted through the use of SecTrustCopyExceptions() and - SecTrustSetExceptions(). Finally, kSecTrustResultFatalTrustFailure is a - negative result that must not be circumvented. - @constant kSecTrustResultInvalid Indicates an invalid setting or result. - This result usually means that SecTrustEvaluate has not yet been called. - @constant kSecTrustResultProceed Indicates you may proceed. This value - may be returned by the SecTrustEvaluate function or stored as part of - the user trust settings. - @constant kSecTrustResultConfirm Indicates confirmation with the user - is required before proceeding. Important: this value is no longer returned - or supported by SecTrustEvaluate or the SecTrustSettings API starting in - OS X 10.5; its use is deprecated in OS X 10.9 and later, as well as in iOS. - @constant kSecTrustResultDeny Indicates a user-configured deny; do not - proceed. This value may be returned by the SecTrustEvaluate function - or stored as part of the user trust settings. - @constant kSecTrustResultUnspecified Indicates the evaluation succeeded - and the certificate is implicitly trusted, but user intent was not - explicitly specified. This value may be returned by the SecTrustEvaluate - function or stored as part of the user trust settings. - @constant kSecTrustResultRecoverableTrustFailure Indicates a trust policy - failure which can be overridden by the user. This value may be returned - by the SecTrustEvaluate function but not stored as part of the user - trust settings. - @constant kSecTrustResultFatalTrustFailure Indicates a trust failure - which cannot be overridden by the user. This value may be returned by the - SecTrustEvaluate function but not stored as part of the user trust - settings. - @constant kSecTrustResultOtherError Indicates a failure other than that - of trust evaluation. This value may be returned by the SecTrustEvaluate - function but not stored as part of the user trust settings. - */ -typedef CF_ENUM(uint32_t, SecTrustResultType) { - kSecTrustResultInvalid CF_ENUM_AVAILABLE(10_3, 2_0) = 0, - kSecTrustResultProceed CF_ENUM_AVAILABLE(10_3, 2_0) = 1, - kSecTrustResultConfirm CF_ENUM_DEPRECATED(10_3, 10_9, 2_0, 7_0) = 2, - kSecTrustResultDeny CF_ENUM_AVAILABLE(10_3, 2_0) = 3, - kSecTrustResultUnspecified CF_ENUM_AVAILABLE(10_3, 2_0) = 4, - kSecTrustResultRecoverableTrustFailure CF_ENUM_AVAILABLE(10_3, 2_0) = 5, - kSecTrustResultFatalTrustFailure CF_ENUM_AVAILABLE(10_3, 2_0) = 6, - kSecTrustResultOtherError CF_ENUM_AVAILABLE(10_3, 2_0) = 7 -}; - -/*! - @typedef SecTrustRef - @abstract CFType used for performing X.509 certificate trust evaluations. - */ -typedef struct CF_BRIDGED_TYPE(id) __SecTrust *SecTrustRef; - -/*! - @enum Trust Property Constants - @discussion Predefined key constants used to obtain values in a - per-certificate dictionary of trust evaluation results, - as retrieved from a call to SecTrustCopyProperties. - @constant kSecPropertyTypeTitle Specifies a key whose value is a - CFStringRef containing the title (display name) of this certificate. - @constant kSecPropertyTypeError Specifies a key whose value is a - CFStringRef containing the reason for a trust evaluation failure. - */ -extern const CFStringRef kSecPropertyTypeTitle - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); -extern const CFStringRef kSecPropertyTypeError - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); - -/*! - @enum Trust Result Constants - @discussion Predefined key constants used to obtain values in a - dictionary of trust evaluation results for a certificate chain, - as retrieved from a call to SecTrustCopyResult. - @constant kSecTrustEvaluationDate - This key will be present if a trust evaluation has been performed - and results are available. Its value is a CFDateRef representing - when the evaluation for this trust object took place. - @constant kSecTrustExtendedValidation - This key will be present and have a value of kCFBooleanTrue - if this chain was validated for EV. - @constant kSecTrustOrganizationName - Organization name field of subject of leaf certificate. This - field is meant to be displayed to the user as the validated - name of the company or entity that owns the certificate if the - kSecTrustExtendedValidation key is present. - @constant kSecTrustResultValue - This key will be present if a trust evaluation has been performed. - Its value is a CFNumberRef representing the SecTrustResultType result - for the evaluation. - @constant kSecTrustRevocationChecked - This key will be present iff this chain had its revocation checked. - The value will be a kCFBooleanTrue if revocation checking was - successful and none of the certificates in the chain were revoked. - The value will be kCFBooleanFalse if no current revocation status - could be obtained for one or more certificates in the chain due - to connection problems or timeouts. This is a hint to a client - to retry revocation checking at a later time. - @constant kSecTrustRevocationValidUntilDate - This key will be present iff kSecTrustRevocationChecked has a - value of kCFBooleanTrue. The value will be a CFDateRef representing - the earliest date at which the revocation info for one of the - certificates in this chain might change. - @constant kSecTrustCertificateTransparency - This key will be present and have a value of kCFBooleanTrue - if this chain is CT qualified. - @constant kSecTrustCertificateTransparencyWhiteList - This key will be present and have a value of kCFBooleanTrue - if this chain is EV, not CT qualified, but included of the CT WhiteList. - */ -extern const CFStringRef kSecTrustEvaluationDate - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustExtendedValidation - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustOrganizationName - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustResultValue - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustRevocationChecked - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustRevocationValidUntilDate - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -extern const CFStringRef kSecTrustCertificateTransparency - __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); -extern const CFStringRef kSecTrustCertificateTransparencyWhiteList - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13, __IPHONE_10_0, __IPHONE_11_0); - -#ifdef __BLOCKS__ -/*! - @typedef SecTrustCallback - @abstract Delivers the result from an asynchronous trust evaluation. - @param trustRef A reference to the trust object which has been evaluated. - @param trustResult The trust result of the evaluation. Additional status - information can be obtained by calling SecTrustCopyProperties(). - */ -typedef void (^SecTrustCallback)(SecTrustRef trustRef, SecTrustResultType trustResult); -#endif /* __BLOCKS__ */ - - -/*! - @function SecTrustGetTypeID - @abstract Returns the type identifier of SecTrust instances. - @result The CFTypeID of SecTrust instances. - */ -CFTypeID SecTrustGetTypeID(void) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecTrustCreateWithCertificates - @abstract Creates a trust object based on the given certificates and - policies. - @param certificates The group of certificates to verify. This can either - be a CFArrayRef of SecCertificateRef objects or a single SecCertificateRef - @param policies An array of one or more policies. You may pass a - SecPolicyRef to represent a single policy. - @param trust On return, a pointer to the trust management reference. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If multiple policies are passed in, all policies must verify - for the chain to be considered valid. - */ -OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates, - CFTypeRef __nullable policies, SecTrustRef * __nonnull CF_RETURNS_RETAINED trust) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecTrustSetPolicies - @abstract Set the policies for which trust should be verified. - @param trust A trust reference. - @param policies An array of one or more policies. You may pass a - SecPolicyRef to represent a single policy. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will invalidate the existing trust result, - requiring a fresh evaluation for the newly-set policies. - */ -OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef policies) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_6_0); - -/*! - @function SecTrustCopyPolicies - @abstract Returns an array of policies used for this evaluation. - @param trust A reference to a trust object. - @param policies On return, an array of policies used by this trust. - Call the CFRelease function to release this reference. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef * __nonnull CF_RETURNS_RETAINED policies) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_7_0); - -/*! - @function SecTrustSetNetworkFetchAllowed - @abstract Specifies whether a trust evaluation is permitted to fetch missing - intermediate certificates from the network. - @param trust A trust reference. - @param allowFetch If true, and a certificate's issuer is not present in the - trust reference but its network location is known, the evaluation is permitted - to attempt to download it automatically. Pass false to disable network fetch - for this trust evaluation. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion By default, network fetch of missing certificates is enabled if - the trust evaluation includes the SSL policy, otherwise it is disabled. - */ -OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, - Boolean allowFetch) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecTrustGetNetworkFetchAllowed - @abstract Returns whether a trust evaluation is permitted to fetch missing - intermediate certificates from the network. - @param trust A trust reference. - @param allowFetch On return, the boolean pointed to by this parameter is - set to true if the evaluation is permitted to download missing certificates. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion By default, network fetch of missing certificates is enabled if - the trust evaluation includes the SSL policy, otherwise it is disabled. - */ -OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, - Boolean *allowFetch) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecTrustSetAnchorCertificates - @abstract Sets the anchor certificates for a given trust. - @param trust A reference to a trust object. - @param anchorCertificates An array of anchor certificates. - Pass NULL to restore the default set of anchor certificates. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Calling this function without also calling - SecTrustSetAnchorCertificatesOnly() will disable trusting any - anchors other than the ones in anchorCertificates. - */ -OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, - CFArrayRef __nullable anchorCertificates) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecTrustSetAnchorCertificatesOnly - @abstract Reenables trusting anchor certificates in addition to those - passed in via the SecTrustSetAnchorCertificates API. - @param trust A reference to a trust object. - @param anchorCertificatesOnly If true, disables trusting any anchors other - than the ones passed in via SecTrustSetAnchorCertificates(). If false, - the built in anchor certificates are also trusted. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, - Boolean anchorCertificatesOnly) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecTrustCopyCustomAnchorCertificates - @abstract Returns an array of custom anchor certificates used by a given - trust, as set by a prior call to SecTrustSetAnchorCertificates, or NULL if - no custom anchors have been specified. - @param trust A reference to a trust object. - @param anchors On return, an array of custom anchor certificates (roots) - used by this trust, or NULL if no custom anchors have been specified. Call - the CFRelease function to release this reference. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, - CFArrayRef * __nonnull CF_RETURNS_RETAINED anchors) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_7_0); - -/*! - @function SecTrustSetVerifyDate - @abstract Set the date for which the trust should be verified. - @param trust A reference to a trust object. - @param verifyDate The date for which to verify trust. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function lets you evaluate certificate validity for a - given date (for example, to determine if a signature was valid on the date - it was signed, even if the certificate has since expired.) If this function - is not called, the time at which SecTrustEvaluate() is called is used - implicitly as the verification time. - */ -OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); - -/*! - @function SecTrustGetVerifyTime - @abstract Returns the verify time. - @param trust A reference to the trust object being verified. - @result A CFAbsoluteTime value representing the time at which certificates - should be checked for validity. - @discussion This function retrieves the verification time for the given - trust reference, as set by a prior call to SecTrustSetVerifyDate(). If the - verification time has not been set, this function returns a value of 0, - indicating that the current date/time is implicitly used for verification. - */ -CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); - -/*! - @function SecTrustEvaluate - @abstract Evaluates a trust reference synchronously. - @param trust A reference to the trust object to evaluate. - @param result A pointer to a result type. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will completely evaluate trust before returning, - possibly including network access to fetch intermediate certificates or to - perform revocation checking. Since this function can block during those - operations, you should call it from within a function that is placed on a - dispatch queue, or in a separate thread from your application's main - run loop. Alternatively, you can use the SecTrustEvaluateAsync function. - */ -OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) - API_DEPRECATED_WITH_REPLACEMENT("SecTrustEvaluateWithError", - macos(10.3, 10.15), - ios(2.0, 13.0), - watchos(1.0, 6.0), - tvos(2.0, 13.0)); - -#ifdef __BLOCKS__ -/*! - @function SecTrustEvaluateAsync - @abstract Evaluates a trust reference asynchronously. - @param trust A reference to the trust object to evaluate. - @param queue A dispatch queue on which the result callback should be - executed. Pass NULL to use the current dispatch queue. - @param result A SecTrustCallback block which will be executed when the - trust evaluation is complete. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecTrustEvaluateAsync(SecTrustRef trust, - dispatch_queue_t __nullable queue, SecTrustCallback result) - API_DEPRECATED_WITH_REPLACEMENT("SecTrustEvaluateAsyncWithError", - macos(10.7, 10.15), - ios(7.0, 13.0), - watchos(1.0, 6.0), - tvos(7.0, 13.0)); -#endif - -/*! - @function SecTrustEvaluateWithError - @abstract Evaluates a trust reference synchronously. - @param trust A reference to the trust object to evaluate. - @param error A pointer to an error object - @result A boolean value indicating whether the certificate is trusted - @discussion This function will completely evaluate trust before returning, - possibly including network access to fetch intermediate certificates or to - perform revocation checking. Since this function can block during those - operations, you should call it from within a function that is placed on a - dispatch queue, or in a separate thread from your application's main - run loop. - If the certificate is trusted and the result is true, the error will be set to NULL. - If the certificate is not trusted or the evaluation was unable to complete, the result - will be false and the error will be set with a description of the failure. - The error contains a code for the most serious error encountered (if multiple trust - failures occurred). The localized description indicates the certificate with the most - serious problem and the type of error. The underlying error contains a localized - description of each certificate in the chain that had an error and all errors found - with that certificate. - */ -__attribute__((warn_unused_result)) bool -SecTrustEvaluateWithError(SecTrustRef trust, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) - API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); - -#ifdef __BLOCKS__ -/*! - @typedef SecTrustWithErrorCallback - @abstract Delivers the result from an asynchronous trust evaluation. - @param trustRef A reference to the trust object which has been evaluated. - @param result A boolean value indicating whether the certificate is trusted. - @param error An error if the trust evaluation failed. - */ -typedef void (^SecTrustWithErrorCallback)(SecTrustRef trustRef, bool result, CFErrorRef _Nullable error); - -/*! - @function SecTrustEvaluateAsyncWithError - @abstract Evaluates a trust reference asynchronously. - @param trust A reference to the trust object to evaluate. - @param queue A dispatch queue on which the result callback will be executed. Note that this - function MUST be called from that queue. - @param result A SecTrustWithErrorCallback block which will be executed when the trust evaluation - is complete. - The block is guaranteed to be called exactly once when the result code is errSecSuccess, and not - called otherwise. Note that this block may be called synchronously inline if no asynchronous - operations are required. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion If the certificate is trusted, the callback will return a result parameter of true - and the error will be set to NULL. - If the certificate is not trusted or the evaluation was unable to complete, the result parameter - will be false and the error will be set with a description of the failure. The error contains a - code for the most serious error encountered (if multiple trust failures occurred). The localized - description indicates the certificate with the most serious problem and the type of error. The - underlying error contains a localized description of each certificate in the chain that had an - error and all errors found with that certificate. - */ -OSStatus SecTrustEvaluateAsyncWithError(SecTrustRef trust, dispatch_queue_t queue, SecTrustWithErrorCallback result) - API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0)); -#endif /* __BLOCKS__ */ - -/*! - @function SecTrustGetTrustResult - @param trust A reference to a trust object. - @param result A pointer to the result from the most recent call to - SecTrustEvaluate for this trust reference. If SecTrustEvaluate has not been - called or trust parameters have changed, the result is kSecTrustResultInvalid. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function replaces SecTrustGetResult for the purpose of - obtaining the current evaluation result of a given trust reference. - */ -OSStatus SecTrustGetTrustResult(SecTrustRef trust, - SecTrustResultType *result) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); - -/*! - @function SecTrustCopyPublicKey - @abstract Return the public key for a leaf certificate after it has - been evaluated. - @param trust A reference to the trust object which has been evaluated. - @result The certificate's public key, or NULL if it the public key could - not be extracted (this can happen if the public key algorithm is not - supported). The caller is responsible for calling CFRelease on the - returned key when it is no longer needed. - */ -__nullable -SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - -/*! - @function SecTrustGetCertificateCount - @abstract Returns the number of certificates in an evaluated certificate - chain. - @param trust A reference to a trust object. - @result The number of certificates in the trust chain, including the anchor. - @discussion Important: if the trust reference has not yet been evaluated, - this function will evaluate it first before returning. If speed is critical, - you may want to call SecTrustGetTrustResult first to make sure that a - result other than kSecTrustResultInvalid is present for the trust object. - */ -CFIndex SecTrustGetCertificateCount(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - -/*! - @function SecTrustGetCertificateAtIndex - @abstract Returns a certificate from the trust chain. - @param trust Reference to a trust object. - @param ix The index of the requested certificate. Indices run from 0 - (leaf) to the anchor (or last certificate found if no anchor was found). - The leaf cert (index 0) is always present regardless of whether the trust - reference has been evaluated or not. - @result A SecCertificateRef for the requested certificate. - */ -__nullable -SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - -/*! - @function SecTrustCopyExceptions - @abstract Returns an opaque cookie which will allow future evaluations - of the current certificate to succeed. - @param trust A reference to an evaluated trust object. - @result An opaque cookie which when passed to SecTrustSetExceptions() will - cause a call to SecTrustEvaluate() return kSecTrustResultProceed. This - will happen upon subsequent evaluation of the current certificate unless - some new error starts happening that wasn't being reported when the cookie - was returned from this function (for example, if the certificate expires - then evaluation will start failing again until a new cookie is obtained.) - @discussion Normally this API should only be called once the errors have - been presented to the user and the user decided to trust the current - certificate chain regardless of the errors being presented, for the - current application/server/protocol combination. - */ -CFDataRef SecTrustCopyExceptions(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); - -/*! - @function SecTrustSetExceptions - @abstract Set a trust cookie to be used for evaluating this certificate chain. - @param trust A reference to a trust object. - @param exceptions An exceptions cookie as returned by a call to - SecTrustCopyExceptions() in the past. You may pass NULL to clear any - exceptions which have been previously set on this trust reference. - @result Upon calling SecTrustEvaluate(), any failures that were present at the - time the exceptions object was created are ignored, and instead of returning - kSecTrustResultRecoverableTrustFailure, kSecTrustResultProceed will be returned - (if the certificate for which exceptions was created matches the current leaf - certificate). - @result Returns true if the exceptions cookies was valid and matches the current - leaf certificate, false otherwise. This function will invalidate the existing - trust result, requiring a subsequent evaluation for the newly-set exceptions. - Note that this function returning true doesn't mean the caller can skip calling - SecTrustEvaluate, as there may be new errors since the exceptions cookie was - created (for example, a certificate may have subsequently expired.) - @discussion Clients of this interface will need to establish the context of this - exception to later decide when this exception cookie is to be used. - Examples of this context would be the server we are connecting to, the ssid - of the wireless network for which this cert is needed, the account for which - this cert should be considered valid, and so on. - */ -bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef __nullable exceptions) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); - -/*! - @function SecTrustCopyProperties - @abstract Return a property array for this trust evaluation. - @param trust A reference to a trust object. If the trust has not been - evaluated, the returned property array will be empty. - @result A property array. It is the caller's responsibility to CFRelease - the returned array when it is no longer needed. - @discussion This function returns an ordered array of CFDictionaryRef - instances for each certificate in the chain. Indices run from 0 (leaf) to - the anchor (or last certificate found if no anchor was found.) See the - "Trust Property Constants" section for a list of currently defined keys. - */ -__nullable -CFArrayRef SecTrustCopyProperties(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); - -/*! - @function SecTrustCopyResult - @abstract Returns a dictionary containing information about the - evaluated certificate chain for use by clients. - @param trust A reference to a trust object. - @result A dictionary with various fields that can be displayed to the user, - or NULL if no additional info is available or the trust has not yet been - validated. The caller is responsible for calling CFRelease on the value - returned when it is no longer needed. - @discussion Returns a dictionary for the overall trust evaluation. See the - "Trust Result Constants" section for a list of currently defined keys. - */ -__nullable -CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecTrustSetOCSPResponse - @abstract Attach OCSPResponse data to a trust object. - @param trust A reference to a trust object. - @param responseData This may be either a CFData object containing a single - DER-encoded OCSPResponse (per RFC 2560), or a CFArray of these. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Allows the caller to provide OCSPResponse data (which may be - obtained during a TLS/SSL handshake, per RFC 3546) as input to a trust - evaluation. If this data is available, it can obviate the need to contact - an OCSP server for current revocation information. - */ -OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef __nullable responseData) - __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); - -/*! - @function SecTrustSignedCertificateTimestamps - @abstract Attach SignedCertificateTimestamp data to a trust object. - @param trust A reference to a trust object. - @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962). - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Allows the caller to provide SCT data (which may be - obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust - evaluation. - */ -OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef __nullable sctArray) - API_AVAILABLE(macos(10.14.2), ios(12.1.1), tvos(12.1.1), watchos(5.1.1)); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -/* - * Legacy functions (OS X only) - */ -#if TARGET_OS_OSX -#include -#include - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/*! - @typedef SecTrustUserSetting - @abstract Specifies a user-specified trust setting value. - @discussion Deprecated in OS X 10.9. User trust settings are managed by - functions in SecTrustSettings.h (starting with OS X 10.5), and by the - SecTrustCopyExceptions and SecTrustSetExceptions functions (starting with - iOS 4 and OS X 10.9). The latter two functions are recommended for both OS X - and iOS, as they avoid the need to explicitly specify these values. - */ -typedef SecTrustResultType SecTrustUserSetting - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); - -/*! - @typedef SecTrustOptionFlags - @abstract Options for customizing trust evaluation. - @constant kSecTrustOptionAllowExpired Allow expired certificates. - @constant kSecTrustOptionLeafIsCA Allow CA as leaf certificate. - @constant kSecTrustOptionFetchIssuerFromNet Allow network fetch of CA cert. - @constant kSecTrustOptionAllowExpiredRoot Allow expired roots. - @constant kSecTrustOptionRequireRevPerCert Require positive revocation - check per certificate. - @constant kSecTrustOptionUseTrustSettings Use TrustSettings instead of - anchors. - @constant kSecTrustOptionImplicitAnchors Properly self-signed certs are - treated as anchors implicitly. - */ -typedef CF_OPTIONS(uint32_t, SecTrustOptionFlags) { - kSecTrustOptionAllowExpired = 0x00000001, - kSecTrustOptionLeafIsCA = 0x00000002, - kSecTrustOptionFetchIssuerFromNet = 0x00000004, - kSecTrustOptionAllowExpiredRoot = 0x00000008, - kSecTrustOptionRequireRevPerCert = 0x00000010, - kSecTrustOptionUseTrustSettings = 0x00000020, - kSecTrustOptionImplicitAnchors = 0x00000040 -}; - -/*! - @function SecTrustSetOptions - @abstract Sets optional flags for customizing a trust evaluation. - @param trustRef A trust reference. - @param options Flags to change evaluation behavior for this trust. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is not available on iOS. Use SecTrustSetExceptions - and SecTrustCopyExceptions to modify default trust results, and - SecTrustSetNetworkFetchAllowed to specify whether missing CA certificates - can be fetched from the network. - */ -OSStatus SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); - -/*! - @function SecTrustSetParameters - @abstract Sets the action and action data for a trust object. - @param trustRef The reference to the trust to change. - @param action A trust action. - @param actionData A reference to data associated with this action. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in OS X 10.7 and later, where it - was replaced by SecTrustSetOptions, and is not available on iOS. Your code - should use SecTrustSetExceptions and SecTrustCopyExceptions to modify default - trust results, and SecTrustSetNetworkFetchAllowed to specify whether missing - CA certificates can be fetched from the network. - */ -OSStatus SecTrustSetParameters(SecTrustRef trustRef, - CSSM_TP_ACTION action, CFDataRef actionData) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustSetKeychains - @abstract Sets the keychains for a given trust object. - @param trust A reference to a trust object. - @param keychainOrArray A reference to an array of keychains to search, a - single keychain, or NULL to use the default keychain search list. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in macOS 10.13 and later. Beginning in - macOS 10.12, this function no longer affected the behavior of the trust - evaluation: the user's keychain search list and the system - anchors keychain are searched for certificates to complete the chain. To change - the keychains that are searched, callers must use SecKeychainSetSearchList to - change the user's keychain search list. - Note: this function was never applicable to iOS. - */ -OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef __nullable keychainOrArray) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustGetResult - @abstract Returns detailed information on the outcome of an evaluation. - @param trustRef A reference to a trust object. - @param result A pointer to the result from the call to SecTrustEvaluate. - @param certChain On return, a pointer to the certificate chain used to - validate the input certificate. Call the CFRelease function to release - this pointer. - @param statusChain On return, a pointer to the status of the certificate - chain. Do not attempt to free this pointer; it remains valid until the - trust is destroyed or the next call to SecTrustEvaluate. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in OS X 10.7 and later, - and is not available on iOS. - To get the complete certificate chain, use SecTrustGetCertificateCount and - SecTrustGetCertificateAtIndex. To get detailed status information for each - certificate, use SecTrustCopyProperties. To get the overall trust result - for the evaluation, use SecTrustGetTrustResult. - */ -OSStatus SecTrustGetResult(SecTrustRef trustRef, SecTrustResultType * __nullable result, - CFArrayRef * __nullable CF_RETURNS_RETAINED certChain, CSSM_TP_APPLE_EVIDENCE_INFO * __nullable * __nullable statusChain) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustGetCssmResult - @abstract Gets the CSSM trust result. - @param trust A reference to a trust. - @param result On return, a pointer to the CSSM trust result. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in OS X 10.7 and later, - and is not available on iOS. - To get detailed status information for each certificate, use - SecTrustCopyProperties. To get the overall trust result for the evaluation, - use SecTrustGetTrustResult. - */ -OSStatus SecTrustGetCssmResult(SecTrustRef trust, - CSSM_TP_VERIFY_CONTEXT_RESULT_PTR __nullable * __nonnull result) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustGetCssmResultCode - @abstract Gets the result code from the most recent call to SecTrustEvaluate - for the specified trust. - @param trust A reference to a trust. - @param resultCode On return, the result code produced by the most recent - evaluation of the given trust (cssmerr.h). The value of resultCode is - undefined if SecTrustEvaluate has not been called. - @result A result code. See "Security Error Codes" (SecBase.h). Returns - errSecTrustNotAvailable if SecTrustEvaluate has not been called for the - specified trust. - @discussion This function is deprecated in OS X 10.7 and later, - and is not available on iOS. - To get detailed status information for each certificate, use - SecTrustCopyProperties. To get the overall trust result for the evaluation, - use SecTrustGetTrustResult. - */ -OSStatus SecTrustGetCssmResultCode(SecTrustRef trust, OSStatus *resultCode) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustGetTPHandle - @abstract Gets the CSSM trust handle - @param trust A reference to a trust. - @param handle On return, a CSSM trust handle. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is deprecated in OS X 10.7 and later. - */ -OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustCopyAnchorCertificates - @abstract Returns an array of default anchor (root) certificates used by - the system. - @param anchors On return, an array containing the system's default anchors - (roots). Call the CFRelease function to release this pointer. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function is not available on iOS, as certificate data - for system-trusted roots is currently unavailable on that platform. - */ -OSStatus SecTrustCopyAnchorCertificates(CFArrayRef * __nonnull CF_RETURNS_RETAINED anchors) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ - -__END_DECLS - -#endif /* !_SECURITY_SECTRUST_H_ */ diff --git a/trust/SecTrustPriv.h b/trust/SecTrustPriv.h deleted file mode 100644 index 5bf6e60b..00000000 --- a/trust/SecTrustPriv.h +++ /dev/null @@ -1,641 +0,0 @@ -/* - * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecTrustPriv - The functions and data types in SecTrustPriv implement trust computation - and allow the user to apply trust decisions to the trust configuration. - */ - -#ifndef _SECURITY_SECTRUSTPRIV_H_ -#define _SECURITY_SECTRUSTPRIV_H_ - -#include -#include -#include -#include -#include - -__BEGIN_DECLS - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -/* Constants used as keys in property lists. See - SecTrustCopySummaryPropertiesAtIndex for more information. */ -extern const CFStringRef kSecPropertyKeyType; -extern const CFStringRef kSecPropertyKeyLabel; -extern const CFStringRef kSecPropertyKeyLocalizedLabel; -extern const CFStringRef kSecPropertyKeyValue; - -extern const CFStringRef kSecPropertyTypeWarning; -extern const CFStringRef kSecPropertyTypeSuccess; -extern const CFStringRef kSecPropertyTypeSection; -extern const CFStringRef kSecPropertyTypeData; -extern const CFStringRef kSecPropertyTypeString; -extern const CFStringRef kSecPropertyTypeURL; -extern const CFStringRef kSecPropertyTypeDate; -extern const CFStringRef kSecPropertyTypeArray; -extern const CFStringRef kSecPropertyTypeNumber; - -/* Constants used as keys in the dictionary returned by SecTrustCopyInfo. */ -extern const CFStringRef kSecTrustInfoExtendedValidationKey; -extern const CFStringRef kSecTrustInfoCompanyNameKey; -extern const CFStringRef kSecTrustInfoRevocationKey; -extern const CFStringRef kSecTrustInfoRevocationValidUntilKey; -extern const CFStringRef kSecTrustInfoCertificateTransparencyKey; - -/* Constants used as keys in the certificate details dictionary. - An array of per-certificate details is returned by SecTrustCopyResult - as the value of the kSecTrustResultDetails key. -*/ -extern const CFStringRef kSecCertificateDetailStatusCodes; - /*__OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);*/ - -/*! - @enum Trust Result Constants - @discussion Predefined key constants used to obtain values in a - dictionary of trust evaluation results for a certificate chain, - as retrieved from a call to SecTrustCopyResult. - - @constant kSecTrustResultDetails - This key will be present if a trust evaluation has been performed. - Its value is a CFArrayRef of CFDictionaryRef representing detailed - status info for each certificate in the completed chain. - @constant kSecTrustRevocationReason - This key will be present iff this chain had its revocation checked, - and a "revoked" response was received. The value of this key will - be a CFNumberRef indicating the reason for revocation. The possible - reason code values are described in RFC 5280, section 5.3.1. - */ -extern const CFStringRef kSecTrustResultDetails; - /*__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_9_0);*/ -extern const CFStringRef kSecTrustRevocationReason; - /*__OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);*/ - -/*! - @function SecTrustCopySummaryPropertiesAtIndex - @abstract Return a property array for the certificate. - @param trust A reference to the trust object to evaluate. - @param ix The index of the requested certificate. Indices run from 0 - (leaf) to the anchor (or last certificate found if no anchor was found). - @result A property array. It is the caller's responsibility to CFRelease - the returned array when it is no longer needed. This function returns a - short summary description of the certificate in question. The property - at index 0 of the array might also include general information about the - entire chain's validity in the context of this trust evaluation. - - @discussion Returns a property array for this trust certificate. A property - array is an array of CFDictionaryRefs. Each dictionary (we call it a - property for short) has the following keys: - - kSecPropertyKeyType This key's value determines how this property - should be displayed. Its associated value is one of the - following: - kSecPropertyTypeWarning - The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not - set. The kSecPropertyKeyValue is a CFStringRef which should - be displayed in yellow with a warning triangle. - kSecPropertyTypeError - The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not - set. The kSecPropertyKeyValue is a CFStringRef which should - be displayed in red with an error X. - kSecPropertyTypeSuccess - The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not - set. The kSecPropertyKeyValue is a CFStringRef which should - be displayed in green with a checkmark in front of it. - kSecPropertyTypeTitle - The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not - set. The kSecPropertyKeyValue is a CFStringRef which should - be displayed in a larger bold font. - kSecPropertyTypeSection - The optional kSecPropertyKeyLocalizedLabel is a CFStringRef with the name - of the next section to display. The value of the - kSecPropertyKeyValue key is a CFArrayRef which is a property - array as defined here. - kSecPropertyTypeData - The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing - the localized label for the value for the kSecPropertyKeyValue. - The type of this value is a CFDataRef. Its contents should be - displayed as: "bytes length_of_data : hexdump_of_data". Ideally - the UI will only show one line of hex dump data and have a - disclosure arrow to see the remainder. - kSecPropertyTypeString - The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing - the localized label for the value for the kSecPropertyKeyValue. - The type of this value is a CFStringRef. It's contents should be - displayed in the normal font. - kSecPropertyTypeURL - The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing - the localized label for the value for the kSecPropertyKeyValue. - The type of this value is a CFURLRef. It's contents should be - displayed as a hyperlink. - kSecPropertyTypeDate - The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing - the localized label for the value for the kSecPropertyKeyValue. - The type of this value is a CFDateRef. It's contents should be - displayed in human readable form (probably in the current - timezone). - kSecPropertyKeyLocalizedLabel - Human readable localized label for a given property. - kSecPropertyKeyValue - See description of kSecPropertyKeyType to determine what the value - for this key is. - kSecPropertyKeyLabel - Non localized key (label) for this value. This is only - present for properties with fixed label names. - @result A property array. It is the caller's responsability to CFRelease - the returned array when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix); - -/*! - @function SecTrustCopyDetailedPropertiesAtIndex - @abstract Return a property array for the certificate. - @param trust A reference to the trust object to evaluate. - @param ix The index of the requested certificate. Indices run from 0 - (leaf) to the anchor (or last certificate found if no anchor was found). - @result A property array. It is the caller's responsibility to CFRelease - the returned array when it is no longer needed. - See SecTrustCopySummaryPropertiesAtIndex on how to intepret this array. - Unlike that function call this function returns a detailed description - of the certificate in question. - */ -__nullable CF_RETURNS_RETAINED -CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix); - -/*! - @function SecTrustCopyInfo - @abstract Return a dictionary with additional information about the - evaluated certificate chain for use by clients. - @param trust A reference to an evaluated trust object. - @discussion Returns a dictionary for this trust evaluation. This - dictionary may have the following keys: - - kSecTrustInfoExtendedValidationKey this key will be present and have - a value of kCFBooleanTrue if this chain was validated for EV. - kSecTrustInfoCompanyNameKey Company name field of subject of leaf - certificate, this field is meant to be displayed to the user - if the kSecTrustInfoExtendedValidationKey is present. - kSecTrustInfoRevocationKey this key will be present iff this chain - had its revocation checked. The value will be a kCFBooleanTrue - if revocation checking was successful and none of the - certificates in the chain were revoked. - The value will be kCFBooleanFalse if no current revocation status - could be obtained for one or more certificates in the chain due - to connection problems or timeouts etc. This is a hint to a - client to retry revocation checking at a later time. - kSecTrustInfoRevocationValidUntilKey this key will be present iff - kSecTrustInfoRevocationKey has a value of kCFBooleanTrue. - The value will be a CFDateRef representing the earliest date at - which the revocation info for one of the certificates in this chain - might change. - - @result A dictionary with various fields that can be displayed to the user, - or NULL if no additional info is available or the trust has not yet been - validated. The caller is responsible for calling CFRelease on the value - returned when it is no longer needed. - */ -__nullable CF_RETURNS_RETAINED -CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust); - -/* For debugging purposes. */ -__nullable -CFArrayRef SecTrustGetDetails(SecTrustRef trust); - -__nullable CF_RETURNS_RETAINED -CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust); - -/*! - @function SecTrustIsExpiredOnly - @abstract Determine whether expiration is the only problem with a certificate chain. - @param trust A reference to a trust object. - @result A boolean value indicating whether expiration is the only problem found - with the certificate chain in the given trust reference. - @discussion Returns true if one or more certificates in the chain have expired, - expiration is an error (i.e. it is not being ignored by existing trust settings), - and it is the only error encountered. Returns false if the certificate(s) have not - expired, or are expired but have trust settings to override their expiration, - or if the trust chain has other errors beside expiration. Your code should call - this function after SecTrustEvaluate has returned a recoverable trust failure, - so you can distinguish this case from other possible errors. - */ -Boolean SecTrustIsExpiredOnly(SecTrustRef trust) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/* For debugging purposes. */ -__nullable CF_RETURNS_RETAINED -CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust); - -/* - @function SecTrustGetTrustStoreVersionNumber - @abstract Ask trustd what trust store version it is using. - @param error A returned error if trustd failed to answer. - @result The current version of the trust store. 0 upon failure. - */ -uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); - -/* - @function SecTrustGetAssetVersionNumber - @abstract Ask trustd what asset version it is using. - @param error A returned error if trustd failed to answer. - @result The current version of the asset. 0 upon failure. - */ -uint64_t SecTrustGetAssetVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); - -/* - @function SecTrustOTAPKIGetUpdatedAsset - @abstract Trigger trustd to fetch a new trust supplementals asset right now. - @param error A returned error if trustd failed to update the asset. - @result The current version of the update, regardless of the success of the update. - @discussion This function blocks up to 1 minute until trustd has finished with the - asset download and update. You should use the error parameter to determine whether - the update was was successful. The current asset version is always returned. - */ -uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); - -/* - @function SecTrustOTASecExperimentGetUpdatedAsset - @abstract Trigger trustd to fetch a new SecExperiment asset right now. - @param error A returned error if trustd failed to update the asset. - @result The current version of the update, regardless of the success of the update. - @discussion This function blocks up to 1 minute until trustd has finished with the - asset download and update. You should use the error parameter to determine whether - the update was was successful. The current asset version is always returned. - */ -uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); - -/* - @function SecTrustOTASecExperimentCopyAsset - @abstract Get current asset from trustd - @param error A returned error if trustd fails to return asset - @result Dictionary of asset - @discussion If the error parameter is supplied, and the function returns false, - the caller is subsequently responsible for releasing the returned CFErrorRef. - */ -CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); - -/*! - @function SecTrustFlushResponseCache - @abstract Removes all OCSP responses from the per-user response cache. - @param error An optional pointer to an error object - @result A boolean value indicating whether the operation was successful. - @discussion If the error parameter is supplied, and the function returns false, - the caller is subsequently responsible for releasing the returned CFErrorRef. - */ -Boolean SecTrustFlushResponseCache(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) - __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); - -/*! - @function SecTrustSetTrustedLogs - @abstract Sets the trusted CT logs for a given trust. - @param trust A reference to a trust object. - @param trustedLogs An array of trusted logs. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion trustedLog is a CFArray of CFData containing the DER-encode SubjectPublicKeyInfo - of the trusted CT logs. - */ -OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs); - -/* Keychain searches are allowed by default. Use this to turn off seaching of - -keychain search list (i.e. login.keychain, system.keychain) - -Local Items/iCloud Keychain - -user- and admin-trusted roots - -network-fetched issuers - User must provide all necessary certificates in the input certificates and/or anchors. */ -OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/* Get the keychain search policy for the trust object. */ -OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean * __nonnull allowed) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecTrustEvaluateLeafOnly - @abstract Evaluates the leaf of the trust reference synchronously. - @param trust A reference to the trust object to evaluate. - @param result A pointer to a result type. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function will only evaluate the trust of the leaf certificate. - No chain will be built and only those aspects of the SecPolicyRef that address - the expected contents of the leaf will be checked. This function does not honor - any set exceptions or usage constraints. - */ -OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType * __nonnull result) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecTrustSerialize - @abstract Creates a serialized version of the trust object - @param trust A reference to the trust object to serialize. - @param error A pointer to an error. - @result The serialized trust object. - @discussion This function is intended to be used to share SecTrustRefs between - processes. Saving the results to disk or sending them over network channels - may cause unexpected behavior. - */ -__nullable CF_RETURNS_RETAINED -CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecTrustDeserialize - @abstract Creates a trust object from the serialized data - @param serializedTrust A reference to the serialized trust object - @param error A pointer to an error. - @result A trust object - @discussion This function is intended to be used to share SecTrustRefs between - processes. Saving the results to disk or sending them over network channels - may cause unexpected behavior. - */ -__nullable CF_RETURNS_RETAINED -SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecTrustGetTrustExceptionsArray - @abstract Return the exceptions array currently set in the trust object - @param trust A reference to the trust object - @result The array of exceptions. - @discussion This function returns an array of exceptions that was previously set - using SecTrustSetExceptions, unlike SecTrustCopyExceptions which returns the - exceptions which could be set using SecTrustSetExceptions. - */ -__nullable CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) - __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); - -/*! - @function SecTrustCopyInputCertificates - @abstract Return the array of certificates currently set in the trust object - @param trust A reference to the trust object - @param certificates On return, an array of the certificates used by this trust. - Call the CFRelease function to release this reference. - @result A result code. See "Security Error Codes" (SecBase.h) -*/ -OSStatus SecTrustCopyInputCertificates(SecTrustRef trust, CFArrayRef * _Nonnull CF_RETURNS_RETAINED certificates) -__OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); - -/*! - @function SecTrustAddToInputCertificates - @abstract Add certificate(s) to the currently set certificates in the trust object - @param trust A reference to the trust object - @param certificates The group of certificates to add. This can either be a CFArrayRef - of SecCertificateRef objects or a single SecCertificateRef. - @result A result code. See "Security Error Codes" (SecBase.h) - */ -OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef _Nonnull certificates) - __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); - -/*! - @function SecTrustSetPinningPolicyName - @abstract Set the policy name to be used during the trust evaluation. - @param trust A reference to the trust object - @param policyName A string representing the name of the pinning policy to be used. - @result A result code. See "Security Error Codes" (SecBase.h) - @discussion This function permits the caller to enable the dynamic lookup of the - pinning policy using a built-in database as an alternative to using a SecPolicyCreate function - with the pinning rules and calling SecTrustCreateWithCertificates or SecTrustSetPolicies. - */ -OSStatus SecTrustSetPinningPolicyName(SecTrustRef trust, CFStringRef policyName) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -/*! - @function SecTrustSetPinningException - @abstract Remove pinning requirement from this trust evaluation - @param trust A reference to the trust object - @result A result code. See "Security Error Codes" (SecBase.h) - @discussion This function provides an exception for this particular trust for a bundle that - otherwise requires pinning for all connections. Bundles use the SecTrustPinningRequired key - with boolean value of true in their info plist to indicate that all SSL connections from the - bundle must be pinned. - */ -OSStatus SecTrustSetPinningException(SecTrustRef trust) - __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); - -#if TARGET_OS_IPHONE -/*! - @function SecTrustGetExceptionResetCount - @abstract Returns the current epoch of trusted exceptions. - @param error A pointer to an error. - @result An unsigned 64-bit integer representing the current epoch. - @discussion Exceptions tagged with an older epoch are not trusted. - */ -uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error) - API_UNAVAILABLE(macos, iosmac) API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0)); - -/*! - @function SecTrustIncrementExceptionResetCount - @abstract Increases the current epoch of trusted exceptions by 1. - @param error A pointer to an error. - @result A result code. See "Security Error Codes" (SecBase.h) - @discussion By increasing the current epoch any existing exceptions, tagged with the old epoch, become distrusted. - */ -OSStatus SecTrustIncrementExceptionResetCount(CFErrorRef *error) - __API_UNAVAILABLE(macos, iosmac) __API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0)); -#endif - -#ifdef __BLOCKS__ -/*! - @function SecTrustEvaluateFastAsync - @abstract Evaluates a trust reference asynchronously. - @param trust A reference to the trust object to evaluate. - @param queue A dispatch queue on which the result callback will be - executed. Note that this function MUST be called from that queue. - @param result A SecTrustCallback block which will be executed when the - trust evaluation is complete. The block is guaranteed to be called exactly once - when the result code is errSecSuccess, and not called otherwise. Note that this - block may be called synchronously inline if no asynchronous operations are required. - @result A result code. See "Security Error Codes" (SecBase.h). - */ -OSStatus SecTrustEvaluateFastAsync(SecTrustRef trust, dispatch_queue_t queue, SecTrustCallback result) - __API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); -#endif - -/*! - @function SecTrustReportTLSAnalytics - @discussion This function MUST NOT be called outside of the TLS stack. -*/ -bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) - __API_AVAILABLE(macos(10.13.4), ios(11.3), tvos(11.3), watchos(4.3)); - -/*! - @function SecTrustReportNetworkingAnalytics - @discussion This function MUST NOT be called outside of the networking stack. -*/ -bool SecTrustReportNetworkingAnalytics(const char *eventName, xpc_object_t eventAttributes) - __API_AVAILABLE(macos(10.15), ios(13), tvos(13), watchos(5)); - -/*! - @function SecTrustSetNeedsEvaluation - @abstract Reset the evaluation state of the trust object - @param trust Trust object to reset - @discussion Calling this will reset the trust object so that the next time SecTrustEvaluate* - is called, a new trust evaluation is performed. SecTrustSet* interfaces implicitly call this, - so this function is only necessary if you've made system configuration changes (like trust - settings) that don't impact the trust object itself. - */ -void SecTrustSetNeedsEvaluation(SecTrustRef trust); - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -/* - * Legacy functions (OS X only) - */ -#if TARGET_OS_OSX - -CF_ASSUME_NONNULL_BEGIN -CF_IMPLICIT_BRIDGING_ENABLED - -#if SEC_OS_IPHONE -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wfour-char-constants" -#endif /* SEC_OS_IPHONE */ -/* - unique keychain item attributes for user trust records. - */ -enum { - kSecTrustCertAttr = 'tcrt', - kSecTrustPolicyAttr = 'tpol', - /* Leopard and later */ - kSecTrustPubKeyAttr = 'tpbk', - kSecTrustSignatureAttr = 'tsig' -}; - -#if SEC_OS_IPHONE -#pragma clang diagnostic pop -#endif /* SEC_OS_IPHONE */ - -/*! - @function SecTrustGetUserTrust - @abstract Gets the user-specified trust settings of a certificate and policy. - @param certificate A reference to a certificate. - @param policy A reference to a policy. - @param trustSetting On return, a pointer to the user specified trust settings. - @result A result code. See "Security Error Codes" (SecBase.h). - @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. - */ -OSStatus SecTrustGetUserTrust(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting * __nullable trustSetting) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustSetUserTrust - @abstract Sets the user-specified trust settings of a certificate and policy. - @param certificate A reference to a certificate. - @param policy A reference to a policy. - @param trustSetting The user-specified trust settings. - @result A result code. See "Security Error Codes" (SecBase.h). - @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. - @discussion as of Mac OS version 10.5, this will result in a call to - SecTrustSettingsSetTrustSettings(). - */ -OSStatus SecTrustSetUserTrust(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting trustSetting) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustSetUserTrustLegacy - @abstract Sets the user-specified trust settings of a certificate and policy. - @param certificate A reference to a certificate. - @param policy A reference to a policy. - @param trustSetting The user-specified trust settings. - @result A result code. See "Security Error Codes" (SecBase.h). - - @This is the private version of what used to be SecTrustSetUserTrust(); it operates - on UserTrust entries as that function used to. The current SecTrustSetUserTrust() - function operated on Trust Settings. - */ -OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting trustSetting) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustGetCSSMAnchorCertificates - @abstract Retrieves the CSSM anchor certificates. - @param cssmAnchors A pointer to an array of anchor certificates. - @param cssmAnchorCount A pointer to the number of certificates in anchors. - @result A result code. See "Security Error Codes" (SecBase.h). - @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. - */ -OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA * __nullable * __nullable cssmAnchors, uint32 *cssmAnchorCount) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); - -/*! - @function SecTrustCopyExtendedResult - @abstract Gets the extended trust result after an evaluation has been performed. - @param trust A trust reference. - @param result On return, result points to a CFDictionaryRef containing extended trust results (if no error occurred). - The caller is responsible for releasing this dictionary with CFRelease when finished with it. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion This function may only be used after SecTrustEvaluate has been called for the trust reference, otherwise - errSecTrustNotAvailable is returned. If the certificate is not an extended validation certificate, there is - no extended result data and errSecDataNotAvailable is returned. Currently, only one dictionary key is defined - (kSecEVOrganizationName). - - Note: this function will be deprecated in a future release of OS X. Your - code should use SecTrustCopyResult to obtain the trust results dictionary. - */ -OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef * __nonnull CF_RETURNS_RETAINED result) - __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12, __IPHONE_NA, __IPHONE_NA); - -/* - * Preference-related strings for Revocation policies. - */ - -/* - * Preference domain, i.e., the name of a plist in ~/Library/Preferences or in - * /Library/Preferences - */ -#define kSecRevocationDomain "com.apple.security.revocation" - -/* OCSP and CRL style keys, followed by values used for both of them */ -#define kSecRevocationOcspStyle CFSTR("OCSPStyle") -#define kSecRevocationCrlStyle CFSTR("CRLStyle") -#define kSecRevocationOff CFSTR("None") -#define kSecRevocationBestAttempt CFSTR("BestAttempt") -#define kSecRevocationRequireIfPresent CFSTR("RequireIfPresent") -#define kSecRevocationRequireForAll CFSTR("RequireForAll") - -/* Which first if both enabled? */ -#define kSecRevocationWhichFirst CFSTR("RevocationFirst") -#define kSecRevocationOcspFirst CFSTR("OCSP") -#define kSecRevocationCrlFirst CFSTR("CRL") - -/* boolean: A "this policy is sufficient per cert" for each */ -#define kSecRevocationOCSPSufficientPerCert CFSTR("OCSPSufficientPerCert") -#define kSecRevocationCRLSufficientPerCert CFSTR("CRLSufficientPerCert") - -/* local OCSP responder URI, value arbitrary string value */ -#define kSecOCSPLocalResponder CFSTR("OCSPLocalResponder") - -/* Extended trust result keys (now in public API) */ -#define kSecEVOrganizationName kSecTrustOrganizationName -#define kSecTrustExpirationDate kSecTrustRevocationValidUntilDate - -CF_IMPLICIT_BRIDGING_DISABLED -CF_ASSUME_NONNULL_END - -#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ - -__END_DECLS - -#endif /* !_SECURITY_SECTRUSTPRIV_H_ */ diff --git a/trust/SecTrustSettings.h b/trust/SecTrustSettings.h deleted file mode 100644 index 48a2eb74..00000000 --- a/trust/SecTrustSettings.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2006,2007,2011,2012,2014-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/*! - @header SecTrustSettings - The functions and data types in SecTrustSettings implement a way to - set and retrive trustability of certificates. -*/ - -#ifndef _SECURITY_SECTRUSTSETTINGS_H_ -#define _SECURITY_SECTRUSTSETTINGS_H_ - -#include -#include -#include -#include - -#if SEC_OS_OSX -#include -#include -#include -#endif /* SEC_OS_OSX */ - -__BEGIN_DECLS - -#if SEC_OS_OSX_INCLUDES -CF_ASSUME_NONNULL_BEGIN -#endif - -/* - * Any certificate (cert) which resides in a keychain can have associated with - * it a set of Trust Settings. Trust Settings specify conditions in which a - * given cert can be trusted or explicitly distrusted. A "trusted" cert is - * either a root (self-signed) cert that, when a cert chain verifies back to that - * root, the entire cert chain is trusted; or a non-root cert that does not need - * to verify to a trusted root cert (which is normally the case when verifying a - * cert chain). An "explicitly distrusted" cert is one which will, when encountered - * during the evaluation of a cert chain, cause immediate and unconditional failure - * of the verify operation. - * - * Trust Settings are configurable by the user; they can apply on three levels - * (called domains): - * - * -- Per-user. - * -- Locally administered, system-wide. Administrator privileges are required - * to make changes to this domain. - * -- System. These Trust Settings are immutable and comprise the set of trusted - * root certificates supplied in Mac OS X. - * - * Per-user Trust Settings override locally administered Trust Settings, which - * in turn override the System Trust Settings. - * - * Each cert's Trust Settings are expressed as a CFArray which includes any - * number (including zero) of CFDictionaries, each of which comprises one set of - * Usage Constraints. Each Usage Constraints dictionary contains zero or one of - * each the following components: - * - * key = kSecTrustSettingsPolicy On OSX, value = SecPolicyRef - On iOS, value = policy OID as CFString - * - * key = kSecTrustSettingsApplication value = SecTrustedApplicationRef - * key = kSecTrustSettingsPolicyString value = CFString, policy-specific - * key = kSecTrustSettingsKeyUsage value = CFNumber, an SInt32 key usage - * - * A given Usage Constraints dictionary applies to a given cert if *all* of the - * usage constraint components specified in the dictionary match the usage of - * the cert being evaluated; when this occurs, the value of the - * kSecTrustSettingsResult entry in the dictionary, shown below, is the effective - * trust setting for the cert. - * - * key = kSecTrustSettingsResult value = CFNumber, an SInt32 SecTrustSettingsResult - * - * The overall Trust Settings of a given cert are the sum of all such Usage - * Constraints CFDictionaries: Trust Settings for a given usage apply if *any* - * of the CFDictionaries in the cert's Trust Settings array satisfies - * the specified usage. Thus, when a cert has multiple Usage Constraints - * dictionaries in its Trust Settings array, the overall Trust Settings - * for the cert are - * - * (Usage Constraint 0 component 0 AND Usage Constraint 0 component 1 ...) - * -- OR -- - * (Usage Constraint 1 component 0 AND Usage Constraint 1 component 1 ...) - * -- OR -- - * ... - * - * Notes on the various Usage Constraints components: - * - * kSecTrustSettingsPolicy Specifies a cert verification policy, e.g., SSL, - * SMIME, etc, using Policy Constants - * kSecTrustSettingsApplication Specifies the application performing the cert - * verification. - * kSecTrustSettingsPolicyString Policy-specific. For the SMIME policy, this is - * an email address. - * For the SSL policy, this is a host name. - * kSecTrustSettingsKeyUsage A bitfield indicating key operations (sign, - * encrypt, etc.) for which this Usage Constraint - * apply. Values are defined below as the - * SecTrustSettingsKeyUsage enum. - * kSecTrustSettingsResult The resulting trust value. If not present this has a - * default of kSecTrustSettingsResultTrustRoot, meaning - * "trust this root cert". Other legal values are: - * kSecTrustSettingsResultTrustAsRoot : trust non-root - * cert as if it were a trusted root. - * kSecTrustSettingsResultDeny : explicitly distrust this - * cert. - * kSecTrustSettingsResultUnspecified : neither trust nor - * distrust; can be used to specify an "Allowed error" - * (see below) without assigning trust to a specific - * cert. - * - * Another optional component in a Usage Constraints dictionary is a CSSM_RETURN - * which, if encountered during certificate verification, is ignored for that - * cert. These "allowed error" values are constrained by Usage Constraints as - * described above; a Usage Constraint dictionary with no constraints but with - * an Allowed Error value causes that error to always be allowed when the cert - * is being evaluated. - * - * The "allowed error" entry in a Usage Constraints dictionary is formatted - * as follows: - * - * key = kSecTrustSettingsAllowedError value = CFNumber, an SInt32 CSSM_RETURN - * - * Note that if kSecTrustSettingsResult value of kSecTrustSettingsResultUnspecified - * is *not* present for a Usage Constraints dictionary with no Usage - * Constraints, the default of kSecTrustSettingsResultTrustRoot is assumed. To - * specify a kSecTrustSettingsAllowedError without explicitly trusting (or - * distrusting) the associated cert, specify kSecTrustSettingsResultUnspecified - * for the kSecTrustSettingsResult component. - * - * Note that an empty Trust Settings array means "always trust this cert, - * with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot". - * An empty Trust Settings array is definitely not the same as *no* Trust - * Settings, which means "this cert must be verified to a known trusted cert". - * - * Note the distinction between kSecTrustSettingsResultTrustRoot and - * kSecTrustSettingsResultTrustAsRoot; the former can only be applied to - * root (self-signed) certs; the latter can only be applied to non-root - * certs. This also means that an empty TrustSettings array for a non-root - * cert is invalid, since the default value for kSecTrustSettingsResult is - * kSecTrustSettingsResultTrustRoot, which is invalid for a non-root cert. - * - * Authentication - * -------------- - * - * When making changes to the per-user Trust Settings, the user will be - * prompted with an alert panel asking for authentication via user name a - * password (or other credentials normally used for login). This means - * that it is not possible to modify per-user Trust Settings when not - * running in a GUI environment (i.e. the user is not logged in via - * Loginwindow). - * - * When making changes to the system-wide Trust Settings, the user will be - * prompted with an alert panel asking for an administrator's name and - * password, unless the calling process is running as root in which case - * no futher authentication is needed. - */ - -/* - * The keys in one Usage Constraints dictionary. - */ -#define kSecTrustSettingsPolicy CFSTR("kSecTrustSettingsPolicy") -#define kSecTrustSettingsApplication CFSTR("kSecTrustSettingsApplication") -#define kSecTrustSettingsPolicyString CFSTR("kSecTrustSettingsPolicyString") -#define kSecTrustSettingsKeyUsage CFSTR("kSecTrustSettingsKeyUsage") -#define kSecTrustSettingsAllowedError CFSTR("kSecTrustSettingsAllowedError") -#define kSecTrustSettingsResult CFSTR("kSecTrustSettingsResult") - -/* - * Key usage bits, the value for Usage Constraints key kSecTrustSettingsKeyUsage. - */ -typedef CF_OPTIONS(uint32_t, SecTrustSettingsKeyUsage) { - /* sign/verify data */ - kSecTrustSettingsKeyUseSignature = 0x00000001, - /* bulk encryption */ - kSecTrustSettingsKeyUseEnDecryptData = 0x00000002, - /* key wrap/unwrap */ - kSecTrustSettingsKeyUseEnDecryptKey = 0x00000004, - /* sign/verify cert */ - kSecTrustSettingsKeyUseSignCert = 0x00000008, - /* sign/verify CRL and OCSP */ - kSecTrustSettingsKeyUseSignRevocation = 0x00000010, - /* key exchange, e.g., Diffie-Hellman */ - kSecTrustSettingsKeyUseKeyExchange = 0x00000020, - /* any usage (the default if this value is not specified) */ - kSecTrustSettingsKeyUseAny = 0xffffffff -}; - -/*! - @enum SecTrustSettingsResult - @abstract Result of a trust settings evaluation. -*/ -typedef CF_ENUM(uint32_t, SecTrustSettingsResult) { - kSecTrustSettingsResultInvalid = 0, /* Never valid in a Trust Settings array or - * in an API call. */ - kSecTrustSettingsResultTrustRoot, /* Root cert is explicitly trusted */ - kSecTrustSettingsResultTrustAsRoot, /* Non-root cert is explicitly trusted */ - kSecTrustSettingsResultDeny, /* Cert is explicitly distrusted */ - kSecTrustSettingsResultUnspecified /* Neither trusted nor distrusted; evaluation - * proceeds as usual */ -}; - -/* - * Specify user, local administrator, or system domain Trust Settings. - * Note that kSecTrustSettingsDomainSystem settings are read-only, even by - * root. - */ -typedef CF_ENUM(uint32_t, SecTrustSettingsDomain) { - kSecTrustSettingsDomainUser = 0, - kSecTrustSettingsDomainAdmin, - kSecTrustSettingsDomainSystem -}; - -/* - * This constant is deprecated and ineffective as of macOS 10.12. - * Please discontinue use. - */ -#define kSecTrustSettingsDefaultRootCertSetting ((SecCertificateRef)-1) - -#if SEC_OS_OSX_INCLUDES -/* - * Obtain Trust Settings for specified cert. - * Caller must CFRelease() the returned CFArray. - * Returns errSecItemNotFound if no Trust settings exist for the cert. - */ -OSStatus SecTrustSettingsCopyTrustSettings( - SecCertificateRef certRef, - SecTrustSettingsDomain domain, - CFArrayRef * __nonnull CF_RETURNS_RETAINED trustSettings); /* RETURNED */ - -/* - * Specify Trust Settings for specified cert. If specified cert - * already has Trust Settings in the specified domain, they will - * be replaced. - * The trustSettingsDictOrArray parameter is either a CFDictionary, - * a CFArray of them, or NULL. NULL indicates "always trust this - * root cert regardless of usage". - */ -OSStatus SecTrustSettingsSetTrustSettings( - SecCertificateRef certRef, - SecTrustSettingsDomain domain, - CFTypeRef __nullable trustSettingsDictOrArray); - -/* - * Delete Trust Settings for specified cert. - * Returns errSecItemNotFound if no Trust settings exist for the cert. - */ -OSStatus SecTrustSettingsRemoveTrustSettings( - SecCertificateRef certRef, - SecTrustSettingsDomain domain); - -/* - * Obtain an array of all certs which have Trust Settings in the - * specified domain. Elements in the returned certArray are - * SecCertificateRefs. - * Caller must CFRelease() the returned array. - * Returns errSecNoTrustSettings if no trust settings exist - * for the specified domain. - */ -OSStatus SecTrustSettingsCopyCertificates( - SecTrustSettingsDomain domain, - CFArrayRef * __nullable CF_RETURNS_RETAINED certArray); - -/* - * Obtain the time at which a specified cert's Trust Settings - * were last modified. Caller must CFRelease the result. - * Returns errSecItemNotFound if no Trust Settings exist for specified - * cert and domain. - */ -OSStatus SecTrustSettingsCopyModificationDate( - SecCertificateRef certRef, - SecTrustSettingsDomain domain, - CFDateRef * __nonnull CF_RETURNS_RETAINED modificationDate); /* RETURNED */ - -/* - * Obtain an external, portable representation of the specified - * domain's TrustSettings. Caller must CFRelease the returned data. - * Returns errSecNoTrustSettings if no trust settings exist - * for the specified domain. - */ -OSStatus SecTrustSettingsCreateExternalRepresentation( - SecTrustSettingsDomain domain, - CFDataRef * __nonnull CF_RETURNS_RETAINED trustSettings); - -/* - * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation, - * into the specified domain. - */ -OSStatus SecTrustSettingsImportExternalRepresentation( - SecTrustSettingsDomain domain, - CFDataRef trustSettings); - -CF_ASSUME_NONNULL_END - -#endif /* SEC_OS_OSX_INCLUDES */ - -__END_DECLS - -#endif /* _SECURITY_SECTRUSTSETTINGS_H_ */ diff --git a/trust/SecTrustSettingsPriv.h b/trust/SecTrustSettingsPriv.h deleted file mode 100644 index 62b1c9b4..00000000 --- a/trust/SecTrustSettingsPriv.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _SECURITY_SECTRUSTSETTINGSPRIV_H_ -#define _SECURITY_SECTRUSTSETTINGSPRIV_H_ - -#include - -#include -#include -#include -#include -#if SEC_OS_OSX -#include -#endif - -__BEGIN_DECLS - -/* - * Private Keys in the Usage Contraints dictionary. - * kSecTrustSettingsPolicyName Specifies a cert verification policy, e.g., - * sslServer, eapClient, etc, using policy names. - * This entry can be used to restrict the policy where - * the same Policy Constant is used for multiple policyNames. - * kSectrustSettingsPolicyOptions Specifies a dictionary of policy options (from - * SecPolicyInternal.h). This entry can be used to require - * a particular SecPolicyCheck whenever this certificate is - * encountered during trust evaluation. - */ -#define kSecTrustSettingsPolicyName CFSTR("kSecTrustSettingsPolicyName") -#define kSecTrustSettingsPolicyOptions CFSTR("kSecTrustSettingsPolicyOptions") - -extern const CFStringRef kSecCTExceptionsCAsKey; -extern const CFStringRef kSecCTExceptionsDomainsKey; -extern const CFStringRef kSecCTExceptionsHashAlgorithmKey; -extern const CFStringRef kSecCTExceptionsSPKIHashKey; - -/* - @function SecTrustStoreSetCTExceptions - @abstract Set the certificate transparency enforcement exceptions - @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the callers entitlements. - @param exceptions Dictionary of exceptions to set for this application. These exceptions replace existing exceptions for the keys in the dictionary. Exceptions for omitted keys are not affected. Null removes all exceptions for this application. See the discussion sections below for a complete overview of options. - @param error Upon failure describes cause of the failure. - @result boolean indicating success of the operation. If false, error will be filled in with a description of the error. - @discussions An exceptions dictionary has two optional keys: - kSecCTExceptionsDomainsKey takes an array of strings. These strings are the domains that are excluded from enforcing CT. A leading "." is supported to signify subdomains. Wildcard domains are not supported. - kSecCTExceptionsCAsKey takes an array of dictionaries. Each dictionary has two required keys: - kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currenlty only "sha256" is supported. - kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificates SubjectPublicKeyInfo. - */ -bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error); - -/* - @function SecTrustStoreCopyCTExceptions - @abstract Return the certificate transparency enforcement exceptions - @param applicationIdentifier Identifier for the caller's exceptions to fetch. If null, all set exceptions will be returned (regardless of which caller set them). - @param error Upon failure describes cause of the failure. - @result The dictionary of currently set exceptions. Null if none exist or upon failure. - @discussion The returned exceptions dictionary has the same options as input exceptions. See the discussion of SecTrustStoreSetCTExceptions. - */ -CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error); - -#if SEC_OS_OSX - -/* - * Fundamental routine used by TP to ascertain status of one cert. - * - * Returns true in *foundMatchingEntry if a trust setting matching - * specific constraints was found for the cert. Returns true in - * *foundAnyEntry if any entry was found for the cert, even if it - * did not match the specified constraints. The TP uses this to - * optimize for the case where a cert is being evaluated for - * one type of usage, and then later for another type. If - * foundAnyEntry is false, the second evaluation need not occur. - * - * Returns the domain in which a setting was found in *foundDomain. - * - * Allowed errors applying to the specified cert evaluation - * are returned in a mallocd array in *allowedErrors and must - * be freed by caller. - */ -OSStatus SecTrustSettingsEvaluateCert( - CFStringRef certHashStr, - /* parameters describing the current cert evalaution */ - const CSSM_OID *policyOID, - const char *policyString, /* optional */ - uint32 policyStringLen, - SecTrustSettingsKeyUsage keyUsage, /* optional */ - bool isRootCert, /* for checking default setting */ - /* RETURNED values */ - SecTrustSettingsDomain *foundDomain, - CSSM_RETURN **allowedErrors, /* mallocd and RETURNED */ - uint32 *numAllowedErrors, /* RETURNED */ - SecTrustSettingsResult *resultType, /* RETURNED */ - bool *foundMatchingEntry, /* RETURNED */ - bool *foundAnyEntry) /* RETURNED */ -DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/* - * Obtain trusted certs which match specified usage. - * Only certs with a SecTrustSettingsResult of - * kSecTrustSettingsResultTrustRoot or - * or kSecTrustSettingsResultTrustAsRoot will be returned. - * - * To be used by SecureTransport for its (hopefully soon-to-be- - * deprecated) SSLSetTrustedRoots() call; I hope nothing else has - * to use this... - * - * Caller must CFRelease the returned CFArrayRef. - */ -OSStatus SecTrustSettingsCopyQualifiedCerts( - const CSSM_OID *policyOID, - const char *policyString, /* optional */ - uint32 policyStringLen, - SecTrustSettingsKeyUsage keyUsage, /* optional */ - CFArrayRef *certArray) /* RETURNED */ -DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; - -/* - * Obtain unrestricted root certificates from the specified domain(s). - * Only returns root certificates with no usage constraints. - * Caller must CFRelease the returned CFArrayRef. - */ -OSStatus SecTrustSettingsCopyUnrestrictedRoots( - Boolean userDomain, - Boolean adminDomain, - Boolean systemDomain, - CFArrayRef *certArray); /* RETURNED */ - -/* - * Obtain a string representing a cert's SHA1 digest. This string is - * the key used to look up per-cert trust settings in a TrustSettings record. - */ -CFStringRef CF_RETURNS_RETAINED SecTrustSettingsCertHashStrFromCert( - SecCertificateRef certRef); - -CFStringRef CF_RETURNS_RETAINED SecTrustSettingsCertHashStrFromData( - const void *cert, - size_t certLen); - -/* - * Add a cert's TrustSettings to a non-persistent TrustSettings record. - * Primarily intended for use in creating a system TrustSettings record - * (which is itself immutable via this module). - * - * The settingsIn argument is an external representation of a TrustSettings - * record, obtained from this function or from - * SecTrustSettingsCreateExternalRepresentation(). - * If settingsIn is NULL, a new (empty) TrustSettings will be created. - * - * The certRef and trustSettingsDictOrArray arguments are as in - * SecTrustSettingsSetTrustSettings(). May be NULL, when e.g. creating - * a new and empty TrustSettings record. - * - * The external representation is written to the settingOut argument, - * which must eventually be CFReleased by the caller. - */ -OSStatus SecTrustSettingsSetTrustSettingsExternal( - CFDataRef settingsIn, /* optional */ - SecCertificateRef certRef, /* optional */ - CFTypeRef trustSettingsDictOrArray, /* optional */ - CFDataRef *settingsOut); /* RETURNED */ - -/* - * Add user trust settings for a SSL certificate and a given hostname. - * This is a wrapper around the SecTrustSettingsSetTrustSettings API - * and should be functionally equivalent to "Always trust" in the UI. - * - * When this function is called, the user will be prompted to authorize - * the trust settings change. After they successfully authenticate, or - * cancel the dialog, the result block will be called to indicate the - * current trust status. If an error occurred (such as errUserCanceled), - * the error reference provided to the block will be non-NULL. - */ -void SecTrustSettingsSetTrustedCertificateForSSLHost( - SecCertificateRef certificate, - CFStringRef hostname, - void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error)) - __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_NA); -#endif // SEC_OS_OSX - -#if SEC_OS_OSX_INCLUDES -/* - * Purge the cache of User and Admin Certs - */ -void SecTrustSettingsPurgeUserAdminCertsCache(void); - -/* - * A wrapper around SecTrustSettingsCopyCertificates that combines user and admin - * domain outputs. - */ -OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains( - CFArrayRef CF_RETURNS_RETAINED *certArray); -#endif /* SEC_OS_OSX_INCLUDES */ - -__END_DECLS - -#endif // _SECURITY_SECTRUSTSETTINGSPRIV_H_ diff --git a/trust/headers/SecCertificate.h b/trust/headers/SecCertificate.h new file mode 100644 index 00000000..fcadd01d --- /dev/null +++ b/trust/headers/SecCertificate.h @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecCertificate + The functions provided in SecCertificate.h implement and manage a + particular type of keychain item that represents a X.509 public key + certificate. You can store a certificate in a keychain, but a + certificate can also be a transient object. + + You can use a certificate as a keychain item in most functions. +*/ + +#ifndef _SECURITY_SECCERTIFICATE_H_ +#define _SECURITY_SECCERTIFICATE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if SEC_OS_OSX +#define _SECURITY_VERSION_GREATER_THAN_57610_ + +#include +#include +#endif // SEC_OS_OSX + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @function SecCertificateGetTypeID + @abstract Returns the type identifier of SecCertificate instances. + @result The CFTypeID of SecCertificate instances. + */ +CFTypeID SecCertificateGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecCertificateCreateWithData + @abstract Create a certificate given it's DER representation as a CFData. + @param allocator CFAllocator to allocate the certificate with. + @param data DER encoded X.509 certificate. + @result Return NULL if the passed-in data is not a valid DER-encoded + X.509 certificate, return a SecCertificateRef otherwise. + */ +__nullable +SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef __nullable allocator, CFDataRef data) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecCertificateCopyData + @abstract Return the DER representation of an X.509 certificate. + @param certificate SecCertificate object created with + SecCertificateCreateWithData(). + @result DER encoded X.509 certificate. + */ +CFDataRef SecCertificateCopyData(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecCertificateCopySubjectSummary + @abstract Return a simple string which hopefully represents a human + understandable summary. + @param certificate A reference to the certificate from which to derive + the subject summary string. + @discussion All the data in this string comes from the certificate itself + and thus it's in whatever language the certificate itself is in. + @result A CFStringRef which the caller should CFRelease() once it's no + longer needed. + */ +__nullable +CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecCertificateCopyCommonName + @abstract Retrieves the common name of the subject of a given certificate. + @param certificate A reference to the certificate from which to retrieve the common name. + @param commonName On return, a reference to the common name. Your code must release this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion All the data in this string comes from the certificate itself, and thus it's in whatever language the certificate itself is in. + Note that the certificate's common name field may not be present, or may be inadequate to describe the certificate; for display purposes, + you should consider using SecCertificateCopySubjectSummary instead of this function. + */ +OSStatus SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef * __nonnull CF_RETURNS_RETAINED commonName) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_10_3); + +/*! + @function SecCertificateCopyEmailAddresses + @abstract Returns an array of zero or more email addresses for the subject of a given certificate. + @param certificate A reference to the certificate from which to retrieve the email addresses. + @param emailAddresses On return, an array of zero or more CFStringRef elements corresponding to each email address found. + Your code must release this array reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef * __nonnull CF_RETURNS_RETAINED emailAddresses) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_10_3); + +/*! + @function SecCertificateCopyNormalizedIssuerSequence + @abstract Return the certificate's normalized issuer + @param certificate The certificate from which to get values + @discussion The issuer is a sequence in the format used by SecItemCopyMatching. The content returned is a DER-encoded X.509 distinguished name. For a display version of the issuer, call SecCertificateCopyValues. The caller must CFRelease the value returned. + */ +__nullable +CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12_4, __IPHONE_10_3); + +/*! + @function SecCertificateCopyNormalizedSubjectSequence + @abstract Return the certificate's normalized subject + @param certificate The certificate from which to get values + @discussion The subject is a sequence in the format used by SecItemCopyMatching. The content returned is a DER-encoded X.509 distinguished name. For a display version of the subject, call SecCertificateCopyValues. The caller must CFRelease the value returned. + */ +__nullable +CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12_4, __IPHONE_10_3); + +/*! + @function SecCertificateCopyKey + @abstract Retrieves the public key for a given certificate. + @param certificate A reference to the certificate from which to retrieve the public key. + @result A reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. If the public key has an encoding issue or uses an unsupported algorithm, the returned reference will be null. + @discussion RSA and ECDSA public keys are supported. All other public key algorithms are unsupported. + */ +__nullable CF_RETURNS_RETAINED +SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate) + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); + +#if TARGET_OS_IPHONE +/*! + @function SecCertificateCopyPublicKey + @abstract Retrieves the public key for a given certificate. + @param certificate A reference to the certificate from which to retrieve the public key. + @result A reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. + @discussion NOTE: Deprecated in iOS 12.0; use SecCertificateCopyKey instead for cross-platform availability. + */ +__nullable +SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate) + API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", ios(10.3, 12.0)) API_UNAVAILABLE(macos, iosmac); +#endif + +#if TARGET_OS_OSX +/*! + @function SecCertificateCopyPublicKey + @abstract Retrieves the public key for a given certificate. + @param certificate A reference to the certificate from which to retrieve the public key. + @param key On return, a reference to the public key for the specified certificate. Your code must release this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion NOTE: Deprecated in macOS 10.14; use SecCertificateCopyKey instead for cross-platform availability. + */ +OSStatus SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef * __nonnull CF_RETURNS_RETAINED key) + API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", macos(10.3, 10.14)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); +#endif + +/*! + @function SecCertificateCopySerialNumberData + @abstract Return the certificate's serial number. + @param certificate The certificate from which to get values. + @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. + */ +__nullable +CFDataRef SecCertificateCopySerialNumberData(SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +#if TARGET_OS_IPHONE +/*! + @function SecCertificateCopySerialNumber + @abstract Return the certificate's serial number. + @param certificate The certificate from which to get values. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in iOS 11.0; use SecCertificateCopySerialNumberData instead for cross-platform availability. + */ +__nullable +CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate) + API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", ios(10.3, 11.0)) API_UNAVAILABLE(macos, iosmac); +#endif + +#if TARGET_OS_OSX +/*! + @function SecCertificateCopySerialNumber + @abstract Return the certificate's serial number. + @param certificate The certificate from which to get values. + @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in macOS 10.13; use SecCertificateCopySerialNumberData instead for cross-platform availability. + */ +__nullable +CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) + API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", macos(10.7, 10.13)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac); +#endif + +/* + * Legacy functions (OS X only) + */ +#if SEC_OS_OSX +/*! + @enum CertificateItemAttributes + @abstract Indicates the type of a certificate item attribute. + @constant kSecSubjectItemAttr Indicates a DER-encoded subject distinguished name. + @constant kSecIssuerItemAttr Indicates a DER-encoded issuer distinguished name. + @constant kSecSerialNumberItemAttr Indicates a DER-encoded certificate serial number (without the tag and length). + @constant kSecPublicKeyHashItemAttr Indicates a public key hash. + @constant kSecSubjectKeyIdentifierItemAttr Indicates a subject key identifier. + @constant kSecCertTypeItemAttr Indicates a certificate type. + @constant kSecCertEncodingItemAttr Indicates a certificate encoding. +*/ +enum +{ + kSecSubjectItemAttr = 'subj', + kSecIssuerItemAttr = 'issu', + kSecSerialNumberItemAttr = 'snbr', + kSecPublicKeyHashItemAttr = 'hpky', + kSecSubjectKeyIdentifierItemAttr = 'skid', + kSecCertTypeItemAttr = 'ctyp', + kSecCertEncodingItemAttr = 'cenc' +} /*DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER*/; + +#pragma mark ---- Certificate Operations ---- + +/*! + @function SecCertificateCreateFromData + @abstract Creates a certificate based on the input data, type, and encoding. + @param data A pointer to the certificate data. + @param type The certificate type as defined in cssmtype.h. + @param encoding The certificate encoding as defined in cssmtype.h. + @param certificate On return, a reference to the newly created certificate. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7 Please use the SecCertificateCreateWithData API instead. +*/ +OSStatus SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificate) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateAddToKeychain + @abstract Adds a certificate to the specified keychain. + @param certificate A reference to a certificate. + @param keychain A reference to the keychain in which to add the certificate. Pass NULL to add the certificate to the default keychain. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is successful only if the certificate was created using the SecCertificateCreateFromData or + SecCertificateCreateWithData functions, and the certificate has not yet been added to the specified keychain. +*/ +OSStatus SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef __nullable keychain) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); + +/*! + @function SecCertificateGetData + @abstract Retrieves the data for a given certificate. + @param certificate A reference to the certificate from which to retrieve the data. + @param data On return, the CSSM_DATA structure pointed to by data is filled in. You must allocate the space for a CSSM_DATA structure before calling this function. This data pointer is only guaranteed to remain valid as long as the certificate remains unchanged and valid. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyData API instead. +*/ +OSStatus SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateGetType + @abstract Retrieves the type for a given certificate. + @param certificate A reference to the certificate from which to obtain the type. + @param certificateType On return, the certificate type of the certificate. Certificate types are defined in cssmtype.h. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. +*/ +OSStatus SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateGetSubject + @abstract Retrieves the subject name for a given certificate. + @param certificate A reference to the certificate from which to obtain the subject name. + @param subject On return, a pointer to a CSSM_X509_NAME struct which contains the subject's X.509 name (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Prior to Mac OS X 10.5, this function did not return any output in the subject parameter. Your code should check the returned pointer value (in addition to the function result) before attempting to use it. + For example: + const CSSM_X509_NAME *subject = NULL; + OSStatus status = SecCertificateGetSubject(certificate, &subject); + if ( (status == errSecSuccess) && (subject != NULL) ) { + // subject is valid + } + This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. +*/ +OSStatus SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME * __nullable * __nonnull subject) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateGetIssuer + @abstract Retrieves the issuer name for a given certificate. + @param certificate A reference to the certificate from which to obtain the issuer name. + @param issuer On return, a pointer to a CSSM_X509_NAME struct which contains the issuer's X.509 name (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Prior to Mac OS X 10.5, this function did not return any output in the issuer parameter. Your code should check the returned pointer value (in addition to the function result) before attempting to use it. + For example: + const CSSM_X509_NAME *issuer = NULL; + OSStatus status = SecCertificateGetIssuer(certificate, &issuer); + if ( (status == errSecSuccess) && (issuer != NULL) ) { + // issuer is valid + } + This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. +*/ +OSStatus SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME * __nullable * __nonnull issuer) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateGetCLHandle + @abstract Retrieves the certificate library handle for a given certificate. + @param certificate A reference to the certificate from which to obtain the certificate library handle. + @param clHandle On return, the certificate library handle of the given certificate. This handle remains valid at least as long as the certificate does. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. +*/ +OSStatus SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateGetAlgorithmID + @abstract Retrieves the algorithm identifier for a given certificate. + @param certificate A reference to the certificate from which to retrieve the algorithm identifier. + @param algid On return, a pointer to a CSSM_X509_ALGORITHM_IDENTIFIER struct which identifies the algorithm for this certificate (x509defs.h). This pointer remains valid until the certificate reference is released. The caller should not attempt to free this pointer. + @result A result code. See "Security Error Codes" (SecBase.h). + discussion This API is deprecated in 10.7. Please use the SecCertificateCopyValues API instead. +*/ +OSStatus SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER * __nullable * __nonnull algid) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateCopyPreference + @abstract Returns the preferred certificate for the specified name and key usage. If a preferred certificate does not exist for the specified name and key usage, NULL is returned. + @param name A string containing an email address (RFC822) or other name for which a preferred certificate is requested. + @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to ignore this parameter. + @param certificate On return, a reference to the preferred certificate, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will typically be used to obtain the preferred encryption certificate for an email recipient. + This API is deprecated in 10.7. Please use the SecCertificateCopyPreferred API instead. +*/ +OSStatus SecCertificateCopyPreference(CFStringRef name, uint32 keyUsage, SecCertificateRef * __nonnull CF_RETURNS_RETAINED certificate) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateCopyPreferred + @abstract Returns the preferred certificate for the specified name and key usage. If a preferred certificate does not exist for the specified name and key usage, NULL is returned. + @param name A string containing an email address (RFC822) or other name for which a preferred certificate is requested. + @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) + @result On return, a reference to the preferred certificate, or NULL if none was found. You are responsible for releasing this reference by calling the CFRelease function. + @discussion This function will typically be used to obtain the preferred encryption certificate for an email recipient. If a preferred certificate has not been set + for the supplied name, the returned reference will be NULL. Your code should then perform a search for possible certificates, using the SecItemCopyMatching API. + */ +__nullable +SecCertificateRef SecCertificateCopyPreferred(CFStringRef name, CFArrayRef __nullable keyUsage) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecCertificateSetPreference + @abstract Sets the preferred certificate for a specified name, key usage, and date. + @param certificate A reference to the certificate which will be preferred. + @param name A string containing an email address (RFC822) or other name for which a preferred certificate will be associated. + @param keyUsage A CSSM_KEYUSE key usage value, as defined in cssmtype.h. Pass 0 to avoid specifying a particular key usage. + @param date (optional) A date reference. If supplied, the preferred certificate will be changed only if this date is later than the currently saved setting. Pass NULL if this preference should not be restricted by date. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will typically be used to set the preferred encryption certificate for an email recipient, either manually (when encrypting email to a recipient) or automatically upon receipt of encrypted email. + This API is deprecated in 10.7. Plese use the SecCertificateSetPreferred API instead. +*/ +OSStatus SecCertificateSetPreference(SecCertificateRef certificate, CFStringRef name, uint32 keyUsage, CFDateRef __nullable date) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/*! + @function SecCertificateSetPreferred + @abstract Sets the preferred certificate for a specified name and optional key usage. + @param certificate A reference to the preferred certificate. If NULL is passed, any existing preference for the specified name is cleared instead. + @param name A string containing an email address (RFC822) or other name for which a preferred certificate will be associated. + @param keyUsage A CFArrayRef value, containing items defined in SecItem.h Pass NULL to ignore this parameter. (kSecAttrCanEncrypt, kSecAttrCanDecrypt, kSecAttrCanDerive, kSecAttrCanSign, kSecAttrCanVerify, kSecAttrCanWrap, kSecAttrCanUnwrap) + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will typically be used to set the preferred encryption certificate for an email recipient, either manually (when encrypting email to a recipient) + or automatically upon receipt of encrypted email. +*/ +OSStatus SecCertificateSetPreferred(SecCertificateRef __nullable certificate, CFStringRef name, CFArrayRef __nullable keyUsage) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @typedef SecKeyUsage + @abstract Flags to indicate key usages in the KeyUsage extension of a certificate + @constant kSecKeyUsageUnspecified No KeyUsage extension in certificate. + @constant kSecKeyUsageDigitalSignature DigitalSignature bit set in KeyUsage extension. + @constant kSecKeyUsageNonRepudiation NonRepudiation bit set in KeyUsage extension. + @constant kSecKeyUsageContentCommitment ContentCommitment bit set in KeyUsage extension. + @constant kSecKeyUsageKeyEncipherment KeyEncipherment bit set in KeyUsage extension. + @constant kSecKeyUsageDataEncipherment DataEncipherment bit set in KeyUsage extension. + @constant kSecKeyUsageKeyAgreement KeyAgreement bit set in KeyUsage extension. + @constant kSecKeyUsageKeyCertSign KeyCertSign bit set in KeyUsage extension. + @constant kSecKeyUsageCRLSign CRLSign bit set in KeyUsage extension. + @constant kSecKeyUsageEncipherOnly EncipherOnly bit set in KeyUsage extension. + @constant kSecKeyUsageDecipherOnly DecipherOnly bit set in KeyUsage extension. + @constant kSecKeyUsageCritical KeyUsage extension is marked critical. + @constant kSecKeyUsageAll For masking purposes, all SecKeyUsage values. + */ +typedef CF_OPTIONS(uint32_t, SecKeyUsage) { + kSecKeyUsageUnspecified = 0u, + kSecKeyUsageDigitalSignature = 1u << 0, + kSecKeyUsageNonRepudiation = 1u << 1, + kSecKeyUsageContentCommitment= 1u << 1, + kSecKeyUsageKeyEncipherment = 1u << 2, + kSecKeyUsageDataEncipherment = 1u << 3, + kSecKeyUsageKeyAgreement = 1u << 4, + kSecKeyUsageKeyCertSign = 1u << 5, + kSecKeyUsageCRLSign = 1u << 6, + kSecKeyUsageEncipherOnly = 1u << 7, + kSecKeyUsageDecipherOnly = 1u << 8, + kSecKeyUsageCritical = 1u << 31, + kSecKeyUsageAll = 0x7FFFFFFFu +}; + +/*! + @enum kSecPropertyKey + @abstract Constants used to access dictionary entries returned by SecCertificateCopyValues + @constant kSecPropertyKeyType The type of the entry + @constant kSecPropertyKeyLabel The label of the entry + @constant kSecPropertyKeyLocalizedLabel The localized label of the entry + @constant kSecPropertyKeyValue The value of the entry + */ + +extern const CFStringRef kSecPropertyKeyType __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyKeyLabel __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyKeyLocalizedLabel __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyKeyValue __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @enum kSecPropertyType + @abstract Public Constants for property list values returned by SecCertificateCopyValues + @discussion Note that kSecPropertyTypeTitle and kSecPropertyTypeError are defined in SecTrust.h +*/ +extern const CFStringRef kSecPropertyTypeWarning __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeSuccess __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeSection __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeData __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeString __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeURL __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeDate __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPropertyTypeArray API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0)); +extern const CFStringRef kSecPropertyTypeNumber API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0)); + +/*! + @function SecCertificateCopyValues + @abstract Creates a dictionary that represents a certificate's contents. + @param certificate The certificate from which to get values + @param keys An array of string OID values, or NULL. If present, this is + the subset of values from the certificate to return. If NULL, + all values will be returned. Only OIDs that are top level keys + in the returned dictionary can be specified. Unknown OIDs are + ignored. + @param error An optional pointer to a CFErrorRef. This value is + set if an error occurred. If not NULL the caller is + responsible for releasing the CFErrorRef. + @discussion The keys array will contain all of the keys used in the + returned dictionary. The top level keys in the returned + dictionary are OIDs, many of which are found in SecCertificateOIDs.h. + Each entry that is returned is itself a dictionary with four + entries, whose keys are kSecPropertyKeyType, kSecPropertyKeyLabel, + kSecPropertyKeyLocalizedLabel, kSecPropertyKeyValue. The label + entries may contain a descriptive (localized) string, or an + OID string. The kSecPropertyKeyType describes the type in the + value entry. The value entry may be any CFType, although it + is usually a CFStringRef, CFArrayRef or a CFDictionaryRef. +*/ +__nullable +CFDictionaryRef SecCertificateCopyValues(SecCertificateRef certificate, CFArrayRef __nullable keys, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecCertificateCopyLongDescription + @abstract Return the long description of a certificate + @param alloc The CFAllocator which should be used to allocate + memory for the dictionary and its storage for values. This + parameter may be NULL in which case the current default + CFAllocator is used. If this reference is not a valid + CFAllocator, the behavior is undefined. + @param certificate The certificate from which to retrieve the long description + @param error An optional pointer to a CFErrorRef. This value is + set if an error occurred. If not NULL the caller is + responsible for releasing the CFErrorRef. + @result A CFStringRef of the long description or NULL. If NULL and the error + parameter is supplied the error will be returned in the error parameter + @discussion Note that the format of this string may change in the future +*/ + +__nullable +CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef __nullable alloc, SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecCertificateCopyShortDescription + @abstract Return the short description of a certificate + @param alloc The CFAllocator which should be used to allocate + memory for the dictionary and its storage for values. This + parameter may be NULL in which case the current default + CFAllocator is used. If this reference is not a valid + CFAllocator, the behavior is undefined. + @param certificate The certificate from which to retrieve the short description + @param error An optional pointer to a CFErrorRef. This value is + set if an error occurred. If not NULL the caller is + responsible for releasing the CFErrorRef. + @result A CFStringRef of the short description or NULL. If NULL and the error + parameter is supplied the error will be returned in the error parameter + @discussion Note that the format of this string may change in the future +*/ + +__nullable +CFStringRef SecCertificateCopyShortDescription(CFAllocatorRef __nullable alloc, SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecCertificateCopyNormalizedIssuerContent + @abstract Return the certificate's normalized issuer + @param certificate The certificate from which to get values + @param error An optional pointer to a CFErrorRef. This value is + set if an error occurred. If not NULL the caller is + responsible for releasing the CFErrorRef. + @discussion The issuer is a sequence in the format used by + SecItemCopyMatching. The content returned is a DER-encoded + X.509 distinguished name. For a display version of the issuer, + call SecCertificateCopyValues. The caller must CFRelease + the value returned. +*/ + +__nullable +CFDataRef SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyNormalizedIssuerContent is deprecated. Use SecCertificateCopyNormalizedIssuerSequence instead."); + +/*! + @function SecCertificateCopyNormalizedSubjectContent + @abstract Return the certificate's normalized subject + @param certificate The certificate from which to get values + @param error An optional pointer to a CFErrorRef. This value is + set if an error occurred. If not NULL the caller is + responsible for releasing the CFErrorRef. + @discussion The subject is a sequence in the format used by + SecItemCopyMatching. The content returned is a DER-encoded + X.509 distinguished name. For a display version of the subject, + call SecCertificateCopyValues. The caller must CFRelease + the value returned. +*/ + +__nullable +CFDataRef SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyNormalizedSubjectContent is deprecated. Use SecCertificateCopyNormalizedSubjectSequence instead."); + + +#endif /* SEC_OS_OSX */ + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECCERTIFICATE_H_ */ diff --git a/trust/headers/SecCertificatePriv.h b/trust/headers/SecCertificatePriv.h new file mode 100644 index 00000000..086f48ac --- /dev/null +++ b/trust/headers/SecCertificatePriv.h @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2002-2004,2006-2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecCertificatePriv + The functions provided in SecCertificatePriv.h implement and manage a particular + type of keychain item that represents a certificate. You can store a + certificate in a keychain, but a certificate can also be a transient + object. + + You can use a certificate as a keychain item in most functions. + Certificates are able to compute their parent certificates, and much more. +*/ + +#ifndef _SECURITY_SECCERTIFICATEPRIV_H_ +#define _SECURITY_SECCERTIFICATEPRIV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +__BEGIN_DECLS + +#if SEC_OS_IPHONE +typedef CF_OPTIONS(uint32_t, SecKeyUsage) { + kSecKeyUsageUnspecified = 0u, + kSecKeyUsageDigitalSignature = 1u << 0, + kSecKeyUsageNonRepudiation = 1u << 1, + kSecKeyUsageContentCommitment= 1u << 1, + kSecKeyUsageKeyEncipherment = 1u << 2, + kSecKeyUsageDataEncipherment = 1u << 3, + kSecKeyUsageKeyAgreement = 1u << 4, + kSecKeyUsageKeyCertSign = 1u << 5, + kSecKeyUsageCRLSign = 1u << 6, + kSecKeyUsageEncipherOnly = 1u << 7, + kSecKeyUsageDecipherOnly = 1u << 8, + kSecKeyUsageCritical = 1u << 31, + kSecKeyUsageAll = 0x7FFFFFFFu +}; +#endif /* SEC_OS_IPHONE */ + +typedef CF_ENUM(uint32_t, SecCertificateEscrowRootType) { + kSecCertificateBaselineEscrowRoot = 0, + kSecCertificateProductionEscrowRoot = 1, + kSecCertificateBaselinePCSEscrowRoot = 2, + kSecCertificateProductionPCSEscrowRoot = 3, + kSecCertificateBaselineEscrowBackupRoot = 4, // v100 and v101 + kSecCertificateProductionEscrowBackupRoot = 5, + kSecCertificateBaselineEscrowEnrollmentRoot = 6, // v101 only + kSecCertificateProductionEscrowEnrollmentRoot = 7, +}; + +/* The names of the files that contain the escrow certificates */ +extern const CFStringRef kSecCertificateProductionEscrowKey; +extern const CFStringRef kSecCertificateProductionPCSEscrowKey; +extern const CFStringRef kSecCertificateEscrowFileName; + +/* Return a certificate for the DER representation of this certificate. + Return NULL if the passed-in data is not a valid DER-encoded X.509 + certificate. */ +SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, + const UInt8 *bytes, CFIndex length) +__SEC_MAC_AND_IOS_UNKNOWN; +//__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_UNKNOWN); + +/* Returns a certificate from a pem blob. + Return NULL if the passed-in data is not a valid DER-encoded X.509 + certificate. */ +SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator, CFDataRef pem_certificate) +__SEC_MAC_AND_IOS_UNKNOWN; +//__OSX_AVAILABLE_STARTING(__MAC_10_12, __SEC_IPHONE_UNKNOWN); + +/* Return the length of the DER representation of this certificate. */ +CFIndex SecCertificateGetLength(SecCertificateRef certificate); + +/* Return the bytes of the DER representation of this certificate. */ +const UInt8 *SecCertificateGetBytePtr(SecCertificateRef certificate); + +/* Return the SHA-1 hash of this certificate. */ +CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the SHA-256 hash of this certificate. */ +CFDataRef SecCertificateCopySHA256Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the SHA-1 hash of the public key in this certificate. */ +CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the SHA-1 hash of the SubjectPublicKeyInfo sequence in this certificate. */ +CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the SHA-256 hash of the SubjectPublicKeyInfo sequence in this certificate. */ +CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return an array of CFStringRefs representing the dns addresses in the + certificate if any. */ +CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return an array of CFStringRefs representing the NTPrincipalNames in the + certificate if any. */ +CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Create a unified SecCertificateRef from a legacy keychain item and its data. */ +SecCertificateRef SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator, + CFDataRef der_certificate, CFTypeRef keychainItem) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Set a legacy item instance for a unified SecCertificateRef. */ +OSStatus SecCertificateSetKeychainItem(SecCertificateRef certificate, CFTypeRef keychain_item) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return a keychain item reference, given a unified SecCertificateRef. + Note: On OSX, for this function to succeed, the provided certificate must have been + created by SecCertificateCreateWithKeychainItem, otherwise NULL is returned. + */ +CFTypeRef SecCertificateCopyKeychainItem(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/*! + @function SecCertificateCopyIssuerSummary + @abstract Return a simple string which hopefully represents a human understandable issuer. + @param certificate SecCertificate object created with SecCertificateCreateWithData(). + @discussion All the data in this string comes from the certificate itself + and thus it's in whatever language the certificate itself is in. + @result A CFStringRef which the caller should CFRelease() once it's no longer needed. + */ +CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate); + +/* Return a string formatted according to RFC 2253 representing the complete + subject of certificate. */ +CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate); + +CFMutableArrayRef SecCertificateCopySummaryProperties( + SecCertificateRef certificate, CFAbsoluteTime verifyTime) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the content of a DER encoded X.501 name (without the tag and length + fields) for the receiving certificates issuer. */ +CFDataRef SecCertificateGetNormalizedIssuerContent(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the content of a DER encoded X.501 name (without the tag and length + fields) for the receiving certificates subject. */ +CFDataRef SecCertificateGetNormalizedSubjectContent(SecCertificateRef certificate) + __SEC_MAC_AND_IOS_UNKNOWN; + +/* Return the DER encoded issuer sequence for the certificate's issuer. */ +CFDataRef SecCertificateCopyIssuerSequence(SecCertificateRef certificate); + +/* Return the DER encoded subject sequence for the certificate's subject. */ +CFDataRef SecCertificateCopySubjectSequence(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the ip addresses in the + certificate if any. */ +CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the email addresses in the + certificate if any. */ +CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the common names in the + certificates subject if any. */ +CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the organization in the + certificate's subject if any. */ +CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the organizational unit in the + certificate's subject if any. */ +CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate); + +/* Return an array of CFStringRefs representing the country in the + certificate's subject if any. */ +CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate); + +/* Return a string with the company name of an ev leaf certificate. */ +CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate); + +/* X.509 Certificate Version: 1, 2 or 3. */ +CFIndex SecCertificateVersion(SecCertificateRef certificate); + +SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate); + +/* Returns an array of CFDataRefs for all extended key usage oids or NULL */ +CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate); + +/*! + @function SecCertificateIsValid + @abstract Check certificate validity on a given date. + @param certificate A certificate reference. + @result Returns true if the specified date falls within the certificate's validity period, false otherwise. + */ +bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); + +/*! + @function SecCertificateNotValidBefore + @abstract Obtain the starting date of the given certificate. + @param certificate A certificate reference. + @result Returns the absolute time at which the given certificate becomes valid, + or 0 if this value could not be obtained. + */ +CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); + +/*! + @function SecCertificateNotValidAfter + @abstract Obtain the expiration date of the given certificate. + @param certificate A certificate reference. + @result Returns the absolute time at which the given certificate expires, + or 0 if this value could not be obtained. + */ +CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_2_0); + +/*! + @function SecCertificateIsSelfSigned + @abstract Determine if the given certificate is self-signed. + @param certRef A certificate reference. + @param isSelfSigned Will be set to true on return if the certificate is self-signed, false otherwise. + @result A result code. Returns errSecSuccess if the certificate's status can be determined. + */ +OSStatus SecCertificateIsSelfSigned(SecCertificateRef certRef, Boolean *isSelfSigned) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_9_0); + +/*! + @function SecCertificateIsSelfSignedCA + @abstract Determine if the given certificate is self-signed and has a basic + constraints extension indicating it is a certificate authority. + @param certificate A certificate reference. + @result Returns true if the certificate is self-signed and has a basic + constraints extension indicating it is a certificate authority, otherwise false. + */ +bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); + +/*! + @function SecCertificateIsCA + @abstract Determine if the given certificate has a basic + constraints extension indicating it is a certificate authority. + @param certificate A certificate reference. + @result Returns true if the certificate has a basic constraints + extension indicating it is a certificate authority, otherwise false. + */ +bool SecCertificateIsCA(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); + + +/* Append certificate to xpc_certificates. */ +bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error); + +/* Decode certificate from xpc_certificates[index] as encoded by SecCertificateAppendToXPCArray(). */ +SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error); + +/* Return an xpc_array of data from an array of SecCertificateRefs. */ +xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error); + +/* Return an array of SecCertificateRefs from a xpc_object array of datas. */ +CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error); + +/*! + @function SecCertificateCopyEscrowRoots + @abstract Retrieve the array of valid escrow certificates for a given root type. + @param escrowRootType An enumerated type indicating which root type to return. + @result An array of zero or more escrow certificates matching the provided type. + */ +CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/* Return an attribute dictionary used to store this item in a keychain. */ +CFDictionaryRef SecCertificateCopyAttributeDictionary(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/* + * Enumerated constants for signature hash algorithms. + */ +typedef CF_ENUM(uint32_t, SecSignatureHashAlgorithm){ + kSecSignatureHashAlgorithmUnknown = 0, + kSecSignatureHashAlgorithmMD2 = 1, + kSecSignatureHashAlgorithmMD4 = 2, + kSecSignatureHashAlgorithmMD5 = 3, + kSecSignatureHashAlgorithmSHA1 = 4, + kSecSignatureHashAlgorithmSHA224 = 5, + kSecSignatureHashAlgorithmSHA256 = 6, + kSecSignatureHashAlgorithmSHA384 = 7, + kSecSignatureHashAlgorithmSHA512 = 8 +}; + +/*! + @function SecCertificateGetSignatureHashAlgorithm + @abstract Determine the hash algorithm used in a certificate's signature. + @param certificate A certificate reference. + @result Returns an enumerated value indicating the signature hash algorithm + used in a certificate. If the hash algorithm is unsupported or cannot be + obtained (e.g. because the supplied certificate reference is invalid), a + value of 0 (kSecSignatureHashAlgorithmUnknown) is returned. + */ +SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @function SecCertificateCopyProperties + @abstract Return a property array for this certificate. + @param certificate A reference to the certificate to evaluate. + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. + See SecTrustCopySummaryPropertiesAtIndex on how to interpret this array. + Unlike that function, this function returns a detailed description of the + certificate. Note that localized description strings are returned by default. + Use SecCertificateCopyLocalizedProperties if your code needs to explicitly + specify whether the strings are localized. + */ +CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate); + +/*! + @function SecCertificateCopyLocalizedProperties + @abstract Return a property array for this certificate. + @param certificate A reference to the certificate to evaluate. + @param localized A value which specifies whether string properties + are localized. If false, description strings will not be localized. + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. + See SecTrustCopySummaryPropertiesAtIndex on how to interpret this array. + Unlike that function, this function returns a detailed description of the + certificate. + */ +CFArrayRef SecCertificateCopyLocalizedProperties(SecCertificateRef certificate, Boolean localized) + API_AVAILABLE(macos(10.15.1), ios(13.2), watchos(6.1), tvos(13.1)); + +/* Returns an array of CFDataRefs for all embedded SCTs */ +CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); + +/* Return the precert TBSCertificate DER data - used for Certificate Transparency */ +CFDataRef SecCertificateCopyPrecertTBS(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); + +/* Returns a dictionary of dictionaries for system-trusted CT logs, indexed by the LogID */ +CFDictionaryRef SecCertificateCopyTrustedCTLogs(void) + __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_13_0); + +/* Returns a dictionary for the CT log matching the provided + * key ID, or NULL if no matching log is found. + * And by keyID we mean LogID as specified in RFC 6962. + */ +CFDictionaryRef SecCertificateCopyCTLogForKeyID(CFDataRef keyID) + __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_13_0); + +/* Return the auth capabilities bitmask from the iAP marker extension */ +CF_RETURNS_RETAINED CFDataRef SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +typedef CF_ENUM(uint32_t, SeciAuthVersion) { + kSeciAuthInvalid = 0, + kSeciAuthVersion1 = 1, /* unused */ + kSeciAuthVersion2 = 2, + kSeciAuthVersion3 = 3, + kSeciAuthVersionSW = 4, +} __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/* Return the iAuth version indicated by the certificate. This function does + * not guarantee that the certificate is valid, so the caller must still call + * SecTrustEvaluate to guarantee that the certificate was properly issued */ +SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/* Return the normalized name or NULL if it fails to parse */ +CFDataRef SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* Returns the Subject Key ID extension from the certificate or NULL if none */ +CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* Returns an array of SecCertificateRefs containing the iPhone Device CA and + * its parent certificates. This interface is meant as a workaround and should + * not be used without consulting the Security team. */ +CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +typedef CF_ENUM(uint32_t, SeciAPSWAuthCapabilitiesType) { + kSeciAPSWAuthGeneralCapabilities = 0, + kSeciAPSWAuthAirPlayCapabilities = 1, + kSeciAPSWAuthHomeKitCapabilities = 2, +} __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); + +/* Return the iAP SW Auth capabilities bitmask from the specificed + * SeciAPSWAuthCapabilitiesType type marker extensions. */ +CF_RETURNS_RETAINED +CFDataRef SecCertificateCopyiAPSWAuthCapabilities(SecCertificateRef certificate, + SeciAPSWAuthCapabilitiesType type) + __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); + +/*! + @function SecCertificateCopyExtensionValue + @abstract Return the value in an extension of a certificate. + @param certificate A reference to the certificate containing the desired extension + @param extensionOID A CFData containing the binary value of ObjectIdentifier of the + desired extension or a CFString containing the decimal value of the ObjectIdentifier. + @param isCritical On return, a boolean value representing whether the extension was critical. + @result If an extension exists in the certificate with the extensionOID, the returned CFData + is the (unparsed) Value of the extension. + @discussion If the certificate has multiple extensions with the same extension OID, the first + extension with the input OID is returned. + */ +CF_RETURNS_RETAINED +CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, + CFTypeRef extensionOID, bool *isCritical) + __OSX_AVAILABLE_STARTING(__MAC_10_13_4, __IPHONE_11_3); + +/* Return an array of CFURLRefs each of which is an ocspResponder for this + certificate. */ +CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + + +/* Return the component type string in a component certificate. */ +CF_RETURNS_RETAINED +CFStringRef SecCertificateCopyComponentType(SecCertificateRef certificate) + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + +bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate, CFAbsoluteTime *time, CFErrorRef * CF_RETURNS_RETAINED error); + +CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, const uint8_t *bytes, size_t length, CFErrorRef *error); + +/* + * Legacy functions (OS X only) + */ +#if SEC_OS_OSX +#include +#include + +/* Given a unified SecCertificateRef, return a copy with a legacy + C++ ItemImpl-based Certificate instance. Only for internal use; + legacy references cannot be used by SecCertificate API functions. */ +SecCertificateRef SecCertificateCreateItemImplInstance(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); + +/* Inverse of above; convert legacy Certificate instance to new ref. */ +SecCertificateRef SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); + + +/* Convenience function to determine type of certificate instance. */ +Boolean SecCertificateIsItemImplInstance(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); + +/* Given a legacy C++ ItemImpl-based Certificate instance obtained with + SecCertificateCreateItemImplInstance, return its clHandle pointer. + Only for internal use. */ +OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); + +/* Deprecated; use SecCertificateCopyCommonName() instead. */ +OSStatus SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_5, __IPHONE_NA, __IPHONE_NA, "SecCertificateGetCommonName is deprecated. Use SecCertificateCopyCommonName instead."); + +/* Deprecated; use SecCertificateCopyEmailAddresses() instead. */ +/* This should have been Copy instead of Get since the returned address is not autoreleased. */ +OSStatus SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_5, __IPHONE_NA, __IPHONE_NA, "SecCertificateGetEmailAddress is deprecated. Use SecCertificateCopyEmailAddresses instead."); + +/* + * Private API to infer a display name for a SecCertificateRef which + * may or may not be in a keychain. + */ +OSStatus SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label); + +/* + * Subset of the above, useful for both certs and CRLs. + * Infer printable label for a given an CSSM_X509_NAME. Returns NULL + * if no appropriate printable name found. + */ +const CSSM_DATA *SecInferLabelFromX509Name( + const CSSM_X509_NAME *x509Name) + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/* Accessors for fields in the cached certificate */ + +/*! + @function SecCertificateCopyFieldValues + @abstract Retrieves the values for a particular field in a given certificate. + @param certificate A valid SecCertificateRef to the certificate. + @param field Pointer to the OID whose values should be returned. + @param fieldValues On return, a zero terminated list of CSSM_DATA_PTR's. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Return a zero terminated list of CSSM_DATA_PTR's with the + values of the field specified by field. Caller must call + SecCertificateReleaseFieldValues to free the storage allocated by this call. +*/ +OSStatus SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyFieldValues is deprecated. Use SecCertificateCopyValues instead."); + +/*! + @function SecCertificateReleaseFieldValues + @abstract Release the storage associated with the values returned by SecCertificateCopyFieldValues. + @param certificate A valid SecCertificateRef to the certificate. + @param field Pointer to the OID whose values were returned by SecCertificateCopyFieldValues. + @param fieldValues Pointer to a zero terminated list of CSSM_DATA_PTR's. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Release the storage associated with the values returned by SecCertificateCopyFieldValues. +*/ +OSStatus SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateReleaseFieldValues is deprecated. Use SecCertificateCopyValues instead."); + +/*! + @function SecCertificateCopyFirstFieldValue + @abstract Return a CSSM_DATA_PTR with the value of the first field specified by field. + @param certificate A valid SecCertificateRef to the certificate. + @param field Pointer to the OID whose value should be returned. + @param fieldValue On return, a CSSM_DATA_PTR to the field data. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Return a CSSM_DATA_PTR with the value of the first field specified by field. Caller must call + SecCertificateReleaseFieldValue to free the storage allocated by this call. +*/ +OSStatus SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopyFirstFieldValue is deprecated. Use SecCertificateCopyValues instead."); + +/*! + @function SecCertificateReleaseFirstFieldValue + @abstract Release the storage associated with the values returned by SecCertificateCopyFirstFieldValue. + @param certificate A valid SecCertificateRef to the certificate. + @param field Pointer to the OID whose values were returned by SecCertificateCopyFieldValue. + @param fieldValue The field data to release. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Release the storage associated with the values returned by SecCertificateCopyFieldValue. +*/ +OSStatus SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateReleaseFirstFieldValue is deprecated. Use SecCertificateCopyValues instead."); + +/*! + @function SecCertificateCopySubjectComponent + @abstract Retrieves a component of the subject distinguished name of a given certificate. + @param certificate A reference to the certificate from which to retrieve the common name. + @param component A component oid naming the component desired. See . + @param result On return, a reference to the string form of the component, if present in the subject. + Your code must release this reference by calling the CFRelease function. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, + CFStringRef *result) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopySubjectComponent is deprecated. Use SecCertificateCopyCommonNames,SecCertificateCopyOrganization,SecCertificateCopyOrganizationalUnit, etc. instead."); + +/* Convenience functions for searching. + */ +OSStatus SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, + const CSSM_DATA *serialNumber, SecCertificateRef *certificate) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindByIssuerAndSN is deprecated. Use SecItemCopyMatching instead."); + +OSStatus SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, + SecCertificateRef *certificate) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindBySubjectKeyID is deprecated. Use SecItemCopyMatching instead."); + +OSStatus SecCertificateFindByEmail(CFTypeRef keychainOrArray, const char *emailAddress, + SecCertificateRef *certificate) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateFindByEmail is deprecated. Use SecItemCopyMatching instead."); + +/* These should go to SecKeychainSearchPriv.h. */ +OSStatus SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, + const CSSM_DATA *serialNumber, SecKeychainSearchRef *searchRef) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByIssuerAndSN is deprecated. Use SecItemCopyMatching instead."); + +OSStatus SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray, CFDataRef issuer, + CFDataRef serialNumber, SecKeychainSearchRef *searchRef) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByIssuerAndSN_CF is deprecated. Use SecItemCopyMatching instead."); + +OSStatus SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, + SecKeychainSearchRef *searchRef) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateBySubjectKeyID is deprecated. Use SecItemCopyMatching instead."); + +OSStatus SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray, const char *emailAddress, + SecKeychainSearchRef *searchRef) + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecKeychainSearchCreateForCertificateByEmail is deprecated. Use SecItemCopyMatching instead."); + +/* Convenience function for generating digests; should be moved elsewhere. */ +CSSM_RETURN SecDigestGetData(CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA); + +/* Return true iff certificate is valid as of verifyTime. */ +/* DEPRECATED: Use SecCertificateIsValid instead. */ +bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecCertificateCopyPublicKeySHA1DigestFromCertificateData + @abstract Returns the SHA1 hash of the public key of a certificate or NULL + @param allocator CFAllocator to allocate the certificate with. + @param der_certificate DER encoded X.509 certificate. + @result SHA1 hash of the public key of a certificate or NULL +*/ +CFDataRef SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator, + CFDataRef der_certificate) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_13_2, __IPHONE_NA, __IPHONE_NA); // Likely incorrect. + +#endif /* SEC_OS_OSX */ + +__END_DECLS + +#endif /* !_SECURITY_SECCERTIFICATEPRIV_H_ */ diff --git a/trust/headers/SecCertificateRequest.h b/trust/headers/SecCertificateRequest.h new file mode 100644 index 00000000..ba33965e --- /dev/null +++ b/trust/headers/SecCertificateRequest.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecCertificateRequest + SecCertificateRequest implements a way to issue a certificate request to a + certificate authority. +*/ + +#ifndef _SECURITY_SECCERTIFICATEREQUEST_H_ +#define _SECURITY_SECCERTIFICATEREQUEST_H_ + +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN + +extern const CFStringRef kSecOidCommonName; +extern const CFStringRef kSecOidCountryName; +extern const CFStringRef kSecOidStateProvinceName; +extern const CFStringRef kSecOidLocalityName; +extern const CFStringRef kSecOidOrganization; +extern const CFStringRef kSecOidOrganizationalUnit; + +extern const unsigned char SecASN1PrintableString; +extern const unsigned char SecASN1UTF8String; + +/* + Parameter keys for certificate request generation: + @param kSecCSRChallengePassword CFStringRef + conversion to PrintableString or UTF8String needs to be possible. + @param kSecCertificateKeyUsage CFNumberRef + with key usage mask using kSecKeyUsage constants. + @param kSecSubjectAltName CFDictionaryRef + with keys defined below. + @param kSecCSRBasicContraintsPathLen CFNumberRef + if set will include basic constraints and mark it as + a CA cert. If 0 <= number < 256, specifies path length, otherwise + path length will be omitted. Basic contraints will always be + marked critical. + @param kSecCertificateExtensions CFDictionaryRef + if set all keys (strings with oids in dotted notation) will be added + as extensions with accompanying value in binary (CFDataRef) or + appropriate string (CFStringRef) type (based on used character set). + @param kSecCertificateExtensionsEncoded CFDictionaryRef + if set all keys (strings with oids in dotted notation) will be added + as extensions with accompanying value. It is assumed that the value + is a CFDataRef and is already properly encoded. This value will be + placed straight into the extension value OCTET STRING. + @param kSecCMSSignHashAlgorithm CFStringRef + (Declared in SecCMS.h) + if set, determines the hash algorithm used to create the signing + request or certificate. If this parameter is omitted, the default + hash algorithm will be used (SHA1 for RSA and SHA256 for ECDSA). + Supported digest algorithm strings are defined in + SecCMS.h, e.g. kSecCMSHashingAlgorithmSHA256;. +*/ +extern const CFStringRef kSecCSRChallengePassword; +extern const CFStringRef kSecSubjectAltName; +extern const CFStringRef kSecCertificateKeyUsage; +extern const CFStringRef kSecCSRBasicContraintsPathLen; +extern const CFStringRef kSecCertificateExtensions; +extern const CFStringRef kSecCertificateExtensionsEncoded; + +/* + Keys for kSecSubjectAltName dictionaries: + @param kSecSubjectAltNameDNSName CFArrayRef or CFStringRef + The value for this key is either a CFStringRef containing a single DNS name, + or a CFArrayRef of CFStringRefs, each containing a single DNS Name. + @param kkSecSubjectAltNameEmailAddress CFArrayRef or CFStringRef + The value for this key is either a CFStringRef containing a single email + address (RFC 822 Name), or a CFArrayRef of CFStringRefs, each containing a + single email address. + @param kSecSubjectAltNameURI CFArrayRef or CFStringRef + The value for this key is either a CFStringRef containing a single URI, + or a CFArrayRef of CFStringRefs, each containing a single URI. + @param kSecSubjectAltNameNTPrincipalName CFStringRef + The value for this key is a CFStringRef containing the NTPrincipalName. +*/ +extern const CFStringRef kSecSubjectAltNameDNSName; +extern const CFStringRef kSecSubjectAltNameEmailAddress; +extern const CFStringRef kSecSubjectAltNameURI; +extern const CFStringRef kSecSubjectAltNameNTPrincipalName; + +typedef struct { + CFTypeRef oid; /* kSecOid constant or CFDataRef with oid */ + unsigned char type; /* currently only SecASN1PrintableString or SecASN1UTF8String */ + CFTypeRef value; /* CFStringRef -> ASCII, UTF8, CFDataRef -> binary */ +} SecATV; + +typedef SecATV *SecRDN; + +/* + @function SecGenerateCertificateRequestWithParameters + @abstract Return a newly generated CSR for subject and keypair. + @param subject RDNs in the subject + @param paramters Parameters for the CSR generation. See above. + @param publicKey Public key + @param privateKey Private key + @result On success, a newly allocated CSR, otherwise NULL + +Example for subject: + SecATV cn[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("test") }, {} }; + SecATV c[] = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} }; + SecATV o[] = { { kSecOidOrganization, SecASN1PrintableString, CFSTR("Apple Inc.") }, {} }; + SecRDN atvs[] = { cn, c, o, NULL }; +*/ +CF_RETURNS_RETAINED _Nullable +CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN _Nonnull * _Nonnull subject, + CFDictionaryRef _Nullable parameters, SecKeyRef _Nullable publicKey, SecKeyRef privateKey) CF_RETURNS_RETAINED; + +/* + @function SecGenerateCertificateRequest + @abstract Return a newly generated CSR for subject and keypair. + @param subject RDNs in the subject in array format + @param paramters Parameters for the CSR generation. See above. + @param publicKey Public key + @param privateKey Private key + @result On success, a newly allocated CSR, otherwise NULL + @discussion The subject array contains an array of the RDNS. Each RDN is + itself an array of ATVs. Each ATV is an array of length two containing + first the OID and then the value. + +Example for subject (in Objective-C for ease of reading): + NSArray *subject = @[ + @[@[(__bridge NSString*)kSecOidCommonName, @"test"]] + @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], + @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc"]], + ]; + */ +CF_RETURNS_RETAINED _Nullable +CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, + CFDictionaryRef _Nullable parameters, SecKeyRef _Nullable publicKey, SecKeyRef privateKey) CF_RETURNS_RETAINED; + +/* + @function SecVerifyCertificateRequest + @abstract validate a CSR and return contained information to certify + @param publicKey (optional/out) SecKeyRef public key to certify + @param challenge (optional/out) CFStringRef enclosed challenge + @param subject (optional/out) encoded subject RDNs + @param extensions (optional/out) encoded extensions +*/ +bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef CF_RETURNS_RETAINED * _Nullable publicKey, + CFStringRef CF_RETURNS_RETAINED _Nullable * _Nullable challenge, + CFDataRef CF_RETURNS_RETAINED _Nullable * _Nullable subject, + CFDataRef CF_RETURNS_RETAINED _Nullable * _Nullable extensions); + + +/* + @function SecGenerateSelfSignedCertificate + @abstract Return a newly generated certificate for subject and keypair. + @param subject RDNs in the subject in array format + @param paramters Parameters for the CSR generation. See above. + @param publicKey Public key (NOTE: This is unused) + @param privateKey Private key + @result On success, a newly allocated certificate, otherwise NULL + @discussion The subject array contains an array of the RDNS. Each RDN is + itself an array of ATVs. Each ATV is an array of length two containing + first the OID and then the value. + + Example for subject (in Objective-C for ease of reading): + NSArray *subject = @[ + @[@[(__bridge NSString*)kSecOidCommonName, @"test"]] + @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], + @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc"]], + ]; + */ +CF_RETURNS_RETAINED _Nullable +SecCertificateRef SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, + SecKeyRef _Nullable publicKey, SecKeyRef privateKey); + +/* + @function SecIdentitySignCertificate + @param issuer issuer's identity (certificate/private key pair) + @param serialno serial number for the issued certificate + @param publicKey public key for the issued certificate + @param subject subject name for the issued certificate + @param extensions extensions for the issued certificate + @param hashingAlgorithm hash algorithm to use for signature + @result On success, a newly allocated certificate, otherwise NULL + @discussion This call can be used in combination with SecVerifyCertificateRequest + to generate a signed certifcate from a CSR after verifying it. The outputs + of SecVerifyCertificateRequest may be passed as inputs to this function. + + The subject may be an array, as specified in SecCertificateGenerateRequest, + or a data containing an encoded subject sequence, as specified by RFC 5280. + + Supported digest algorithm strings are defined in SecCMS.h, e.g. + kSecCMSHashingAlgorithmSHA256. + */ +CF_RETURNS_RETAINED _Nullable +SecCertificateRef SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno, + SecKeyRef publicKey, CFTypeRef subject, CFTypeRef _Nullable extensions); + +CF_RETURNS_RETAINED _Nullable +SecCertificateRef SecIdentitySignCertificateWithAlgorithm(SecIdentityRef issuer, CFDataRef serialno, + SecKeyRef publicKey, CFTypeRef subject, CFTypeRef _Nullable extensions, CFStringRef _Nullable hashingAlgorithm); + +/* PRIVATE */ + +CF_RETURNS_RETAINED _Nullable +CFDataRef SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate, CFArrayRef subject); + +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* _SECURITY_SECCERTIFICATEREQUEST_H_ */ diff --git a/trust/headers/SecPolicy.h b/trust/headers/SecPolicy.h new file mode 100644 index 00000000..59e95b54 --- /dev/null +++ b/trust/headers/SecPolicy.h @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecPolicy + The functions provided in SecPolicy.h provide an interface to various + X.509 certificate trust policies. + */ + +#ifndef _SECURITY_SECPOLICY_H_ +#define _SECURITY_SECPOLICY_H_ + +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @enum Policy Constants + @discussion Predefined constants used to specify a policy. + @constant kSecPolicyAppleX509Basic + @constant kSecPolicyAppleSSL + @constant kSecPolicyAppleSMIME + @constant kSecPolicyAppleEAP + @constant kSecPolicyAppleiChat + @constant kSecPolicyAppleIPsec + @constant kSecPolicyApplePKINITClient + @constant kSecPolicyApplePKINITServer + @constant kSecPolicyAppleCodeSigning + @constant kSecPolicyMacAppStoreReceipt + @constant kSecPolicyAppleIDValidation + @constant kSecPolicyAppleTimeStamping + @constant kSecPolicyAppleRevocation + @constant kSecPolicyApplePassbookSigning + @constant kSecPolicyApplePayIssuerEncryption + */ +extern const CFStringRef kSecPolicyAppleX509Basic + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleSSL + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleSMIME + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleEAP + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleIPsec + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +#if TARGET_OS_OSX +extern const CFStringRef kSecPolicyAppleiChat + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); +#endif +extern const CFStringRef kSecPolicyApplePKINITClient + API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); +extern const CFStringRef kSecPolicyApplePKINITServer + API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac); +extern const CFStringRef kSecPolicyAppleCodeSigning + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyMacAppStoreReceipt + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleIDValidation + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleTimeStamping + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleRevocation + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyApplePassbookSigning + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyApplePayIssuerEncryption + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @enum Policy Value Constants + @abstract Predefined property key constants used to get or set values in + a dictionary for a policy instance. + @discussion + All policies will have the following read-only value: + kSecPolicyOid (the policy object identifier) + + Additional policy values which your code can optionally set: + kSecPolicyName (name which must be matched) + kSecPolicyClient (evaluate for client, rather than server) + kSecPolicyRevocationFlags (only valid for a revocation policy) + kSecPolicyTeamIdentifier (only valid for a Passbook signing policy) + + @constant kSecPolicyOid Specifies the policy OID (value is a CFStringRef) + @constant kSecPolicyName Specifies a CFStringRef (or CFArrayRef of same) + containing a name which must be matched in the certificate to satisfy + this policy. For SSL/TLS, EAP, and IPSec policies, this specifies the + server name which must match the common name of the certificate. + For S/MIME, this specifies the RFC822 email address. For Passbook + signing, this specifies the pass signer. + @constant kSecPolicyClient Specifies a CFBooleanRef value that indicates + this evaluation should be for a client certificate. If not set (or + false), the policy evaluates the certificate as a server certificate. + @constant kSecPolicyRevocationFlags Specifies a CFNumberRef that holds a + kCFNumberCFIndexType bitmask value. See "Revocation Policy Constants" + for a description of individual bits in this value. + @constant kSecPolicyTeamIdentifier Specifies a CFStringRef containing a + team identifier which must be matched in the certificate to satisfy + this policy. For the Passbook signing policy, this string must match + the Organizational Unit field of the certificate subject. + */ +extern const CFStringRef kSecPolicyOid + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyName + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyClient + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPolicyRevocationFlags + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyTeamIdentifier + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + + +/*! + @function SecPolicyGetTypeID + @abstract Returns the type identifier of SecPolicy instances. + @result The CFTypeID of SecPolicy instances. + */ +CFTypeID SecPolicyGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecPolicyCopyProperties + @abstract Returns a dictionary of this policy's properties. + @param policyRef A policy reference. + @result A properties dictionary. See "Policy Value Constants" for a list + of currently defined property keys. It is the caller's responsibility to + CFRelease this reference when it is no longer needed. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function returns the properties for a policy, as set by the + policy's construction function or by a prior call to SecPolicySetProperties. + */ +__nullable +CFDictionaryRef SecPolicyCopyProperties(SecPolicyRef policyRef) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); + +/*! + @function SecPolicyCreateBasicX509 + @abstract Returns a policy object for the default X.509 policy. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +SecPolicyRef SecPolicyCreateBasicX509(void) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecPolicyCreateSSL + @abstract Returns a policy object for evaluating SSL certificate chains. + @param server Passing true for this parameter creates a policy for SSL + server certificates. + @param hostname (Optional) If present, the policy will require the specified + hostname to match the hostname in the leaf certificate. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef __nullable hostname) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @enum Revocation Policy Constants + @abstract Predefined constants which allow you to specify how revocation + checking will be performed for a trust evaluation. + @constant kSecRevocationOCSPMethod If this flag is set, perform revocation + checking using OCSP (Online Certificate Status Protocol). + @constant kSecRevocationCRLMethod If this flag is set, perform revocation + checking using the CRL (Certificate Revocation List) method. + @constant kSecRevocationPreferCRL If this flag is set, then CRL revocation + checking will be preferred over OCSP (by default, OCSP is preferred.) + Note that this flag only matters if both revocation methods are specified. + @constant kSecRevocationRequirePositiveResponse If this flag is set, then + the policy will fail unless a verified positive response is obtained. If + the flag is not set, revocation checking is done on a "best attempt" basis, + where failure to reach the server is not considered fatal. + @constant kSecRevocationNetworkAccessDisabled If this flag is set, then + no network access is performed; only locally cached replies are consulted. + This constant disallows network access for both revocation checks and + intermediate CA issuer fetching. + @constant kSecRevocationUseAnyAvailableMethod Specifies that either + OCSP or CRL may be used, depending on the method(s) specified in the + certificate and the value of kSecRevocationPreferCRL. + */ +CF_ENUM(CFOptionFlags) { + kSecRevocationOCSPMethod = (1 << 0), + kSecRevocationCRLMethod = (1 << 1), + kSecRevocationPreferCRL = (1 << 2), + kSecRevocationRequirePositiveResponse = (1 << 3), + kSecRevocationNetworkAccessDisabled = (1 << 4), + kSecRevocationUseAnyAvailableMethod = (kSecRevocationOCSPMethod | + kSecRevocationCRLMethod) +}; + +/*! + @function SecPolicyCreateRevocation + @abstract Returns a policy object for checking revocation of certificates. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + @param revocationFlags Flags to specify revocation checking options. + @discussion Use this function to create a revocation policy with behavior + specified by revocationFlags. See the "Revocation Policy Constants" section + for a description of these flags. Note: it is usually not necessary to + create a revocation policy yourself unless you wish to override default + system behavior (e.g. to force a particular method, or to disable + revocation checking entirely.) + */ +__nullable +SecPolicyRef SecPolicyCreateRevocation(CFOptionFlags revocationFlags) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecPolicyCreateWithProperties + @abstract Returns a policy object based on an object identifier for the + policy type. See the "Policy Constants" section for a list of defined + policy object identifiers. + @param policyIdentifier The identifier for the desired policy type. + @param properties (Optional) A properties dictionary. See "Policy Value + Constants" for a list of currently defined property keys. + @result The returned policy reference, or NULL if the policy could not be + created. + */ +__nullable +SecPolicyRef SecPolicyCreateWithProperties(CFTypeRef policyIdentifier, + CFDictionaryRef __nullable properties) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +/* + * Legacy functions (OS X only) + */ +#if TARGET_OS_OSX +#include + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @enum Policy Value Constants (OS X) + @discussion Predefined property key constants used to get or set values in + a dictionary for a policy instance. + + Some policy values may specify CFBooleanRef key usage constraints: + kSecPolicyKU_DigitalSignature + kSecPolicyKU_NonRepudiation + kSecPolicyKU_KeyEncipherment + kSecPolicyKU_DataEncipherment + kSecPolicyKU_KeyAgreement + kSecPolicyKU_KeyCertSign + kSecPolicyKU_CRLSign + kSecPolicyKU_EncipherOnly + kSecPolicyKU_DecipherOnly + + kSecPolicyKU policy values define certificate-level key purposes, + in contrast to the key-level definitions in SecItem.h + + For example, a key in a certificate might be acceptable to use for + signing a CRL, but not for signing another certificate. In either + case, this key would have the ability to sign (i.e. kSecAttrCanSign + is true), but may only sign for specific purposes allowed by these + policy constants. Similarly, a public key might have the capability + to perform encryption or decryption, but the certificate in which it + resides might have a decipher-only certificate policy. + + These constants correspond to values defined in RFC 5280, section + 4.2.1.3 (Key Usage) which define the purpose of a key contained in a + certificate, in contrast to section 4.1.2.7 which define the uses that + a key is capable of. + + Note: these constants are not available on iOS. Your code should + avoid direct reliance on these values for making policy decisions + and use higher level policies where possible. + + @constant kSecPolicyKU_DigitalSignature Specifies that the certificate must + have a key usage that allows it to be used for signing. + @constant kSecPolicyKU_NonRepudiation Specifies that the certificate must + have a key usage that allows it to be used for non-repudiation. + @constant kSecPolicyKU_KeyEncipherment Specifies that the certificate must + have a key usage that allows it to be used for key encipherment. + @constant kSecPolicyKU_DataEncipherment Specifies that the certificate must + have a key usage that allows it to be used for data encipherment. + @constant kSecPolicyKU_KeyAgreement Specifies that the certificate must + have a key usage that allows it to be used for key agreement. + @constant kSecPolicyKU_KeyCertSign Specifies that the certificate must + have a key usage that allows it to be used for signing certificates. + @constant kSecPolicyKU_CRLSign Specifies that the certificate must + have a key usage that allows it to be used for signing CRLs. + @constant kSecPolicyKU_EncipherOnly Specifies that the certificate must + have a key usage that permits it to be used for encryption only. + @constant kSecPolicyKU_DecipherOnly Specifies that the certificate must + have a key usage that permits it to be used for decryption only. + */ +extern const CFStringRef kSecPolicyKU_DigitalSignature + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_NonRepudiation + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_KeyEncipherment + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_DataEncipherment + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_KeyAgreement + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_KeyCertSign + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_CRLSign + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_EncipherOnly + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); +extern const CFStringRef kSecPolicyKU_DecipherOnly + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecPolicyCreateWithOID + @abstract Returns a policy object based on an object identifier for the + policy type. See the "Policy Constants" section for a list of defined + policy object identifiers. + @param policyOID The OID of the desired policy. + @result The returned policy reference, or NULL if the policy could not be + created. + @discussion This function is deprecated in Mac OS X 10.9 and later; + use SecPolicyCreateWithProperties (or a more specific policy creation + function) instead. + */ +__nullable +SecPolicyRef SecPolicyCreateWithOID(CFTypeRef policyOID) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicyGetOID + @abstract Returns a policy's object identifier. + @param policyRef A policy reference. + @param oid On return, a pointer to the policy's object identifier. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later; + use SecPolicyCopyProperties instead. + */ +OSStatus SecPolicyGetOID(SecPolicyRef policyRef, CSSM_OID *oid) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicyGetValue + @abstract Returns a policy's value. + @param policyRef A policy reference. + @param value On return, a pointer to the policy's value. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later; + use SecPolicyCopyProperties instead. + */ +OSStatus SecPolicyGetValue(SecPolicyRef policyRef, CSSM_DATA *value) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicySetValue + @abstract Sets a policy's value. + @param policyRef A policy reference. + @param value The value to be set into the policy object, replacing any + previous value. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later. Policy + instances should be considered read-only; in cases where your code would + consider changing properties of a policy, it should instead create a new + policy instance with the desired properties. + */ +OSStatus SecPolicySetValue(SecPolicyRef policyRef, const CSSM_DATA *value) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicySetProperties + @abstract Sets a policy's properties. + @param policyRef A policy reference. + @param properties A properties dictionary. See "Policy Value Constants" + for a list of currently defined property keys. This dictionary replaces the + policy's existing properties, if any. Note that the policy OID (specified + by kSecPolicyOid) is a read-only property of the policy and cannot be set. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.9 and later. Policy + instances should be considered read-only; in cases where your code would + consider changing properties of a policy, it should instead create a new + policy instance with the desired properties. + */ +OSStatus SecPolicySetProperties(SecPolicyRef policyRef, + CFDictionaryRef properties) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicyGetTPHandle + @abstract Returns the CSSM trust policy handle for the given policy. + @param policyRef A policy reference. + @param tpHandle On return, a pointer to a value of type CSSM_TP_HANDLE. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later. + */ +OSStatus SecPolicyGetTPHandle(SecPolicyRef policyRef, CSSM_TP_HANDLE *tpHandle) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ + +__END_DECLS + +#endif /* !_SECURITY_SECPOLICY_H_ */ diff --git a/trust/headers/SecPolicyPriv.h b/trust/headers/SecPolicyPriv.h new file mode 100644 index 00000000..781fb65f --- /dev/null +++ b/trust/headers/SecPolicyPriv.h @@ -0,0 +1,2021 @@ +/* + * Copyright (c) 2003-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecPolicyPriv + The functions provided in SecPolicyPriv provide an interface to various + X.509 certificate trust policies. +*/ + +#ifndef _SECURITY_SECPOLICYPRIV_H_ +#define _SECURITY_SECPOLICYPRIV_H_ + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @enum Policy Constants (Private) + @discussion Predefined constants used to specify a policy. + */ +extern const CFStringRef kSecPolicyAppleMobileStore + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleTestMobileStore + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleEscrowService + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleProfileSigner + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleQAProfileSigner + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecPolicyAppleServerAuthentication + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); +extern const CFStringRef kSecPolicyAppleOTAPKISigner + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); +extern const CFStringRef kSecPolicyAppleTestOTAPKISigner + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); +extern const CFStringRef kSecPolicyAppleIDValidationRecordSigningPolicy + API_DEPRECATED_WITH_REPLACEMENT("kSecPolicyAppleIDValidationRecordSigning", ios(7.0,10.0), macos(10.9,10.12)); +extern const CFStringRef kSecPolicyAppleIDValidationRecordSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleSMPEncryption + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); +extern const CFStringRef kSecPolicyAppleTestSMPEncryption + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); +extern const CFStringRef kSecPolicyApplePCSEscrowService + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +extern const CFStringRef kSecPolicyApplePPQSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleTestPPQSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleSWUpdateSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyApplePackageSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleOSXProvisioningProfileSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleATVVPNProfileSigning + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecPolicyAppleAST2DiagnosticsServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); +extern const CFStringRef kSecPolicyAppleEscrowProxyServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleFMiPServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleMMCService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleGSService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyApplePPQService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleHomeKitServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiPhoneActivation + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiPhoneDeviceCertificate + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleFactoryDeviceCertificate + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiAP + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiTunesStoreURLBag + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiPhoneApplicationSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiPhoneProfileApplicationSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleiPhoneProvisioningProfileSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleLockdownPairing + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleURLBag + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleOTATasking + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleMobileAsset + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleIDAuthority + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleGenericApplePinned + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleGenericAppleSSLPinned + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleSoftwareSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleExternalDeveloper + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleOCSPSigner + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleIDSService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleIDSServiceContext + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyApplePushService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleLegacyPushService + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleTVOSApplicationSigning + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleUniqueDeviceIdentifierCertificate + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleEscrowProxyCompatibilityServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleMMCSCompatibilityServerAuth + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyAppleSecureIOStaticAsset + __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); +extern const CFStringRef kSecPolicyAppleWarsaw + __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); +extern const CFStringRef kSecPolicyAppleiCloudSetupServerAuth + __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); +extern const CFStringRef kSecPolicyAppleiCloudSetupCompatibilityServerAuth + __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); +extern const CFStringRef kSecPolicyAppleAppTransportSecurity + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMobileSoftwareUpdate + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMobileAssetDevelopment + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMacOSProfileApplicationSigning + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleBasicAttestationSystem + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleBasicAttestationUser + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleiPhoneVPNApplicationSigning + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleiAPSWAuth + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); +extern const CFStringRef kSecPolicyAppleDemoDigitalCatalog + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); +extern const CFStringRef kSecPolicyAppleAssetReceipt + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); +extern const CFStringRef kSecPolicyAppleDeveloperIDPlusTicket + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); +extern const CFStringRef kSecPolicyAppleComponentCertificate + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); +extern const CFStringRef kSecPolicyAppleKeyTransparency + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); +extern const CFStringRef kSecPolicyAppleLegacySSL + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + +/*! + @enum Policy Name Constants (Private) + @discussion Predefined constants used to specify a SSL Pinning policy. + To be used with SecTrustSetPolicyName. + @constant kSecPolicyNameAppleAST2Service + @constant kSecPolicyNameAppleEscrowProxyService + @constant kSecPolicyNameAppleFMiPService + @constant kSecPolicyNameAppleGSService + @constant kSecPolicyNameAppleHomeKitService + @constant kSecPolicyNameAppleiCloudSetupService + @constant kSecPolicyNameAppleIDSService + @constant kSecPolicyNameAppleMMCSService + @constant kSecPolicyNameApplePPQService + @constant kSecPolicyNameApplePushService + @constant kSecPolicyNameAppleAIDCService + @constant kSecPolicyNameAppleMapsService + @constant kSecPolicyNameAppleHealthProviderService + @constant kSecPolicyNameAppleParsecService + @constant kSecPolicyNameAppleAMPService + @constant kSecPolicyNameAppleSiriService + @constant kSecPolicyNameAppleHomeAppClipUploadService + */ +extern const CFStringRef kSecPolicyNameAppleAST2Service + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleEscrowProxyService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleFMiPService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleGSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleHomeKitService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleiCloudSetupService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleIDSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleMMCSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameApplePPQService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameApplePushService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleAIDCService + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); +extern const CFStringRef kSecPolicyNameAppleMapsService + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); +extern const CFStringRef kSecPolicyNameAppleHealthProviderService + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); +extern const CFStringRef kSecPolicyNameAppleParsecService + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); +extern const CFStringRef kSecPolicyNameAppleAMPService + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); +extern const CFStringRef kSecPolicyNameAppleSiriService + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); +extern const CFStringRef kSecPolicyNameAppleHomeAppClipUploadService + API_AVAILABLE(macos(10.15.1), ios(13.2), watchos(6.1), tvos(13.1)); + +/*! + @enum Policy Value Constants + @abstract Predefined property key constants used to get or set values in + a dictionary for a policy instance. + @discussion + All policies will have the following read-only value: + kSecPolicyOid (the policy object identifier) + + Additional policy values which your code can optionally set: + kSecPolicyName (name which must be matched) + kSecPolicyClient (evaluate for client, rather than server) + kSecPolicyRevocationFlags (only valid for a revocation policy) + kSecPolicyRevocationFlags (only valid for a revocation policy) + kSecPolicyTeamIdentifier (only valid for a Passbook signing policy) + kSecPolicyContext (valid for policies below that take a context parameter) + kSecPolicyPolicyName (only valid for GenericApplePinned or + GenericAppleSSLPinned policies) + kSecPolicyIntermediateMarkerOid (only valid for GenericApplePinned or + GenericAppleSSLPinned policies) + kSecPolicyLeafMarkerOid (only valid for GenericApplePinned or + GenericAppleSSLPinned policies) + kSecPolicyRootDigest (only valid for the UniqueDeviceCertificate policy) + + @constant kSecPolicyContext Specifies a CFDictionaryRef with keys and values + specified by the particular SecPolicyCreate function. + @constant kSecPolicyPolicyName Specifies a CFStringRef of the name of the + desired policy result. + @constant kSecPolicyIntermediateMarkerOid Specifies a CFStringRef of the + marker OID (in decimal format) required in the intermediate certificate. + @constant kSecPolicyLeafMarkerOid Specifies a CFStringRef of the + marker OID (in decimal format) required in the leaf certificate. + @constant kSecPolicyRootDigest Specifies a CFDataRef of digest required to + match the SHA-256 of the root certificate. + */ +extern const CFStringRef kSecPolicyContext + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyPolicyName + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyIntermediateMarkerOid + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyLeafMarkerOid + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +extern const CFStringRef kSecPolicyRootDigest + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/*! + @enum Revocation Policy Constants + @abstract Predefined constants which allow you to specify how revocation + checking will be performed for a trust evaluation. + @constant kSecRevocationOnlineCheck If this flag is set, perform an online + revocation check, ignoring cached revocation results. This flag will not force + an online check if an online check was done within the last 5 minutes. Online + checks are only applicable to OCSP; this constant will not force a fresh + CRL download. + @constant kSecRevocationCheckIfTrusted If this flag is set, perform network-based + revocation checks only if the chain has no other validation errors. This flag + overrides SecTrustSetNetworkFetchAllowed and kSecRevocationNetworkAccessDisabled + for revocation checking (but not for intermediate fetching). + Note that this flag's behavior is not default because revoked certs produce Fatal + trust results, whereas most checks produce Recoverable trust results. If we skip + revocation checks on untrusted chains, the user may be able to ignore the failures + of a revoked cert. + */ +CF_ENUM(CFOptionFlags) { + kSecRevocationOnlineCheck = (1 << 5), + kSecRevocationCheckIfTrusted = (1 << 6), +}; + +/*! + @function SecPolicyCreateApplePinned + @abstract Returns a policy object for verifying Apple certificates. + @param policyName A string that identifies the policy name. + @param intermediateMarkerOID A string containing the decimal representation of the + extension OID in the intermediate certificate. + @param leafMarkerOID A string containing the decimal representation of the extension OID + in the leaf certificate. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if the value true is set for the key + "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the + com.apple.security preferences for the user of the calling application. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID matching the intermediateMarkerOID + parameter. + * The leaf has a marker extension with OID matching the leafMarkerOID parameter. + * Revocation is checked via any available method. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePinned(CFStringRef policyName, + CFStringRef intermediateMarkerOID, CFStringRef leafMarkerOID) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyCreateAppleSSLPinned + @abstract Returns a policy object for verifying Apple SSL certificates. + @param policyName A string that identifies the service/policy name. + @param hostname hostname to verify the certificate name against. + @param intermediateMarkerOID A string containing the decimal representation of the + extension OID in the intermediate certificate. If NULL is passed, the default OID of + 1.2.840.113635.100.6.2.12 is checked. + @param leafMarkerOID A string containing the decimal representation of the extension OID + in the leaf certificate. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if the value true is set for the key + "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the + com.apple.security preferences for the user of the calling application. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID matching the intermediateMarkerOID + parameter, or 1.2.840.113635.100.6.2.12 if NULL is passed. + * The leaf has a marker extension with OID matching the leafMarkerOID parameter. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef hostname, + CFStringRef __nullable intermediateMarkerOID, CFStringRef leafMarkerOID) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyCreateiPhoneActivation + @abstract Returns a policy object for verifying iPhone Activation + certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "iPhone Activation". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneActivation(void); + +/*! + @function SecPolicyCreateiPhoneDeviceCertificate + @abstract Returns a policy object for verifying iPhone Device certificate + chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 4 certs in chain. + * The first intermediate has Common Name "Apple iPhone Device CA". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneDeviceCertificate(void); + +/*! + @function SecPolicyCreateFactoryDeviceCertificate + @abstract Returns a policy object for verifying Factory Device certificate + chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to the Factory Device CA. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateFactoryDeviceCertificate(void); + +/*! + @function SecPolicyCreateiAP + @abstract Returns a policy object for verifying iAP certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The leaf has notBefore date after 5/31/2006 midnight GMT. + * The leaf has Common Name beginning with "IPA_". + The intended use of this policy is that the caller pass in the + intermediates for iAP1 and iAP2 to SecTrustSetAnchorCertificates(). + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiAP(void); + +/*! + @function SecPolicyCreateiTunesStoreURLBag + @abstract Returns a policy object for verifying iTunes Store URL bag + certificates. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to the iTMS CA. + * There are exactly 2 certs in the chain. + * The leaf has Organization "Apple Inc.". + * The leaf has Common Name "iTunes Store URL Bag". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiTunesStoreURLBag(void); + +/*! + @function SecPolicyCreateEAP + @abstract Returns a policy object for verifying for 802.1x/EAP certificates. + @param server Passing true for this parameter create a policy for EAP + server certificates. + @param trustedServerNames Optional; if present, the hostname in the leaf + certificate must be in the trustedServerNames list. Note that contrary + to all other policies the trustedServerNames list entries can have wildcards + whilst the certificate cannot. This matches the existing deployments. + @discussion This policy uses the Basic X.509 policy with validity check but + disallowing network fetching. If trustedServerNames param is non-null, the + ExtendedKeyUsage extension, if present, of the leaf certificate is verified + to contain either the ServerAuth OID, if the server param is true or + ClientAuth OID, otherwise. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateEAP(Boolean server, CFArrayRef __nullable trustedServerNames); + +/*! + @function SecPolicyCreateIPSec + @abstract Returns a policy object for evaluating IPSec certificate chains. + @param server Passing true for this parameter create a policy for IPSec + server certificates. + @param hostname Optional; if present, the policy will require the specified + hostname or ip address to match the hostname in the leaf certificate. + @discussion This policy uses the Basic X.509 policy with validity check. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateIPSec(Boolean server, CFStringRef __nullable hostname); + +/*! + @function SecPolicyCreateAppleSWUpdateSigning + @abstract Returns a policy object for evaluating SW update signing certs. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate ExtendedKeyUsage Extension contains 1.2.840.113635.100.4.1. + * The leaf ExtendedKeyUsage extension contains 1.2.840.113635.100.4.1. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSWUpdateSigning(void); + +/*! + @function SecPolicyCreateApplePackageSigning + @abstract Returns a policy object for evaluating installer package signing certs. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The leaf KeyUsage extension has the digital signature bit set. + * The leaf ExtendedKeyUsage extension has the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePackageSigning(void); + +/*! + @function SecPolicyCreateiPhoneApplicationSigning + @abstract Returns a policy object for evaluating signed application + signatures. This is for apps signed directly by the app store. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "Apple iPhone OS Application Signing". + * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.3 or OID + 1.2.840.113635.100.6.1.6. + * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID + or the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void); + +/*! + @function SecPolicyCreateiPhoneVPNApplicationSigning + @abstract Returns a policy object for evaluating signed VPN application + signatures. This is for VPN plugins signed directly by the VPN team. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "Apple iPhone OS Application Signing". + * The leaf has a marker extension with 1.2.840.113635.100.6.1.6. + * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID + or the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneVPNApplicationSigning(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateiPhoneProfileApplicationSigning + @abstract Returns a policy object for evaluating signed application + signatures. This policy is for certificates inside a UPP or regular + profile. + @discussion This policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1 (WWDR CA). + * The leaf has a marker extension with OID matching one of the following: + * 1.2.840.113635.100.6.1.2 ("iPhone Developer" leaf) + * 1.2.840.113635.100.6.1.4 ("iPhone Distribution" leaf) + * 1.2.840.113635.100.6.1.25.1 ("TestFlight" leaf) + * On internal releases, 1.2.840.113635.100.6.1.25.2 + * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneProfileApplicationSigning(void); + +/*! + @function SecPolicyCreateMacOSProfileApplicationSigning + @abstract Returns a policy object for evaluating signed application + signatures. This policy is for certificates inside a UPP or regular + profile. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The leaf has a marker extension with OID matching one of the following: + * 1.2.840.113635.100.6.1.7 ("3rd Party Mac Developer Application" leaf) + * 1.2.840.113635.100.6.1.12 ("Mac Developer" leaf) + * 1.2.840.113635.100.6.1.13 ("Developer ID Application" leaf) + * 1.2.840.113635.100.6.22 ("Software Signing" leaf + * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMacOSProfileApplicationSigning(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateiPhoneProvisioningProfileSigning + @abstract Returns a policy object for evaluating provisioning profile signatures. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "Apple iPhone OS Provisioning Profile Signing". + * If the device is not a production device and is running an internal + release, the leaf may have the Common Name "TEST Apple iPhone OS + Provisioning Profile Signing TEST". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneProvisioningProfileSigning(void); + +/*! + @function SecPolicyCreateAppleTVOSApplicationSigning + @abstract Returns a policy object for evaluating signed application + signatures. This is for apps signed directly by the Apple TV app store, + and allows for both the prod and the dev/test certs. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. + Test roots are never permitted. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. + * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID or + the CodeSigning OID. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.24 or OID + 1.2.840.113635.100.6.1.24.1. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleTVOSApplicationSigning(void); + +/*! + @function SecPolicyCreateOCSPSigner + @abstract Returns a policy object for evaluating ocsp response signers. + @discussion This policy uses the Basic X.509 policy with validity check and + requires the leaf to have an ExtendedKeyUsage of OCSPSigning. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateOCSPSigner(void); + + +enum { + kSecSignSMIMEUsage = (1 << 0), + kSecKeyEncryptSMIMEUsage = (1 << 1), + kSecDataEncryptSMIMEUsage = (1 << 2), + kSecKeyExchangeDecryptSMIMEUsage = (1 << 3), + kSecKeyExchangeEncryptSMIMEUsage = (1 << 4), + kSecKeyExchangeBothSMIMEUsage = (1 << 5), + kSecAnyEncryptSMIME = kSecKeyEncryptSMIMEUsage | kSecDataEncryptSMIMEUsage | + kSecKeyExchangeDecryptSMIMEUsage | kSecKeyExchangeEncryptSMIMEUsage, + kSecIgnoreExpirationSMIMEUsage = (1 << 6) +}; + +/*! + @function SecPolicyCreateSMIME + @abstract Returns a policy object for evaluating S/MIME certificate chains. + @param smimeUsage Pass the bitwise or of one or more kSecXXXSMIMEUsage + flags, to indicate the intended usage of this certificate. + @param email Optional; if present, the policy will require the specified + email to match the email in the leaf certificate. + @discussion This policy uses the Basic X.509 policy with validity check and + requires the leaf to have + * a KeyUsage matching the smimeUsage, + * an ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID or the + EmailProtection OID, and + * if the email param is specified, the email address in the RFC822Name in the + SubjectAlternativeName extension or in the Email Address field of the + Subject Name. + Note that temporal validity checking can be disabled with kSecIgnoreExpirationSMIMEUsage + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef __nullable email); + +/*! + @function SecPolicyCreateCodeSigning + @abstract Returns a policy object for evaluating code signing certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check and + requires the leaf to have + * a KeyUsage with both the DigitalSignature and NonRepudiation bits set, and + * an ExtendedKeyUsage with the AnyExtendedKeyUsage OID or the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateCodeSigning(void); + +/*! + @function SecPolicyCreateLockdownPairing + @abstract basic x509 policy for checking lockdown pairing certificate chains. + @discussion This policy checks some of the Basic X.509 policy options with no + validity check. It explicitly allows for empty subjects. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateLockdownPairing(void); + +/*! + @function SecPolicyCreateURLBag + @abstract Returns a policy object for evaluating certificate chains for signing URL bags. + @discussion This policy uses the Basic X.509 policy with no validity check and requires + that the leaf has ExtendedKeyUsage extension with the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateURLBag(void); + +/*! + @function SecPolicyCreateOTATasking + @abstract Returns a policy object for evaluating certificate chains for signing OTA Tasking. + @discussion This policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "OTA Task Signing". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateOTATasking(void); + +/*! + @function SecPolicyCreateMobileAsset + @abstract Returns a policy object for evaluating certificate chains for signing Mobile Assets. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple iPhone Certification Authority". + * The leaf has Common Name "Asset Manifest Signing". + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileAsset(void); + +/*! + @function SecPolicyCreateMobileAssetDevelopment + @abstract Returns a policy object for evaluating certificate chains for signing development + Mobile Assets. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.55.1. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileAssetDevelopment(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateAppleIDAuthorityPolicy + @abstract Returns a policy object for evaluating certificate chains for Apple ID Authority. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3 + or OID 1.2.840.113635.100.6.2.7. + * The leaf has a marker extension with OID 1.2.840.113635.100.4.7. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleIDAuthorityPolicy(void); + +/*! + @function SecPolicyCreateMacAppStoreReceipt + @abstract Returns a policy object for evaluating certificate chains for signing + Mac App Store Receipts. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. + * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.6.1. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.11.1. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMacAppStoreReceipt(void); + +/*! + @function SecPolicyCreatePassbookCardSigner + @abstract Returns a policy object for evaluating certificate chains for signing Passbook cards. + @param cardIssuer Required; must match name in marker extension. + @param teamIdentifier Optional; if present, the policy will require the specified + team ID to match the organizationalUnit field in the leaf certificate's subject. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.16 and containing the + cardIssuer. + * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.14. + * The leaf has a Organizational Unit matching the TeamID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreatePassbookCardSigner(CFStringRef cardIssuer, + CFStringRef __nullable teamIdentifier); + +/*! + @function SecPolicyCreateMobileStoreSigner + @abstract Returns a policy object for evaluating Mobile Store certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple System Integration 2 Certification Authority". + * The leaf has KeyUsage with the DigitalSignature bit set. + * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.12. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileStoreSigner(void); + +/*! + @function SecPolicyCreateTestMobileStoreSigner + @abstract Returns a policy object for evaluating Test Mobile Store certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple System Integration 2 Certification Authority". + * The leaf has KeyUsage with the DigitalSignature bit set. + * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.12.1. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateTestMobileStoreSigner(void); + +/*! + @function SecPolicyCreateEscrowServiceSigner + @abstract Returns a policy object for evaluating Escrow Service certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to the current Escrow Roots in the OTAPKI asset. + * There are exactly 2 certs in the chain. + * The leaf has KeyUsage with the KeyEncipherment bit set. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateEscrowServiceSigner(void); + +/*! + @function SecPolicyCreatePCSEscrowServiceSigner + @abstract Returns a policy object for evaluating PCS Escrow Service certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to the current PCS Escrow Roots in the OTAPKI asset. + * There are exactly 2 certs in the chain. + * The leaf has KeyUsage with the KeyEncipherment bit set. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreatePCSEscrowServiceSigner(void); + +/*! + @function SecPolicyCreateOSXProvisioningProfileSigning + @abstract Returns a policy object for evaluating certificate chains for signing OS X + Provisioning Profiles. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1. + * The leaf has KeyUsage with the DigitalSignature bit set. + * The leaf has a marker extension with OID 1.2.840.113635.100.4.11. + * Revocation is checked via OCSP. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateOSXProvisioningProfileSigning(void); + +/*! + @function SecPolicyCreateConfigurationProfileSigner + @abstract Returns a policy object for evaluating certificate chains for signing + Configuration Profiles. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3. + * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.16. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateConfigurationProfileSigner(void); + +/*! + @function SecPolicyCreateQAConfigurationProfileSigner + @abstract Returns a policy object for evaluating certificate chains for signing + QA Configuration Profiles. On customer builds, this function returns the same + policy as SecPolicyCreateConfigurationProfileSigner. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3. + * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.17. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateQAConfigurationProfileSigner(void); + +/*! + @function SecPolicyCreateOTAPKISigner + @abstract Returns a policy object for evaluating OTA PKI certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to Apple PKI Settings CA. + * There are exactly 2 certs in the chain. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateOTAPKISigner(void) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); + +/*! + @function SecPolicyCreateTestOTAPKISigner + @abstract Returns a policy object for evaluating OTA PKI certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to Apple Test PKI Settings CA. + * There are exactly 2 certs in the chain. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateTestOTAPKISigner(void) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3); + +/*! + @function SecPolicyCreateAppleIDValidationRecordSigningPolicy + @abstract Returns a policy object for evaluating certificate chains for signing + Apple ID Validation Records. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3 + or OID 1.2.840.113635.100.6.2.10. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.25. + * Revocation is checked via OCSP. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. +*/ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleIDValidationRecordSigningPolicy(void); + +/*! + @function SecPolicyCreateAppleSMPEncryption + @abstract Returns a policy object for evaluating SMP certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.13. + * The leaf has KeyUsage with the KeyEncipherment bit set. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.30. + * Revocation is checked via OCSP. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSMPEncryption(void); + +/*! + @function SecPolicyCreateTestAppleSMPEncryption + @abstract Returns a policy object for evaluating Test SMP certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to a Test Apple Root with ECC public key certificate. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Test Apple System Integration CA - ECC". + * The leaf has KeyUsage with the KeyEncipherment bit set. + * Revocation is checked via OCSP. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateTestAppleSMPEncryption(void); + +/*! + @function SecPolicyCreateApplePPQSigning + @abstract Returns a policy object for verifying production PPQ Signing certificates. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple System Integration 2 Certification + Authority". + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. + * The leaf has KeyUsage with the DigitalSignature bit set. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.38.2. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePPQSigning(void); + +/*! + @function SecPolicyCreateTestApplePPQSigning + @abstract Returns a policy object for verifying test PPQ Signing certificates. On + customer builds, this function returns the same policy as SecPolicyCreateApplePPQSigning. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple System Integration 2 Certification + Authority". + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. + * The leaf has KeyUsage with the DigitalSignature bit set. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.38.1. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateTestApplePPQSigning(void); + +/*! + @function SecPolicyCreateAppleIDSService + @abstract Ensure we're appropriately pinned to the IDS service (SSL + Apple restrictions) + @discussion This policy uses the SSL server policy. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef __nullable hostname); + +/*! + @function SecPolicyCreateAppleIDSServiceContext + @abstract Ensure we're appropriately pinned to the IDS service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATIDS" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted only on internal releases either using the context dictionary or with + defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.4.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.4.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleIDSServiceContext(CFStringRef hostname, CFDictionaryRef __nullable context); + +/*! + @function SecPolicyCreateApplePushService + @abstract Ensure we're appropriately pinned to the Apple Push service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATAPN" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted only on internal releases either using the context dictionary or with + defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.5.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.5.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePushService(CFStringRef hostname, CFDictionaryRef __nullable context); + +/*! + @function SecPolicyCreateApplePushServiceLegacy + @abstract Ensure we're appropriately pinned to the Push service (via Entrust) + @param hostname Required; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to an Entrust Intermediate. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePushServiceLegacy(CFStringRef hostname); + +/*! + @function SecPolicyCreateAppleMMCSService + @abstract Ensure we're appropriately pinned to the MMCS service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATMMCS" with value + Boolean true will allow Test Apple roots and test OIDs on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or, if + enabled, OID 1.2.840.113635.100.6.27.11.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleMMCSService(CFStringRef hostname, CFDictionaryRef __nullable context); + +/*! + @function SecPolicyCreateAppleCompatibilityMMCSService + @abstract Ensure we're appropriately pinned to the MMCS service using compatibility certs + @param hostname Required; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to the GeoTrust Global CA + * The intermediate has a subject public key info hash matching the public key of + the Apple IST CA G1 intermediate. + * The chain length is 3. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or + OID 1.2.840.113635.100.6.27.11.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleCompatibilityMMCSService(CFStringRef hostname) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/*! + @function SecPolicyCreateAppleGSService + @abstract Ensure we're appropriately pinned to the GS service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATGS" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted only on internal releases either using the context dictionary or with + defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.2. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleGSService(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @function SecPolicyCreateApplePPQService + @abstract Ensure we're appropriately pinned to the PPQ service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATPPQ" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted only on internal releases either using the context dictionary or with + defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.3.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.3.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePPQService(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @function SecPolicyCreateAppleAST2Service + @abstract Ensure we're appropriately pinned to the AST2 Diagnostic service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATAST2" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted either using the context dictionary or with defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.8.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.8.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleAST2Service(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); + +/*! + @function SecPolicyCreateAppleEscrowProxyService + @abstract Ensure we're appropriately pinned to the iCloud Escrow Proxy service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATEscrow" with value +Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check +and pinning options: + * The chain is anchored to any of the production Apple Root CAs via full certificate + comparison. Test Apple Root CAs are permitted only on internal releases either + using the context dictionary or with defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.7.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease +on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleEscrowProxyService(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/*! + @function SecPolicyCreateAppleCompatibilityEscrowProxyService + @abstract Ensure we're appropriately pinned to the iCloud Escrow Proxy service using compatibility certs + @param hostname Required; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to the GeoTrust Global CA + * The intermediate has a subject public key info hash matching the public key of + the Apple IST CA G1 intermediate. + * The chain length is 3. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or, + if UAT is enabled with a defaults write (internal devices only), + OID 1.2.840.113635.100.6.27.7.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleCompatibilityEscrowProxyService(CFStringRef hostname) +__OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/*! + @function SecPolicyCreateAppleFMiPService + @abstract Ensure we're appropriately pinned to the Find My iPhone service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATFMiP" with value + Boolean true will allow Test Apple roots on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs via full certificate + comparison. Test Apple Root CAs are permitted only on internal releases either + using the context dictionary or with defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.6.2 or, + if Test Roots are allowed, OID 1.2.840.113635.100.6.27.6.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleFMiPService(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + +/*! + @function SecPolicyCreateAppleSSLService + @abstract Ensure we're appropriately pinned to an Apple server (SSL + Apple restrictions) + @param hostname Optional; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.1 + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage, if any, with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSSLService(CFStringRef __nullable hostname); + +/*! + @function SecPolicyCreateAppleTimeStamping + @abstract Returns a policy object for evaluating time stamping certificate chains. + @discussion This policy uses the Basic X.509 policy with validity check + and requires the leaf has ExtendedKeyUsage with the TimeStamping OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleTimeStamping(void); + +/*! + @function SecPolicyCreateApplePayIssuerEncryption + @abstract Returns a policy object for evaluating Apple Pay Issuer Encryption certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has Common Name "Apple Worldwide Developer Relations CA - G2". + * The leaf has KeyUsage with the KeyEncipherment bit set. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.39. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateApplePayIssuerEncryption(void) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @function SecPolicyCreateAppleATVVPNProfileSigning + @abstract Returns a policy object for evaluating Apple TV VPN Profile certificate chains. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs + are permitted only on internal releases. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.43. + * Revocation is checked via OCSP. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleATVVPNProfileSigning(void) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + +/*! + @function SecPolicyCreateAppleHomeKitServerAuth + @abstract Ensure we're appropriately pinned to the HomeKit service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs via full certificate + comparison. Test Apple Root CAs are permitted only on internal releases with defaults write. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.16 + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.9. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) + __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_9_3); + +/*! + @function SecPolicyCreateAppleExternalDeveloper + @abstract Returns a policy object for verifying Apple-issued external developer + certificates. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1 + (WWDR CA) or 1.2.840.113635.100.6.2.6 (Developer ID CA). + * The leaf has a marker extension with OID matching one of the following: + * 1.2.840.113635.100.6.1.2 ("iPhone Developer" leaf) + * 1.2.840.113635.100.6.1.4 ("iPhone Distribution" leaf) + * 1.2.840.113635.100.6.1.5 ("Safari Developer" leaf) + * 1.2.840.113635.100.6.1.7 ("3rd Party Mac Developer Application" leaf) + * 1.2.840.113635.100.6.1.8 ("3rd Party Mac Developer Installer" leaf) + * 1.2.840.113635.100.6.1.12 ("Mac Developer" leaf) + * 1.2.840.113635.100.6.1.13 ("Developer ID Application" leaf) + * 1.2.840.113635.100.6.1.14 ("Developer ID Installer" leaf) + * The leaf has an ExtendedKeyUsage OID matching one of the following: + * 1.3.6.1.5.5.7.3.3 (CodeSigning EKU) + * 1.2.840.113635.100.4.8 ("Safari Developer" EKU) + * 1.2.840.113635.100.4.9 ("3rd Party Mac Developer Installer" EKU) + * 1.2.840.113635.100.4.13 ("Developer ID Installer" EKU) + * Revocation is checked via any available method. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleExternalDeveloper(void) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyCreateAppleSoftwareSigning + @abstract Returns a policy object for verifying the Apple Software Signing certificate. + @discussion The resulting policy uses the Basic X.509 policy with no validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has the Common Name "Apple Code Signing Certification Authority". + * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.22. + * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (Code Signing). + * Revocation is checked via any available method. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSoftwareSigning(void) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyGetName + @abstract Returns a policy's name. + @param policy A policy reference. + @result A policy name. + */ +__nullable CFStringRef SecPolicyGetName(SecPolicyRef policy) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyGetOidString + @abstract Returns a policy's oid in string decimal format. + @param policy A policy reference. + @result A policy oid. + */ +CFStringRef SecPolicyGetOidString(SecPolicyRef policy) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyCreateAppleUniqueDeviceCertificate + @abstract Returns a policy object for verifying Unique Device Identifier Certificates. + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with no validity check and + pinning options: + * The chain is anchored to the SEP Root CA. Internal releases allow the chain to be + anchored to the testRootHash input if the value true is set for the key + "ApplePinningAllowTestCertsUCRT" in the com.apple.security preferences for the user + of the calling application. + * There are exactly 3 certs in the chain. + * The intermediate has an extension with OID matching 1.2.840.113635.100.6.44 and value + of "ucrt". + * The leaf has a marker extension with OID matching 1.2.840.113635.100.10.1. + * RSA key sizes are disallowed. EC key sizes are P-256 or larger. +@result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleUniqueDeviceCertificate(CFDataRef __nullable testRootHash) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecPolicyCreateAppleWarsaw + @abstract Returns a policy object for verifying signed Warsaw assets. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.14. + * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.29. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleWarsaw(void) + __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); + +/*! + @function SecPolicyCreateAppleSecureIOStaticAsset + @abstract Returns a policy object for verifying signed static assets for Secure IO. + @discussion The resulting policy uses the Basic X.509 policy with no validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.10. + * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.50. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void) + __OSX_AVAILABLE(10.12.1) __IOS_AVAILABLE(10.1) __TVOS_AVAILABLE(10.0.1) __WATCHOS_AVAILABLE(3.1); + +/*! + @function SecPolicyCreateAppleiCloudSetupService + @abstract Ensure we're appropriately pinned to the iCloud Setup service (SSL + Apple restrictions) + @param hostname Required; hostname to verify the certificate name against. + @param context Optional; if present, "AppleServerAuthenticationAllowUATiCloudSetup" with value + Boolean true will allow Test Apple roots and test OIDs on internal releases. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or, if + enabled, OID 1.2.840.113635.100.6.27.15.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + * Revocation is checked via any available method. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleiCloudSetupService(CFStringRef hostname, CFDictionaryRef __nullable context) + __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); + +/*! + @function SecPolicyCreateAppleCompatibilityiCloudSetupService + @abstract Ensure we're appropriately pinned to the iCloud Setup service using compatibility certs + @param hostname Required; hostname to verify the certificate name against. + @discussion This policy uses the Basic X.509 policy with validity check + and pinning options: + * The chain is anchored to the GeoTrust Global CA + * The intermediate has a subject public key info hash matching the public key of + the Apple IST CA G1 intermediate. + * The chain length is 3. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or + OID 1.2.840.113635.100.6.27.15.1. + * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName + extension or Common Name. + * The leaf is checked against the Black and Gray lists. + * The leaf has ExtendedKeyUsage with the ServerAuth OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleCompatibilityiCloudSetupService(CFStringRef hostname) + __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); + +/*! + @function SecPolicyCreateAppleAppTransportSecurity + @abstract Ensure all certs in the evaluation meet ATS minimums + @discussion This policy is meant to be used alongside an SSL policy in order to enforce App Transport Security certificate rules: + * All certificates use either RSA key sizes of 2048-bits or larger or EC key sizes of 256-bits or larger. + * All certificates use SHA-256 or better for signature hash algorithms. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleAppTransportSecurity(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateMobileSoftwareUpdate + @abstract Returns a policy object for evaluating certificate chains for signing Mobile Software Updates. + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.57.2, or on internal releases, + 1.2.840.113635.100.6.57.1. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileSoftwareUpdate(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateAppleBasicAttestationSystem + @abstract Returns a policy object for verifying Basic Attestation Authority SCRT-attested certs + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to the Basic Attestation System Root CA. + * There are exactly 3 certs in the chain. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleBasicAttestationSystem(CFDataRef __nullable testRootHash) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateAppleBasicAttestationUser + @abstract Returns a policy object for verifying Basic Attestation Authority UCRT-attested certs + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to the Basic Attestation User Root CA. + * There are exactly 3 certs in the chain. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleBasicAttestationUser(CFDataRef __nullable testRootHash) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateiAPSWAuth + @abstract Returns a policy object for verifying iAP Software Auth certificates + @discussion The resulting policy uses the Basic X.509 policy with no validity check + and pinning options: + * There are exactly 2 certs in the chain. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.59.1 + The intended use of this policy is that the caller pass in the + SW Auth root to SecTrustSetAnchorCertificates(). + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiAPSWAuth(void) + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); + +/*! + @function SecPolicyCreateDemoDigitalCatalog + @abstract Returns a policy object for evaluating certificate chains for signing Digital + Catalog manifests for Demo units. + @discussion This policy uses the Basic X.509 policy with validity check and + pinning options: + * There are exactly 3 certs in the chain. + * The intermediate has common name "DemoUnit CA" + * The leaf has a marker extension with OID 1.2.840.113635.100.6.60 + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateDemoDigitalCatalogSigning(void) + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); + +/*! + @function SecPolicyCreateAppleAssetReceipt + @abstract Returns a policy object for evaluating certificate chains for signing Asset Receipts + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. Internal releases allow + the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.61. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleAssetReceipt(void) + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); + +/*! + @function SecPolicyCreateAppleDeveloperIDPlustTicket + @abstract Returns a policy object for evaluating certificate chains for signing Developer ID+ Tickets + @discussion This policy uses the Basic X.509 policy with no validity check + and pinning options: + * The chain is anchored to any of the production Apple Root CAs. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.17. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.30. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleDeveloperIDPlusTicket(void) + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); + +/*! + @function SecPolicyCreateiAPSWAuthWithExpiration + @abstract Returns a policy object for verifying iAP Software Auth certificates + @param checkExpiration Determines whether the policy checks expiration on the certificates + @discussion The resulting policy uses the Basic X.509 policy and pinning options: + * There are exactly 2 certs in the chain. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.59.1 + The intended use of this policy is that the caller pass in the + SW Auth root to SecTrustSetAnchorCertificates(). + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiAPSWAuthWithExpiration(bool checkExpiration) + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); + +/*! + @function SecPolicyCreateAppleFDRProvisioning + @abstract Returns a policy object for verifying FDR Provisioning certificates + @discussion The resulting policy uses the Basic X.509 policy with no validity check. + The intended use of this policy is that the caller pass in the FDR root to SecTrustSetAnchorCertificates(). + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleFDRProvisioning(void) + API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0)); + +/*! + @function SecPolicyCreateAppleComponentCertificate + @abstract Returns a policy object for verifying Component certs + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to the Component Root CA. + * There are exactly 3 certs in the chain. + * The leaf and intermediate each have a marker extension with OID matching 1.2.840.113635.100.11.1 + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleComponentCertificate(CFDataRef __nullable testRootHash) + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + +/*! + @function SecPolicyCreateAppleKeyTransparency + @abstract Returns a policy object for verifying Apple certificates. + @param applicationId A string that identifies the applicationId. + @discussion The resulting policy uses the Basic X.509 policy with no validity check and + pinning options: + * The chain is anchored to any of the production Apple Root CAs. + * There are exactly 3 certs in the chain. + * The intermediate has a marker extension with OID TBD. + * The leaf has a marker extension with OID 1.2.840.113635.100.6.69.1 and value + matching the applicationId. + * Revocation is checked via any available method. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease on this when + it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleKeyTransparency(CFStringRef applicationId) + API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + +/*! + @function SecPolicyCreateLegacySSL + @abstract Returns a policy object for evaluating legacy SSL certificate chains that don't meet + SecPolicyCreateSSL. + @param server Passing true for this parameter creates a policy for SSL + server certificates. + @param hostname (Optional) If present, the policy will require the specified + hostname to match the hostname in the leaf certificate. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + @discussion Use of this policy will be audited. Passing false for the server parameter will + result in a SecPolicy object with the same requirements as SecPolicyCreateSSL with a false + server parameter (i.e. the client authentication verification performed by this policy is + identical to the client authentication verification performed by SecPolicyCreateSSL). + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateLegacySSL(Boolean server, CFStringRef __nullable hostname) + SPI_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); + +/* + * Legacy functions (OS X only) + */ +#if TARGET_OS_OSX + +/*! + @function SecPolicyCopy + @abstract Returns a copy of a policy reference based on certificate type and OID. + @param certificateType A certificate type. + @param policyOID The OID of the policy you want to find. This is a required parameter. See oidsalg.h to see a list of policy OIDs. + @param policy The returned policy reference. This is a required parameter. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later; + to obtain a policy reference, use one of the SecPolicyCreate* functions in SecPolicy.h. + */ +OSStatus SecPolicyCopy(CSSM_CERT_TYPE certificateType, const CSSM_OID *policyOID, SecPolicyRef * __nonnull CF_RETURNS_RETAINED policy) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecPolicyCopyAll + @abstract Returns an array of all known policies based on certificate type. + @param certificateType A certificate type. This is a optional parameter. Pass CSSM_CERT_UNKNOWN if the certificate type is unknown. + @param policies The returned array of policies. This is a required parameter. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in Mac OS X 10.7 and later; + to obtain a policy reference, use one of the SecPolicyCreate* functions in SecPolicy.h. (Note: there is normally + no reason to iterate over multiple disjointed policies, except to provide a way to edit trust settings for each + policy, as is done in certain certificate UI views. In that specific case, your code should call SecPolicyCreateWithOID + for each desired policy from the list of supported OID constants in SecPolicy.h.) + */ +OSStatus SecPolicyCopyAll(CSSM_CERT_TYPE certificateType, CFArrayRef * __nonnull CF_RETURNS_RETAINED policies) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/* Given a unified SecPolicyRef, return a copy with a legacy + C++ ItemImpl-based Policy instance. Only for internal use; + legacy references cannot be used by SecPolicy API functions. */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateItemImplInstance(SecPolicyRef policy); + +/* Given a CSSM_OID pointer, return a string which can be passed + to SecPolicyCreateWithProperties. The return value can be NULL + if no supported policy was found for the OID argument. */ +__nullable +CFStringRef SecPolicyGetStringForOID(CSSM_OID* oid) + API_DEPRECATED("No longer supported", macos(10.5,10.14)); + +/*! + @function SecPolicyCreateAppleTimeStampingAndRevocationPolicies + @abstract Create timeStamping policy array from a given set of policies by applying identical revocation behavior + @param policyOrArray can be a SecPolicyRef or a CFArray of SecPolicyRef + @discussion This function is deprecated in macOS 10.13 and later. Your code should call SecPolicyCreateAppleTimeStamping + and SecPolicyCreateRevocation instead to obtain these policies, then insert them into an array as needed. + */ +__nullable CF_RETURNS_RETAINED +CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); + +#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ + +/* MARK: WARNING: The following constants and functions are for project use + * within the Security project and are subject to change without warning */ + +/*! + @enum Policy Check Keys + @discussion Keys that represent various checks that can be done in a trust + policy. Use outside of the Security project at your own peril. + */ +extern const CFStringRef kSecPolicyCheckAnchorApple; +extern const CFStringRef kSecPolicyCheckAnchorSHA1; +extern const CFStringRef kSecPolicyCheckAnchorSHA256; +extern const CFStringRef kSecPolicyCheckAnchorTrusted; +extern const CFStringRef kSecPolicyCheckBasicCertificateProcessing; +extern const CFStringRef kSecPolicyCheckBasicConstraints; +extern const CFStringRef kSecPolicyCheckBasicConstraintsCA; +extern const CFStringRef kSecPolicyCheckBasicConstraintsPathLen; +extern const CFStringRef kSecPolicyCheckBlackListedKey; +extern const CFStringRef kSecPolicyCheckBlackListedLeaf; +extern const CFStringRef kSecPolicyCheckCertificatePolicy; +extern const CFStringRef kSecPolicyCheckChainLength; +extern const CFStringRef kSecPolicyCheckCriticalExtensions; +extern const CFStringRef kSecPolicyCheckCTRequired; +extern const CFStringRef kSecPolicyCheckEAPTrustedServerNames; +extern const CFStringRef kSecPolicyCheckEmail; +extern const CFStringRef kSecPolicyCheckExtendedKeyUsage; +extern const CFStringRef kSecPolicyCheckExtendedValidation; +extern const CFStringRef kSecPolicyCheckGrayListedKey; +extern const CFStringRef kSecPolicyCheckGrayListedLeaf; +extern const CFStringRef kSecPolicyCheckIdLinkage; +extern const CFStringRef kSecPolicyCheckIntermediateCountry; +extern const CFStringRef kSecPolicyCheckIntermediateEKU; +extern const CFStringRef kSecPolicyCheckIntermediateMarkerOid; +extern const CFStringRef kSecPolicyCheckIntermediateMarkerOidWithoutValueCheck; +extern const CFStringRef kSecPolicyCheckIntermediateOrganization; +extern const CFStringRef kSecPolicyCheckIntermediateSPKISHA256; +extern const CFStringRef kSecPolicyCheckIssuerCommonName; +extern const CFStringRef kSecPolicyCheckIssuerPolicyConstraints; +extern const CFStringRef kSecPolicyCheckIssuerNameConstraints; +extern const CFStringRef kSecPolicyCheckKeySize; +extern const CFStringRef kSecPolicyCheckKeyUsage; +extern const CFStringRef kSecPolicyCheckLeafMarkerOid; +extern const CFStringRef kSecPolicyCheckLeafMarkerOidWithoutValueCheck; +extern const CFStringRef kSecPolicyCheckLeafMarkersProdAndQA; +extern const CFStringRef kSecPolicyCheckMissingIntermediate; +extern const CFStringRef kSecPolicyCheckNameConstraints; +extern const CFStringRef kSecPolicyCheckNoNetworkAccess; +extern const CFStringRef kSecPolicyCheckNonEmptySubject; +extern const CFStringRef kSecPolicyCheckNotValidBefore; +extern const CFStringRef kSecPolicyCheckPinningRequired; +extern const CFStringRef kSecPolicyCheckPolicyConstraints; +extern const CFStringRef kSecPolicyCheckRevocation; +extern const CFStringRef kSecPolicyCheckRevocationIfTrusted; +extern const CFStringRef kSecPolicyCheckRevocationOnline; +extern const CFStringRef kSecPolicyCheckRevocationResponseRequired; +extern const CFStringRef kSecPolicyCheckSSLHostname; +extern const CFStringRef kSecPolicyCheckServerAuthEKU; +extern const CFStringRef kSecPolicyCheckSignatureHashAlgorithms; +extern const CFStringRef kSecPolicyCheckSubjectCommonName; +extern const CFStringRef kSecPolicyCheckSubjectCommonNamePrefix; +extern const CFStringRef kSecPolicyCheckSubjectCommonNameTEST; +extern const CFStringRef kSecPolicyCheckSubjectOrganization; +extern const CFStringRef kSecPolicyCheckSubjectOrganizationalUnit; +extern const CFStringRef kSecPolicyCheckSystemTrustedCTRequired; +extern const CFStringRef kSecPolicyCheckSystemTrustedWeakHash; +extern const CFStringRef kSecPolicyCheckSystemTrustedWeakKey; +extern const CFStringRef kSecPolicyCheckTemporalValidity; +extern const CFStringRef kSecPolicyCheckUnparseableExtension; +extern const CFStringRef kSecPolicyCheckUsageConstraints; +extern const CFStringRef kSecPolicyCheckValidityPeriodMaximums; +extern const CFStringRef kSecPolicyCheckValidRoot; +extern const CFStringRef kSecPolicyCheckWeakKeySize; +extern const CFStringRef kSecPolicyCheckWeakSignature; + +/* Special option for checking Apple Anchors */ +extern const CFStringRef kSecPolicyAppleAnchorIncludeTestRoots; + +/* Special option for checking Prod and QA Markers */ +extern const CFStringRef kSecPolicyLeafMarkerProd; +extern const CFStringRef kSecPolicyLeafMarkerQA; + +/* Special option for checking Revocation */ +extern const CFStringRef kSecPolicyCheckRevocationOCSP; +extern const CFStringRef kSecPolicyCheckRevocationCRL; +extern const CFStringRef kSecPolicyCheckRevocationAny; + +/* Policy Names */ +extern const CFStringRef kSecPolicyNameX509Basic; +extern const CFStringRef kSecPolicyNameSSLServer; +extern const CFStringRef kSecPolicyNameSSLClient; +extern const CFStringRef kSecPolicyNameEAPServer; +extern const CFStringRef kSecPolicyNameEAPClient; +extern const CFStringRef kSecPolicyNameIPSecServer; +extern const CFStringRef kSecPolicyNameIPSecClient; +extern const CFStringRef kSecPolicyNameSMIME; +extern const CFStringRef kSecPolicyNameCodeSigning; +extern const CFStringRef kSecPolicyNameTimeStamping; +extern const CFStringRef kSecPolicyNameOCSPSigner; + +/* + * MARK: SecPolicyCheckCert functions + */ +bool SecPolicyCheckCertSSLHostname(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertEmail(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertTemporalValidity(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertWeakKeySize(SecCertificateRef cert, CFTypeRef __nullable pvcValue); +bool SecPolicyCheckCertKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertExtendedKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertSubjectCommonName(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertSubjectCommonNamePrefix(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertSubjectCommonNameTEST(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertSubjectOrganization(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertSubjectOrganizationalUnit(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertNotValidBefore(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertEAPTrustedServerNames(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertLeafMarkerOid(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertLeafMarkersProdAndQA(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef __nullable pvcValue); +bool SecPolicyCheckCertKeySize(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertWeakSignature(SecCertificateRef cert, CFTypeRef __nullable pvcValue); +bool SecPolicyCheckCertSignatureHashAlgorithms(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertCertificatePolicy(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertCriticalExtensions(SecCertificateRef cert, CFTypeRef __nullable pvcValue); +bool SecPolicyCheckCertSubjectCountry(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertUnparseableExtension(SecCertificateRef cert, CFTypeRef pvcValue); + +void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName); +__nullable CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFErrorRef *error); + +void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); + +bool SecDNSIsTLD(CFStringRef reference); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* !_SECURITY_SECPOLICYPRIV_H_ */ diff --git a/trust/headers/SecTrust.h b/trust/headers/SecTrust.h new file mode 100644 index 00000000..a48083cd --- /dev/null +++ b/trust/headers/SecTrust.h @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecTrust + The functions and data types in SecTrust implement trust computation + and allow the caller to apply trust decisions to the evaluation. + */ + +#ifndef _SECURITY_SECTRUST_H_ +#define _SECURITY_SECTRUST_H_ + +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @typedef SecTrustResultType + @abstract Specifies the trust result type. + @discussion SecTrustResultType results have two dimensions. They specify + both whether evaluation succeeded and whether this is because of a user + decision. The commonly expected result is kSecTrustResultUnspecified, + which indicates a positive result that wasn't decided by the user. The + common failure is kSecTrustResultRecoverableTrustFailure, which means a + negative result. kSecTrustResultProceed and kSecTrustResultDeny are the + positive and negative result respectively when decided by the user. User + decisions are persisted through the use of SecTrustCopyExceptions() and + SecTrustSetExceptions(). Finally, kSecTrustResultFatalTrustFailure is a + negative result that must not be circumvented. + @constant kSecTrustResultInvalid Indicates an invalid setting or result. + This result usually means that SecTrustEvaluate has not yet been called. + @constant kSecTrustResultProceed Indicates you may proceed. This value + may be returned by the SecTrustEvaluate function or stored as part of + the user trust settings. + @constant kSecTrustResultConfirm Indicates confirmation with the user + is required before proceeding. Important: this value is no longer returned + or supported by SecTrustEvaluate or the SecTrustSettings API starting in + OS X 10.5; its use is deprecated in OS X 10.9 and later, as well as in iOS. + @constant kSecTrustResultDeny Indicates a user-configured deny; do not + proceed. This value may be returned by the SecTrustEvaluate function + or stored as part of the user trust settings. + @constant kSecTrustResultUnspecified Indicates the evaluation succeeded + and the certificate is implicitly trusted, but user intent was not + explicitly specified. This value may be returned by the SecTrustEvaluate + function or stored as part of the user trust settings. + @constant kSecTrustResultRecoverableTrustFailure Indicates a trust policy + failure which can be overridden by the user. This value may be returned + by the SecTrustEvaluate function but not stored as part of the user + trust settings. + @constant kSecTrustResultFatalTrustFailure Indicates a trust failure + which cannot be overridden by the user. This value may be returned by the + SecTrustEvaluate function but not stored as part of the user trust + settings. + @constant kSecTrustResultOtherError Indicates a failure other than that + of trust evaluation. This value may be returned by the SecTrustEvaluate + function but not stored as part of the user trust settings. + */ +typedef CF_ENUM(uint32_t, SecTrustResultType) { + kSecTrustResultInvalid CF_ENUM_AVAILABLE(10_3, 2_0) = 0, + kSecTrustResultProceed CF_ENUM_AVAILABLE(10_3, 2_0) = 1, + kSecTrustResultConfirm CF_ENUM_DEPRECATED(10_3, 10_9, 2_0, 7_0) = 2, + kSecTrustResultDeny CF_ENUM_AVAILABLE(10_3, 2_0) = 3, + kSecTrustResultUnspecified CF_ENUM_AVAILABLE(10_3, 2_0) = 4, + kSecTrustResultRecoverableTrustFailure CF_ENUM_AVAILABLE(10_3, 2_0) = 5, + kSecTrustResultFatalTrustFailure CF_ENUM_AVAILABLE(10_3, 2_0) = 6, + kSecTrustResultOtherError CF_ENUM_AVAILABLE(10_3, 2_0) = 7 +}; + +/*! + @typedef SecTrustRef + @abstract CFType used for performing X.509 certificate trust evaluations. + */ +typedef struct CF_BRIDGED_TYPE(id) __SecTrust *SecTrustRef; + +/*! + @enum Trust Property Constants + @discussion Predefined key constants used to obtain values in a + per-certificate dictionary of trust evaluation results, + as retrieved from a call to SecTrustCopyProperties. + @constant kSecPropertyTypeTitle Specifies a key whose value is a + CFStringRef containing the title (display name) of this certificate. + @constant kSecPropertyTypeError Specifies a key whose value is a + CFStringRef containing the reason for a trust evaluation failure. + */ +extern const CFStringRef kSecPropertyTypeTitle + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); +extern const CFStringRef kSecPropertyTypeError + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); + +/*! + @enum Trust Result Constants + @discussion Predefined key constants used to obtain values in a + dictionary of trust evaluation results for a certificate chain, + as retrieved from a call to SecTrustCopyResult. + @constant kSecTrustEvaluationDate + This key will be present if a trust evaluation has been performed + and results are available. Its value is a CFDateRef representing + when the evaluation for this trust object took place. + @constant kSecTrustExtendedValidation + This key will be present and have a value of kCFBooleanTrue + if this chain was validated for EV. + @constant kSecTrustOrganizationName + Organization name field of subject of leaf certificate. This + field is meant to be displayed to the user as the validated + name of the company or entity that owns the certificate if the + kSecTrustExtendedValidation key is present. + @constant kSecTrustResultValue + This key will be present if a trust evaluation has been performed. + Its value is a CFNumberRef representing the SecTrustResultType result + for the evaluation. + @constant kSecTrustRevocationChecked + This key will be present iff this chain had its revocation checked. + The value will be a kCFBooleanTrue if revocation checking was + successful and none of the certificates in the chain were revoked. + The value will be kCFBooleanFalse if no current revocation status + could be obtained for one or more certificates in the chain due + to connection problems or timeouts. This is a hint to a client + to retry revocation checking at a later time. + @constant kSecTrustRevocationValidUntilDate + This key will be present iff kSecTrustRevocationChecked has a + value of kCFBooleanTrue. The value will be a CFDateRef representing + the earliest date at which the revocation info for one of the + certificates in this chain might change. + @constant kSecTrustCertificateTransparency + This key will be present and have a value of kCFBooleanTrue + if this chain is CT qualified. + @constant kSecTrustCertificateTransparencyWhiteList + This key will be present and have a value of kCFBooleanTrue + if this chain is EV, not CT qualified, but included of the CT WhiteList. + */ +extern const CFStringRef kSecTrustEvaluationDate + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustExtendedValidation + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustOrganizationName + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustResultValue + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustRevocationChecked + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustRevocationValidUntilDate + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +extern const CFStringRef kSecTrustCertificateTransparency + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +extern const CFStringRef kSecTrustCertificateTransparencyWhiteList + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13, __IPHONE_10_0, __IPHONE_11_0); + +#ifdef __BLOCKS__ +/*! + @typedef SecTrustCallback + @abstract Delivers the result from an asynchronous trust evaluation. + @param trustRef A reference to the trust object which has been evaluated. + @param trustResult The trust result of the evaluation. Additional status + information can be obtained by calling SecTrustCopyProperties(). + */ +typedef void (^SecTrustCallback)(SecTrustRef trustRef, SecTrustResultType trustResult); +#endif /* __BLOCKS__ */ + + +/*! + @function SecTrustGetTypeID + @abstract Returns the type identifier of SecTrust instances. + @result The CFTypeID of SecTrust instances. + */ +CFTypeID SecTrustGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecTrustCreateWithCertificates + @abstract Creates a trust object based on the given certificates and + policies. + @param certificates The group of certificates to verify. This can either + be a CFArrayRef of SecCertificateRef objects or a single SecCertificateRef + @param policies An array of one or more policies. You may pass a + SecPolicyRef to represent a single policy. + @param trust On return, a pointer to the trust management reference. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If multiple policies are passed in, all policies must verify + for the chain to be considered valid. + */ +OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates, + CFTypeRef __nullable policies, SecTrustRef * __nonnull CF_RETURNS_RETAINED trust) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecTrustSetPolicies + @abstract Set the policies for which trust should be verified. + @param trust A trust reference. + @param policies An array of one or more policies. You may pass a + SecPolicyRef to represent a single policy. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will invalidate the existing trust result, + requiring a fresh evaluation for the newly-set policies. + */ +OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef policies) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_6_0); + +/*! + @function SecTrustCopyPolicies + @abstract Returns an array of policies used for this evaluation. + @param trust A reference to a trust object. + @param policies On return, an array of policies used by this trust. + Call the CFRelease function to release this reference. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef * __nonnull CF_RETURNS_RETAINED policies) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_7_0); + +/*! + @function SecTrustSetNetworkFetchAllowed + @abstract Specifies whether a trust evaluation is permitted to fetch missing + intermediate certificates from the network. + @param trust A trust reference. + @param allowFetch If true, and a certificate's issuer is not present in the + trust reference but its network location is known, the evaluation is permitted + to attempt to download it automatically. Pass false to disable network fetch + for this trust evaluation. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion By default, network fetch of missing certificates is enabled if + the trust evaluation includes the SSL policy, otherwise it is disabled. + */ +OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, + Boolean allowFetch) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecTrustGetNetworkFetchAllowed + @abstract Returns whether a trust evaluation is permitted to fetch missing + intermediate certificates from the network. + @param trust A trust reference. + @param allowFetch On return, the boolean pointed to by this parameter is + set to true if the evaluation is permitted to download missing certificates. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion By default, network fetch of missing certificates is enabled if + the trust evaluation includes the SSL policy, otherwise it is disabled. + */ +OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, + Boolean *allowFetch) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecTrustSetAnchorCertificates + @abstract Sets the anchor certificates for a given trust. + @param trust A reference to a trust object. + @param anchorCertificates An array of anchor certificates. + Pass NULL to restore the default set of anchor certificates. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Calling this function without also calling + SecTrustSetAnchorCertificatesOnly() will disable trusting any + anchors other than the ones in anchorCertificates. + */ +OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, + CFArrayRef __nullable anchorCertificates) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecTrustSetAnchorCertificatesOnly + @abstract Reenables trusting anchor certificates in addition to those + passed in via the SecTrustSetAnchorCertificates API. + @param trust A reference to a trust object. + @param anchorCertificatesOnly If true, disables trusting any anchors other + than the ones passed in via SecTrustSetAnchorCertificates(). If false, + the built in anchor certificates are also trusted. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, + Boolean anchorCertificatesOnly) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecTrustCopyCustomAnchorCertificates + @abstract Returns an array of custom anchor certificates used by a given + trust, as set by a prior call to SecTrustSetAnchorCertificates, or NULL if + no custom anchors have been specified. + @param trust A reference to a trust object. + @param anchors On return, an array of custom anchor certificates (roots) + used by this trust, or NULL if no custom anchors have been specified. Call + the CFRelease function to release this reference. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, + CFArrayRef * __nonnull CF_RETURNS_RETAINED anchors) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_7_0); + +/*! + @function SecTrustSetVerifyDate + @abstract Set the date for which the trust should be verified. + @param trust A reference to a trust object. + @param verifyDate The date for which to verify trust. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function lets you evaluate certificate validity for a + given date (for example, to determine if a signature was valid on the date + it was signed, even if the certificate has since expired.) If this function + is not called, the time at which SecTrustEvaluate() is called is used + implicitly as the verification time. + */ +OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_2_0); + +/*! + @function SecTrustGetVerifyTime + @abstract Returns the verify time. + @param trust A reference to the trust object being verified. + @result A CFAbsoluteTime value representing the time at which certificates + should be checked for validity. + @discussion This function retrieves the verification time for the given + trust reference, as set by a prior call to SecTrustSetVerifyDate(). If the + verification time has not been set, this function returns a value of 0, + indicating that the current date/time is implicitly used for verification. + */ +CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0); + +/*! + @function SecTrustEvaluate + @abstract Evaluates a trust reference synchronously. + @param trust A reference to the trust object to evaluate. + @param result A pointer to a result type. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will completely evaluate trust before returning, + possibly including network access to fetch intermediate certificates or to + perform revocation checking. Since this function can block during those + operations, you should call it from within a function that is placed on a + dispatch queue, or in a separate thread from your application's main + run loop. Alternatively, you can use the SecTrustEvaluateAsync function. + */ +OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) + API_DEPRECATED_WITH_REPLACEMENT("SecTrustEvaluateWithError", + macos(10.3, 10.15), + ios(2.0, 13.0), + watchos(1.0, 6.0), + tvos(2.0, 13.0)); + +#ifdef __BLOCKS__ +/*! + @function SecTrustEvaluateAsync + @abstract Evaluates a trust reference asynchronously. + @param trust A reference to the trust object to evaluate. + @param queue A dispatch queue on which the result callback should be + executed. Pass NULL to use the current dispatch queue. + @param result A SecTrustCallback block which will be executed when the + trust evaluation is complete. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecTrustEvaluateAsync(SecTrustRef trust, + dispatch_queue_t __nullable queue, SecTrustCallback result) + API_DEPRECATED_WITH_REPLACEMENT("SecTrustEvaluateAsyncWithError", + macos(10.7, 10.15), + ios(7.0, 13.0), + watchos(1.0, 6.0), + tvos(7.0, 13.0)); +#endif + +/*! + @function SecTrustEvaluateWithError + @abstract Evaluates a trust reference synchronously. + @param trust A reference to the trust object to evaluate. + @param error A pointer to an error object + @result A boolean value indicating whether the certificate is trusted + @discussion This function will completely evaluate trust before returning, + possibly including network access to fetch intermediate certificates or to + perform revocation checking. Since this function can block during those + operations, you should call it from within a function that is placed on a + dispatch queue, or in a separate thread from your application's main + run loop. + If the certificate is trusted and the result is true, the error will be set to NULL. + If the certificate is not trusted or the evaluation was unable to complete, the result + will be false and the error will be set with a description of the failure. + The error contains a code for the most serious error encountered (if multiple trust + failures occurred). The localized description indicates the certificate with the most + serious problem and the type of error. The underlying error contains a localized + description of each certificate in the chain that had an error and all errors found + with that certificate. + */ +__attribute__((warn_unused_result)) bool +SecTrustEvaluateWithError(SecTrustRef trust, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) + API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); + +#ifdef __BLOCKS__ +/*! + @typedef SecTrustWithErrorCallback + @abstract Delivers the result from an asynchronous trust evaluation. + @param trustRef A reference to the trust object which has been evaluated. + @param result A boolean value indicating whether the certificate is trusted. + @param error An error if the trust evaluation failed. + */ +typedef void (^SecTrustWithErrorCallback)(SecTrustRef trustRef, bool result, CFErrorRef _Nullable error); + +/*! + @function SecTrustEvaluateAsyncWithError + @abstract Evaluates a trust reference asynchronously. + @param trust A reference to the trust object to evaluate. + @param queue A dispatch queue on which the result callback will be executed. Note that this + function MUST be called from that queue. + @param result A SecTrustWithErrorCallback block which will be executed when the trust evaluation + is complete. + The block is guaranteed to be called exactly once when the result code is errSecSuccess, and not + called otherwise. Note that this block may be called synchronously inline if no asynchronous + operations are required. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion If the certificate is trusted, the callback will return a result parameter of true + and the error will be set to NULL. + If the certificate is not trusted or the evaluation was unable to complete, the result parameter + will be false and the error will be set with a description of the failure. The error contains a + code for the most serious error encountered (if multiple trust failures occurred). The localized + description indicates the certificate with the most serious problem and the type of error. The + underlying error contains a localized description of each certificate in the chain that had an + error and all errors found with that certificate. + */ +OSStatus SecTrustEvaluateAsyncWithError(SecTrustRef trust, dispatch_queue_t queue, SecTrustWithErrorCallback result) + API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0)); +#endif /* __BLOCKS__ */ + +/*! + @function SecTrustGetTrustResult + @param trust A reference to a trust object. + @param result A pointer to the result from the most recent call to + SecTrustEvaluate for this trust reference. If SecTrustEvaluate has not been + called or trust parameters have changed, the result is kSecTrustResultInvalid. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function replaces SecTrustGetResult for the purpose of + obtaining the current evaluation result of a given trust reference. + */ +OSStatus SecTrustGetTrustResult(SecTrustRef trust, + SecTrustResultType *result) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0); + +/*! + @function SecTrustCopyPublicKey + @abstract Return the public key for a leaf certificate after it has + been evaluated. + @param trust A reference to the trust object which has been evaluated. + @result The certificate's public key, or NULL if it the public key could + not be extracted (this can happen if the public key algorithm is not + supported). The caller is responsible for calling CFRelease on the + returned key when it is no longer needed. + */ +__nullable +SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + +/*! + @function SecTrustGetCertificateCount + @abstract Returns the number of certificates in an evaluated certificate + chain. + @param trust A reference to a trust object. + @result The number of certificates in the trust chain, including the anchor. + @discussion Important: if the trust reference has not yet been evaluated, + this function will evaluate it first before returning. If speed is critical, + you may want to call SecTrustGetTrustResult first to make sure that a + result other than kSecTrustResultInvalid is present for the trust object. + */ +CFIndex SecTrustGetCertificateCount(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + +/*! + @function SecTrustGetCertificateAtIndex + @abstract Returns a certificate from the trust chain. + @param trust Reference to a trust object. + @param ix The index of the requested certificate. Indices run from 0 + (leaf) to the anchor (or last certificate found if no anchor was found). + The leaf cert (index 0) is always present regardless of whether the trust + reference has been evaluated or not. + @result A SecCertificateRef for the requested certificate. + */ +__nullable +SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + +/*! + @function SecTrustCopyExceptions + @abstract Returns an opaque cookie which will allow future evaluations + of the current certificate to succeed. + @param trust A reference to an evaluated trust object. + @result An opaque cookie which when passed to SecTrustSetExceptions() will + cause a call to SecTrustEvaluate() return kSecTrustResultProceed. This + will happen upon subsequent evaluation of the current certificate unless + some new error starts happening that wasn't being reported when the cookie + was returned from this function (for example, if the certificate expires + then evaluation will start failing again until a new cookie is obtained.) + @discussion Normally this API should only be called once the errors have + been presented to the user and the user decided to trust the current + certificate chain regardless of the errors being presented, for the + current application/server/protocol combination. + */ +CFDataRef SecTrustCopyExceptions(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); + +/*! + @function SecTrustSetExceptions + @abstract Set a trust cookie to be used for evaluating this certificate chain. + @param trust A reference to a trust object. + @param exceptions An exceptions cookie as returned by a call to + SecTrustCopyExceptions() in the past. You may pass NULL to clear any + exceptions which have been previously set on this trust reference. + @result Upon calling SecTrustEvaluate(), any failures that were present at the + time the exceptions object was created are ignored, and instead of returning + kSecTrustResultRecoverableTrustFailure, kSecTrustResultProceed will be returned + (if the certificate for which exceptions was created matches the current leaf + certificate). + @result Returns true if the exceptions cookies was valid and matches the current + leaf certificate, false otherwise. This function will invalidate the existing + trust result, requiring a subsequent evaluation for the newly-set exceptions. + Note that this function returning true doesn't mean the caller can skip calling + SecTrustEvaluate, as there may be new errors since the exceptions cookie was + created (for example, a certificate may have subsequently expired.) + @discussion Clients of this interface will need to establish the context of this + exception to later decide when this exception cookie is to be used. + Examples of this context would be the server we are connecting to, the ssid + of the wireless network for which this cert is needed, the account for which + this cert should be considered valid, and so on. + */ +bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef __nullable exceptions) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); + +/*! + @function SecTrustCopyProperties + @abstract Return a property array for this trust evaluation. + @param trust A reference to a trust object. If the trust has not been + evaluated, the returned property array will be empty. + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. + @discussion This function returns an ordered array of CFDictionaryRef + instances for each certificate in the chain. Indices run from 0 (leaf) to + the anchor (or last certificate found if no anchor was found.) See the + "Trust Property Constants" section for a list of currently defined keys. + */ +__nullable +CFArrayRef SecTrustCopyProperties(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); + +/*! + @function SecTrustCopyResult + @abstract Returns a dictionary containing information about the + evaluated certificate chain for use by clients. + @param trust A reference to a trust object. + @result A dictionary with various fields that can be displayed to the user, + or NULL if no additional info is available or the trust has not yet been + validated. The caller is responsible for calling CFRelease on the value + returned when it is no longer needed. + @discussion Returns a dictionary for the overall trust evaluation. See the + "Trust Result Constants" section for a list of currently defined keys. + */ +__nullable +CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecTrustSetOCSPResponse + @abstract Attach OCSPResponse data to a trust object. + @param trust A reference to a trust object. + @param responseData This may be either a CFData object containing a single + DER-encoded OCSPResponse (per RFC 2560), or a CFArray of these. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Allows the caller to provide OCSPResponse data (which may be + obtained during a TLS/SSL handshake, per RFC 3546) as input to a trust + evaluation. If this data is available, it can obviate the need to contact + an OCSP server for current revocation information. + */ +OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef __nullable responseData) + __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); + +/*! + @function SecTrustSignedCertificateTimestamps + @abstract Attach SignedCertificateTimestamp data to a trust object. + @param trust A reference to a trust object. + @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962). + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Allows the caller to provide SCT data (which may be + obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust + evaluation. + */ +OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef __nullable sctArray) + API_AVAILABLE(macos(10.14.2), ios(12.1.1), tvos(12.1.1), watchos(5.1.1)); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +/* + * Legacy functions (OS X only) + */ +#if TARGET_OS_OSX +#include +#include + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/*! + @typedef SecTrustUserSetting + @abstract Specifies a user-specified trust setting value. + @discussion Deprecated in OS X 10.9. User trust settings are managed by + functions in SecTrustSettings.h (starting with OS X 10.5), and by the + SecTrustCopyExceptions and SecTrustSetExceptions functions (starting with + iOS 4 and OS X 10.9). The latter two functions are recommended for both OS X + and iOS, as they avoid the need to explicitly specify these values. + */ +typedef SecTrustResultType SecTrustUserSetting + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_9, __IPHONE_NA, __IPHONE_NA); + +/*! + @typedef SecTrustOptionFlags + @abstract Options for customizing trust evaluation. + @constant kSecTrustOptionAllowExpired Allow expired certificates. + @constant kSecTrustOptionLeafIsCA Allow CA as leaf certificate. + @constant kSecTrustOptionFetchIssuerFromNet Allow network fetch of CA cert. + @constant kSecTrustOptionAllowExpiredRoot Allow expired roots. + @constant kSecTrustOptionRequireRevPerCert Require positive revocation + check per certificate. + @constant kSecTrustOptionUseTrustSettings Use TrustSettings instead of + anchors. + @constant kSecTrustOptionImplicitAnchors Properly self-signed certs are + treated as anchors implicitly. + */ +typedef CF_OPTIONS(uint32_t, SecTrustOptionFlags) { + kSecTrustOptionAllowExpired = 0x00000001, + kSecTrustOptionLeafIsCA = 0x00000002, + kSecTrustOptionFetchIssuerFromNet = 0x00000004, + kSecTrustOptionAllowExpiredRoot = 0x00000008, + kSecTrustOptionRequireRevPerCert = 0x00000010, + kSecTrustOptionUseTrustSettings = 0x00000020, + kSecTrustOptionImplicitAnchors = 0x00000040 +}; + +/*! + @function SecTrustSetOptions + @abstract Sets optional flags for customizing a trust evaluation. + @param trustRef A trust reference. + @param options Flags to change evaluation behavior for this trust. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is not available on iOS. Use SecTrustSetExceptions + and SecTrustCopyExceptions to modify default trust results, and + SecTrustSetNetworkFetchAllowed to specify whether missing CA certificates + can be fetched from the network. + */ +OSStatus SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +/*! + @function SecTrustSetParameters + @abstract Sets the action and action data for a trust object. + @param trustRef The reference to the trust to change. + @param action A trust action. + @param actionData A reference to data associated with this action. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in OS X 10.7 and later, where it + was replaced by SecTrustSetOptions, and is not available on iOS. Your code + should use SecTrustSetExceptions and SecTrustCopyExceptions to modify default + trust results, and SecTrustSetNetworkFetchAllowed to specify whether missing + CA certificates can be fetched from the network. + */ +OSStatus SecTrustSetParameters(SecTrustRef trustRef, + CSSM_TP_ACTION action, CFDataRef actionData) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustSetKeychains + @abstract Sets the keychains for a given trust object. + @param trust A reference to a trust object. + @param keychainOrArray A reference to an array of keychains to search, a + single keychain, or NULL to use the default keychain search list. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in macOS 10.13 and later. Beginning in + macOS 10.12, this function no longer affected the behavior of the trust + evaluation: the user's keychain search list and the system + anchors keychain are searched for certificates to complete the chain. To change + the keychains that are searched, callers must use SecKeychainSetSearchList to + change the user's keychain search list. + Note: this function was never applicable to iOS. + */ +OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef __nullable keychainOrArray) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustGetResult + @abstract Returns detailed information on the outcome of an evaluation. + @param trustRef A reference to a trust object. + @param result A pointer to the result from the call to SecTrustEvaluate. + @param certChain On return, a pointer to the certificate chain used to + validate the input certificate. Call the CFRelease function to release + this pointer. + @param statusChain On return, a pointer to the status of the certificate + chain. Do not attempt to free this pointer; it remains valid until the + trust is destroyed or the next call to SecTrustEvaluate. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in OS X 10.7 and later, + and is not available on iOS. + To get the complete certificate chain, use SecTrustGetCertificateCount and + SecTrustGetCertificateAtIndex. To get detailed status information for each + certificate, use SecTrustCopyProperties. To get the overall trust result + for the evaluation, use SecTrustGetTrustResult. + */ +OSStatus SecTrustGetResult(SecTrustRef trustRef, SecTrustResultType * __nullable result, + CFArrayRef * __nullable CF_RETURNS_RETAINED certChain, CSSM_TP_APPLE_EVIDENCE_INFO * __nullable * __nullable statusChain) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustGetCssmResult + @abstract Gets the CSSM trust result. + @param trust A reference to a trust. + @param result On return, a pointer to the CSSM trust result. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in OS X 10.7 and later, + and is not available on iOS. + To get detailed status information for each certificate, use + SecTrustCopyProperties. To get the overall trust result for the evaluation, + use SecTrustGetTrustResult. + */ +OSStatus SecTrustGetCssmResult(SecTrustRef trust, + CSSM_TP_VERIFY_CONTEXT_RESULT_PTR __nullable * __nonnull result) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustGetCssmResultCode + @abstract Gets the result code from the most recent call to SecTrustEvaluate + for the specified trust. + @param trust A reference to a trust. + @param resultCode On return, the result code produced by the most recent + evaluation of the given trust (cssmerr.h). The value of resultCode is + undefined if SecTrustEvaluate has not been called. + @result A result code. See "Security Error Codes" (SecBase.h). Returns + errSecTrustNotAvailable if SecTrustEvaluate has not been called for the + specified trust. + @discussion This function is deprecated in OS X 10.7 and later, + and is not available on iOS. + To get detailed status information for each certificate, use + SecTrustCopyProperties. To get the overall trust result for the evaluation, + use SecTrustGetTrustResult. + */ +OSStatus SecTrustGetCssmResultCode(SecTrustRef trust, OSStatus *resultCode) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustGetTPHandle + @abstract Gets the CSSM trust handle + @param trust A reference to a trust. + @param handle On return, a CSSM trust handle. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is deprecated in OS X 10.7 and later. + */ +OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustCopyAnchorCertificates + @abstract Returns an array of default anchor (root) certificates used by + the system. + @param anchors On return, an array containing the system's default anchors + (roots). Call the CFRelease function to release this pointer. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function is not available on iOS, as certificate data + for system-trusted roots is currently unavailable on that platform. + */ +OSStatus SecTrustCopyAnchorCertificates(CFArrayRef * __nonnull CF_RETURNS_RETAINED anchors) + __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ + +__END_DECLS + +#endif /* !_SECURITY_SECTRUST_H_ */ diff --git a/trust/headers/SecTrustPriv.h b/trust/headers/SecTrustPriv.h new file mode 100644 index 00000000..5bf6e60b --- /dev/null +++ b/trust/headers/SecTrustPriv.h @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecTrustPriv + The functions and data types in SecTrustPriv implement trust computation + and allow the user to apply trust decisions to the trust configuration. + */ + +#ifndef _SECURITY_SECTRUSTPRIV_H_ +#define _SECURITY_SECTRUSTPRIV_H_ + +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +/* Constants used as keys in property lists. See + SecTrustCopySummaryPropertiesAtIndex for more information. */ +extern const CFStringRef kSecPropertyKeyType; +extern const CFStringRef kSecPropertyKeyLabel; +extern const CFStringRef kSecPropertyKeyLocalizedLabel; +extern const CFStringRef kSecPropertyKeyValue; + +extern const CFStringRef kSecPropertyTypeWarning; +extern const CFStringRef kSecPropertyTypeSuccess; +extern const CFStringRef kSecPropertyTypeSection; +extern const CFStringRef kSecPropertyTypeData; +extern const CFStringRef kSecPropertyTypeString; +extern const CFStringRef kSecPropertyTypeURL; +extern const CFStringRef kSecPropertyTypeDate; +extern const CFStringRef kSecPropertyTypeArray; +extern const CFStringRef kSecPropertyTypeNumber; + +/* Constants used as keys in the dictionary returned by SecTrustCopyInfo. */ +extern const CFStringRef kSecTrustInfoExtendedValidationKey; +extern const CFStringRef kSecTrustInfoCompanyNameKey; +extern const CFStringRef kSecTrustInfoRevocationKey; +extern const CFStringRef kSecTrustInfoRevocationValidUntilKey; +extern const CFStringRef kSecTrustInfoCertificateTransparencyKey; + +/* Constants used as keys in the certificate details dictionary. + An array of per-certificate details is returned by SecTrustCopyResult + as the value of the kSecTrustResultDetails key. +*/ +extern const CFStringRef kSecCertificateDetailStatusCodes; + /*__OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);*/ + +/*! + @enum Trust Result Constants + @discussion Predefined key constants used to obtain values in a + dictionary of trust evaluation results for a certificate chain, + as retrieved from a call to SecTrustCopyResult. + + @constant kSecTrustResultDetails + This key will be present if a trust evaluation has been performed. + Its value is a CFArrayRef of CFDictionaryRef representing detailed + status info for each certificate in the completed chain. + @constant kSecTrustRevocationReason + This key will be present iff this chain had its revocation checked, + and a "revoked" response was received. The value of this key will + be a CFNumberRef indicating the reason for revocation. The possible + reason code values are described in RFC 5280, section 5.3.1. + */ +extern const CFStringRef kSecTrustResultDetails; + /*__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_9_0);*/ +extern const CFStringRef kSecTrustRevocationReason; + /*__OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);*/ + +/*! + @function SecTrustCopySummaryPropertiesAtIndex + @abstract Return a property array for the certificate. + @param trust A reference to the trust object to evaluate. + @param ix The index of the requested certificate. Indices run from 0 + (leaf) to the anchor (or last certificate found if no anchor was found). + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. This function returns a + short summary description of the certificate in question. The property + at index 0 of the array might also include general information about the + entire chain's validity in the context of this trust evaluation. + + @discussion Returns a property array for this trust certificate. A property + array is an array of CFDictionaryRefs. Each dictionary (we call it a + property for short) has the following keys: + + kSecPropertyKeyType This key's value determines how this property + should be displayed. Its associated value is one of the + following: + kSecPropertyTypeWarning + The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not + set. The kSecPropertyKeyValue is a CFStringRef which should + be displayed in yellow with a warning triangle. + kSecPropertyTypeError + The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not + set. The kSecPropertyKeyValue is a CFStringRef which should + be displayed in red with an error X. + kSecPropertyTypeSuccess + The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not + set. The kSecPropertyKeyValue is a CFStringRef which should + be displayed in green with a checkmark in front of it. + kSecPropertyTypeTitle + The kSecPropertyKeyLocalizedLabel and kSecPropertyKeyLabel keys are not + set. The kSecPropertyKeyValue is a CFStringRef which should + be displayed in a larger bold font. + kSecPropertyTypeSection + The optional kSecPropertyKeyLocalizedLabel is a CFStringRef with the name + of the next section to display. The value of the + kSecPropertyKeyValue key is a CFArrayRef which is a property + array as defined here. + kSecPropertyTypeData + The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing + the localized label for the value for the kSecPropertyKeyValue. + The type of this value is a CFDataRef. Its contents should be + displayed as: "bytes length_of_data : hexdump_of_data". Ideally + the UI will only show one line of hex dump data and have a + disclosure arrow to see the remainder. + kSecPropertyTypeString + The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing + the localized label for the value for the kSecPropertyKeyValue. + The type of this value is a CFStringRef. It's contents should be + displayed in the normal font. + kSecPropertyTypeURL + The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing + the localized label for the value for the kSecPropertyKeyValue. + The type of this value is a CFURLRef. It's contents should be + displayed as a hyperlink. + kSecPropertyTypeDate + The optional kSecPropertyKeyLocalizedLabel is a CFStringRef containing + the localized label for the value for the kSecPropertyKeyValue. + The type of this value is a CFDateRef. It's contents should be + displayed in human readable form (probably in the current + timezone). + kSecPropertyKeyLocalizedLabel + Human readable localized label for a given property. + kSecPropertyKeyValue + See description of kSecPropertyKeyType to determine what the value + for this key is. + kSecPropertyKeyLabel + Non localized key (label) for this value. This is only + present for properties with fixed label names. + @result A property array. It is the caller's responsability to CFRelease + the returned array when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix); + +/*! + @function SecTrustCopyDetailedPropertiesAtIndex + @abstract Return a property array for the certificate. + @param trust A reference to the trust object to evaluate. + @param ix The index of the requested certificate. Indices run from 0 + (leaf) to the anchor (or last certificate found if no anchor was found). + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. + See SecTrustCopySummaryPropertiesAtIndex on how to intepret this array. + Unlike that function call this function returns a detailed description + of the certificate in question. + */ +__nullable CF_RETURNS_RETAINED +CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix); + +/*! + @function SecTrustCopyInfo + @abstract Return a dictionary with additional information about the + evaluated certificate chain for use by clients. + @param trust A reference to an evaluated trust object. + @discussion Returns a dictionary for this trust evaluation. This + dictionary may have the following keys: + + kSecTrustInfoExtendedValidationKey this key will be present and have + a value of kCFBooleanTrue if this chain was validated for EV. + kSecTrustInfoCompanyNameKey Company name field of subject of leaf + certificate, this field is meant to be displayed to the user + if the kSecTrustInfoExtendedValidationKey is present. + kSecTrustInfoRevocationKey this key will be present iff this chain + had its revocation checked. The value will be a kCFBooleanTrue + if revocation checking was successful and none of the + certificates in the chain were revoked. + The value will be kCFBooleanFalse if no current revocation status + could be obtained for one or more certificates in the chain due + to connection problems or timeouts etc. This is a hint to a + client to retry revocation checking at a later time. + kSecTrustInfoRevocationValidUntilKey this key will be present iff + kSecTrustInfoRevocationKey has a value of kCFBooleanTrue. + The value will be a CFDateRef representing the earliest date at + which the revocation info for one of the certificates in this chain + might change. + + @result A dictionary with various fields that can be displayed to the user, + or NULL if no additional info is available or the trust has not yet been + validated. The caller is responsible for calling CFRelease on the value + returned when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust); + +/* For debugging purposes. */ +__nullable +CFArrayRef SecTrustGetDetails(SecTrustRef trust); + +__nullable CF_RETURNS_RETAINED +CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust); + +/*! + @function SecTrustIsExpiredOnly + @abstract Determine whether expiration is the only problem with a certificate chain. + @param trust A reference to a trust object. + @result A boolean value indicating whether expiration is the only problem found + with the certificate chain in the given trust reference. + @discussion Returns true if one or more certificates in the chain have expired, + expiration is an error (i.e. it is not being ignored by existing trust settings), + and it is the only error encountered. Returns false if the certificate(s) have not + expired, or are expired but have trust settings to override their expiration, + or if the trust chain has other errors beside expiration. Your code should call + this function after SecTrustEvaluate has returned a recoverable trust failure, + so you can distinguish this case from other possible errors. + */ +Boolean SecTrustIsExpiredOnly(SecTrustRef trust) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/* For debugging purposes. */ +__nullable CF_RETURNS_RETAINED +CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust); + +/* + @function SecTrustGetTrustStoreVersionNumber + @abstract Ask trustd what trust store version it is using. + @param error A returned error if trustd failed to answer. + @result The current version of the trust store. 0 upon failure. + */ +uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + +/* + @function SecTrustGetAssetVersionNumber + @abstract Ask trustd what asset version it is using. + @param error A returned error if trustd failed to answer. + @result The current version of the asset. 0 upon failure. + */ +uint64_t SecTrustGetAssetVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + +/* + @function SecTrustOTAPKIGetUpdatedAsset + @abstract Trigger trustd to fetch a new trust supplementals asset right now. + @param error A returned error if trustd failed to update the asset. + @result The current version of the update, regardless of the success of the update. + @discussion This function blocks up to 1 minute until trustd has finished with the + asset download and update. You should use the error parameter to determine whether + the update was was successful. The current asset version is always returned. + */ +uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + +/* + @function SecTrustOTASecExperimentGetUpdatedAsset + @abstract Trigger trustd to fetch a new SecExperiment asset right now. + @param error A returned error if trustd failed to update the asset. + @result The current version of the update, regardless of the success of the update. + @discussion This function blocks up to 1 minute until trustd has finished with the + asset download and update. You should use the error parameter to determine whether + the update was was successful. The current asset version is always returned. + */ +uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + +/* + @function SecTrustOTASecExperimentCopyAsset + @abstract Get current asset from trustd + @param error A returned error if trustd fails to return asset + @result Dictionary of asset + @discussion If the error parameter is supplied, and the function returns false, + the caller is subsequently responsible for releasing the returned CFErrorRef. + */ +CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + +/*! + @function SecTrustFlushResponseCache + @abstract Removes all OCSP responses from the per-user response cache. + @param error An optional pointer to an error object + @result A boolean value indicating whether the operation was successful. + @discussion If the error parameter is supplied, and the function returns false, + the caller is subsequently responsible for releasing the returned CFErrorRef. + */ +Boolean SecTrustFlushResponseCache(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) + __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); + +/*! + @function SecTrustSetTrustedLogs + @abstract Sets the trusted CT logs for a given trust. + @param trust A reference to a trust object. + @param trustedLogs An array of trusted logs. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion trustedLog is a CFArray of CFData containing the DER-encode SubjectPublicKeyInfo + of the trusted CT logs. + */ +OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs); + +/* Keychain searches are allowed by default. Use this to turn off seaching of + -keychain search list (i.e. login.keychain, system.keychain) + -Local Items/iCloud Keychain + -user- and admin-trusted roots + -network-fetched issuers + User must provide all necessary certificates in the input certificates and/or anchors. */ +OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/* Get the keychain search policy for the trust object. */ +OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean * __nonnull allowed) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecTrustEvaluateLeafOnly + @abstract Evaluates the leaf of the trust reference synchronously. + @param trust A reference to the trust object to evaluate. + @param result A pointer to a result type. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function will only evaluate the trust of the leaf certificate. + No chain will be built and only those aspects of the SecPolicyRef that address + the expected contents of the leaf will be checked. This function does not honor + any set exceptions or usage constraints. + */ +OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType * __nonnull result) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecTrustSerialize + @abstract Creates a serialized version of the trust object + @param trust A reference to the trust object to serialize. + @param error A pointer to an error. + @result The serialized trust object. + @discussion This function is intended to be used to share SecTrustRefs between + processes. Saving the results to disk or sending them over network channels + may cause unexpected behavior. + */ +__nullable CF_RETURNS_RETAINED +CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecTrustDeserialize + @abstract Creates a trust object from the serialized data + @param serializedTrust A reference to the serialized trust object + @param error A pointer to an error. + @result A trust object + @discussion This function is intended to be used to share SecTrustRefs between + processes. Saving the results to disk or sending them over network channels + may cause unexpected behavior. + */ +__nullable CF_RETURNS_RETAINED +SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecTrustGetTrustExceptionsArray + @abstract Return the exceptions array currently set in the trust object + @param trust A reference to the trust object + @result The array of exceptions. + @discussion This function returns an array of exceptions that was previously set + using SecTrustSetExceptions, unlike SecTrustCopyExceptions which returns the + exceptions which could be set using SecTrustSetExceptions. + */ +__nullable CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); + +/*! + @function SecTrustCopyInputCertificates + @abstract Return the array of certificates currently set in the trust object + @param trust A reference to the trust object + @param certificates On return, an array of the certificates used by this trust. + Call the CFRelease function to release this reference. + @result A result code. See "Security Error Codes" (SecBase.h) +*/ +OSStatus SecTrustCopyInputCertificates(SecTrustRef trust, CFArrayRef * _Nonnull CF_RETURNS_RETAINED certificates) +__OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); + +/*! + @function SecTrustAddToInputCertificates + @abstract Add certificate(s) to the currently set certificates in the trust object + @param trust A reference to the trust object + @param certificates The group of certificates to add. This can either be a CFArrayRef + of SecCertificateRef objects or a single SecCertificateRef. + @result A result code. See "Security Error Codes" (SecBase.h) + */ +OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef _Nonnull certificates) + __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); + +/*! + @function SecTrustSetPinningPolicyName + @abstract Set the policy name to be used during the trust evaluation. + @param trust A reference to the trust object + @param policyName A string representing the name of the pinning policy to be used. + @result A result code. See "Security Error Codes" (SecBase.h) + @discussion This function permits the caller to enable the dynamic lookup of the + pinning policy using a built-in database as an alternative to using a SecPolicyCreate function + with the pinning rules and calling SecTrustCreateWithCertificates or SecTrustSetPolicies. + */ +OSStatus SecTrustSetPinningPolicyName(SecTrustRef trust, CFStringRef policyName) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecTrustSetPinningException + @abstract Remove pinning requirement from this trust evaluation + @param trust A reference to the trust object + @result A result code. See "Security Error Codes" (SecBase.h) + @discussion This function provides an exception for this particular trust for a bundle that + otherwise requires pinning for all connections. Bundles use the SecTrustPinningRequired key + with boolean value of true in their info plist to indicate that all SSL connections from the + bundle must be pinned. + */ +OSStatus SecTrustSetPinningException(SecTrustRef trust) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +#if TARGET_OS_IPHONE +/*! + @function SecTrustGetExceptionResetCount + @abstract Returns the current epoch of trusted exceptions. + @param error A pointer to an error. + @result An unsigned 64-bit integer representing the current epoch. + @discussion Exceptions tagged with an older epoch are not trusted. + */ +uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error) + API_UNAVAILABLE(macos, iosmac) API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0)); + +/*! + @function SecTrustIncrementExceptionResetCount + @abstract Increases the current epoch of trusted exceptions by 1. + @param error A pointer to an error. + @result A result code. See "Security Error Codes" (SecBase.h) + @discussion By increasing the current epoch any existing exceptions, tagged with the old epoch, become distrusted. + */ +OSStatus SecTrustIncrementExceptionResetCount(CFErrorRef *error) + __API_UNAVAILABLE(macos, iosmac) __API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0)); +#endif + +#ifdef __BLOCKS__ +/*! + @function SecTrustEvaluateFastAsync + @abstract Evaluates a trust reference asynchronously. + @param trust A reference to the trust object to evaluate. + @param queue A dispatch queue on which the result callback will be + executed. Note that this function MUST be called from that queue. + @param result A SecTrustCallback block which will be executed when the + trust evaluation is complete. The block is guaranteed to be called exactly once + when the result code is errSecSuccess, and not called otherwise. Note that this + block may be called synchronously inline if no asynchronous operations are required. + @result A result code. See "Security Error Codes" (SecBase.h). + */ +OSStatus SecTrustEvaluateFastAsync(SecTrustRef trust, dispatch_queue_t queue, SecTrustCallback result) + __API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)); +#endif + +/*! + @function SecTrustReportTLSAnalytics + @discussion This function MUST NOT be called outside of the TLS stack. +*/ +bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) + __API_AVAILABLE(macos(10.13.4), ios(11.3), tvos(11.3), watchos(4.3)); + +/*! + @function SecTrustReportNetworkingAnalytics + @discussion This function MUST NOT be called outside of the networking stack. +*/ +bool SecTrustReportNetworkingAnalytics(const char *eventName, xpc_object_t eventAttributes) + __API_AVAILABLE(macos(10.15), ios(13), tvos(13), watchos(5)); + +/*! + @function SecTrustSetNeedsEvaluation + @abstract Reset the evaluation state of the trust object + @param trust Trust object to reset + @discussion Calling this will reset the trust object so that the next time SecTrustEvaluate* + is called, a new trust evaluation is performed. SecTrustSet* interfaces implicitly call this, + so this function is only necessary if you've made system configuration changes (like trust + settings) that don't impact the trust object itself. + */ +void SecTrustSetNeedsEvaluation(SecTrustRef trust); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +/* + * Legacy functions (OS X only) + */ +#if TARGET_OS_OSX + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +#if SEC_OS_IPHONE +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfour-char-constants" +#endif /* SEC_OS_IPHONE */ +/* + unique keychain item attributes for user trust records. + */ +enum { + kSecTrustCertAttr = 'tcrt', + kSecTrustPolicyAttr = 'tpol', + /* Leopard and later */ + kSecTrustPubKeyAttr = 'tpbk', + kSecTrustSignatureAttr = 'tsig' +}; + +#if SEC_OS_IPHONE +#pragma clang diagnostic pop +#endif /* SEC_OS_IPHONE */ + +/*! + @function SecTrustGetUserTrust + @abstract Gets the user-specified trust settings of a certificate and policy. + @param certificate A reference to a certificate. + @param policy A reference to a policy. + @param trustSetting On return, a pointer to the user specified trust settings. + @result A result code. See "Security Error Codes" (SecBase.h). + @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. + */ +OSStatus SecTrustGetUserTrust(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting * __nullable trustSetting) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustSetUserTrust + @abstract Sets the user-specified trust settings of a certificate and policy. + @param certificate A reference to a certificate. + @param policy A reference to a policy. + @param trustSetting The user-specified trust settings. + @result A result code. See "Security Error Codes" (SecBase.h). + @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. + @discussion as of Mac OS version 10.5, this will result in a call to + SecTrustSettingsSetTrustSettings(). + */ +OSStatus SecTrustSetUserTrust(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting trustSetting) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustSetUserTrustLegacy + @abstract Sets the user-specified trust settings of a certificate and policy. + @param certificate A reference to a certificate. + @param policy A reference to a policy. + @param trustSetting The user-specified trust settings. + @result A result code. See "Security Error Codes" (SecBase.h). + + @This is the private version of what used to be SecTrustSetUserTrust(); it operates + on UserTrust entries as that function used to. The current SecTrustSetUserTrust() + function operated on Trust Settings. + */ +OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef __nullable certificate, SecPolicyRef __nullable policy, SecTrustUserSetting trustSetting) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustGetCSSMAnchorCertificates + @abstract Retrieves the CSSM anchor certificates. + @param cssmAnchors A pointer to an array of anchor certificates. + @param cssmAnchorCount A pointer to the number of certificates in anchors. + @result A result code. See "Security Error Codes" (SecBase.h). + @availability Mac OS X version 10.4. Deprecated in Mac OS X version 10.5. + */ +OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA * __nullable * __nullable cssmAnchors, uint32 *cssmAnchorCount) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_NA, __IPHONE_NA); + +/*! + @function SecTrustCopyExtendedResult + @abstract Gets the extended trust result after an evaluation has been performed. + @param trust A trust reference. + @param result On return, result points to a CFDictionaryRef containing extended trust results (if no error occurred). + The caller is responsible for releasing this dictionary with CFRelease when finished with it. + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion This function may only be used after SecTrustEvaluate has been called for the trust reference, otherwise + errSecTrustNotAvailable is returned. If the certificate is not an extended validation certificate, there is + no extended result data and errSecDataNotAvailable is returned. Currently, only one dictionary key is defined + (kSecEVOrganizationName). + + Note: this function will be deprecated in a future release of OS X. Your + code should use SecTrustCopyResult to obtain the trust results dictionary. + */ +OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef * __nonnull CF_RETURNS_RETAINED result) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12, __IPHONE_NA, __IPHONE_NA); + +/* + * Preference-related strings for Revocation policies. + */ + +/* + * Preference domain, i.e., the name of a plist in ~/Library/Preferences or in + * /Library/Preferences + */ +#define kSecRevocationDomain "com.apple.security.revocation" + +/* OCSP and CRL style keys, followed by values used for both of them */ +#define kSecRevocationOcspStyle CFSTR("OCSPStyle") +#define kSecRevocationCrlStyle CFSTR("CRLStyle") +#define kSecRevocationOff CFSTR("None") +#define kSecRevocationBestAttempt CFSTR("BestAttempt") +#define kSecRevocationRequireIfPresent CFSTR("RequireIfPresent") +#define kSecRevocationRequireForAll CFSTR("RequireForAll") + +/* Which first if both enabled? */ +#define kSecRevocationWhichFirst CFSTR("RevocationFirst") +#define kSecRevocationOcspFirst CFSTR("OCSP") +#define kSecRevocationCrlFirst CFSTR("CRL") + +/* boolean: A "this policy is sufficient per cert" for each */ +#define kSecRevocationOCSPSufficientPerCert CFSTR("OCSPSufficientPerCert") +#define kSecRevocationCRLSufficientPerCert CFSTR("CRLSufficientPerCert") + +/* local OCSP responder URI, value arbitrary string value */ +#define kSecOCSPLocalResponder CFSTR("OCSPLocalResponder") + +/* Extended trust result keys (now in public API) */ +#define kSecEVOrganizationName kSecTrustOrganizationName +#define kSecTrustExpirationDate kSecTrustRevocationValidUntilDate + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +#endif /* TARGET_OS_MAC && !TARGET_OS_IPHONE */ + +__END_DECLS + +#endif /* !_SECURITY_SECTRUSTPRIV_H_ */ diff --git a/trust/headers/SecTrustSettings.h b/trust/headers/SecTrustSettings.h new file mode 100644 index 00000000..48a2eb74 --- /dev/null +++ b/trust/headers/SecTrustSettings.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2006,2007,2011,2012,2014-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecTrustSettings + The functions and data types in SecTrustSettings implement a way to + set and retrive trustability of certificates. +*/ + +#ifndef _SECURITY_SECTRUSTSETTINGS_H_ +#define _SECURITY_SECTRUSTSETTINGS_H_ + +#include +#include +#include +#include + +#if SEC_OS_OSX +#include +#include +#include +#endif /* SEC_OS_OSX */ + +__BEGIN_DECLS + +#if SEC_OS_OSX_INCLUDES +CF_ASSUME_NONNULL_BEGIN +#endif + +/* + * Any certificate (cert) which resides in a keychain can have associated with + * it a set of Trust Settings. Trust Settings specify conditions in which a + * given cert can be trusted or explicitly distrusted. A "trusted" cert is + * either a root (self-signed) cert that, when a cert chain verifies back to that + * root, the entire cert chain is trusted; or a non-root cert that does not need + * to verify to a trusted root cert (which is normally the case when verifying a + * cert chain). An "explicitly distrusted" cert is one which will, when encountered + * during the evaluation of a cert chain, cause immediate and unconditional failure + * of the verify operation. + * + * Trust Settings are configurable by the user; they can apply on three levels + * (called domains): + * + * -- Per-user. + * -- Locally administered, system-wide. Administrator privileges are required + * to make changes to this domain. + * -- System. These Trust Settings are immutable and comprise the set of trusted + * root certificates supplied in Mac OS X. + * + * Per-user Trust Settings override locally administered Trust Settings, which + * in turn override the System Trust Settings. + * + * Each cert's Trust Settings are expressed as a CFArray which includes any + * number (including zero) of CFDictionaries, each of which comprises one set of + * Usage Constraints. Each Usage Constraints dictionary contains zero or one of + * each the following components: + * + * key = kSecTrustSettingsPolicy On OSX, value = SecPolicyRef + On iOS, value = policy OID as CFString + * + * key = kSecTrustSettingsApplication value = SecTrustedApplicationRef + * key = kSecTrustSettingsPolicyString value = CFString, policy-specific + * key = kSecTrustSettingsKeyUsage value = CFNumber, an SInt32 key usage + * + * A given Usage Constraints dictionary applies to a given cert if *all* of the + * usage constraint components specified in the dictionary match the usage of + * the cert being evaluated; when this occurs, the value of the + * kSecTrustSettingsResult entry in the dictionary, shown below, is the effective + * trust setting for the cert. + * + * key = kSecTrustSettingsResult value = CFNumber, an SInt32 SecTrustSettingsResult + * + * The overall Trust Settings of a given cert are the sum of all such Usage + * Constraints CFDictionaries: Trust Settings for a given usage apply if *any* + * of the CFDictionaries in the cert's Trust Settings array satisfies + * the specified usage. Thus, when a cert has multiple Usage Constraints + * dictionaries in its Trust Settings array, the overall Trust Settings + * for the cert are + * + * (Usage Constraint 0 component 0 AND Usage Constraint 0 component 1 ...) + * -- OR -- + * (Usage Constraint 1 component 0 AND Usage Constraint 1 component 1 ...) + * -- OR -- + * ... + * + * Notes on the various Usage Constraints components: + * + * kSecTrustSettingsPolicy Specifies a cert verification policy, e.g., SSL, + * SMIME, etc, using Policy Constants + * kSecTrustSettingsApplication Specifies the application performing the cert + * verification. + * kSecTrustSettingsPolicyString Policy-specific. For the SMIME policy, this is + * an email address. + * For the SSL policy, this is a host name. + * kSecTrustSettingsKeyUsage A bitfield indicating key operations (sign, + * encrypt, etc.) for which this Usage Constraint + * apply. Values are defined below as the + * SecTrustSettingsKeyUsage enum. + * kSecTrustSettingsResult The resulting trust value. If not present this has a + * default of kSecTrustSettingsResultTrustRoot, meaning + * "trust this root cert". Other legal values are: + * kSecTrustSettingsResultTrustAsRoot : trust non-root + * cert as if it were a trusted root. + * kSecTrustSettingsResultDeny : explicitly distrust this + * cert. + * kSecTrustSettingsResultUnspecified : neither trust nor + * distrust; can be used to specify an "Allowed error" + * (see below) without assigning trust to a specific + * cert. + * + * Another optional component in a Usage Constraints dictionary is a CSSM_RETURN + * which, if encountered during certificate verification, is ignored for that + * cert. These "allowed error" values are constrained by Usage Constraints as + * described above; a Usage Constraint dictionary with no constraints but with + * an Allowed Error value causes that error to always be allowed when the cert + * is being evaluated. + * + * The "allowed error" entry in a Usage Constraints dictionary is formatted + * as follows: + * + * key = kSecTrustSettingsAllowedError value = CFNumber, an SInt32 CSSM_RETURN + * + * Note that if kSecTrustSettingsResult value of kSecTrustSettingsResultUnspecified + * is *not* present for a Usage Constraints dictionary with no Usage + * Constraints, the default of kSecTrustSettingsResultTrustRoot is assumed. To + * specify a kSecTrustSettingsAllowedError without explicitly trusting (or + * distrusting) the associated cert, specify kSecTrustSettingsResultUnspecified + * for the kSecTrustSettingsResult component. + * + * Note that an empty Trust Settings array means "always trust this cert, + * with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot". + * An empty Trust Settings array is definitely not the same as *no* Trust + * Settings, which means "this cert must be verified to a known trusted cert". + * + * Note the distinction between kSecTrustSettingsResultTrustRoot and + * kSecTrustSettingsResultTrustAsRoot; the former can only be applied to + * root (self-signed) certs; the latter can only be applied to non-root + * certs. This also means that an empty TrustSettings array for a non-root + * cert is invalid, since the default value for kSecTrustSettingsResult is + * kSecTrustSettingsResultTrustRoot, which is invalid for a non-root cert. + * + * Authentication + * -------------- + * + * When making changes to the per-user Trust Settings, the user will be + * prompted with an alert panel asking for authentication via user name a + * password (or other credentials normally used for login). This means + * that it is not possible to modify per-user Trust Settings when not + * running in a GUI environment (i.e. the user is not logged in via + * Loginwindow). + * + * When making changes to the system-wide Trust Settings, the user will be + * prompted with an alert panel asking for an administrator's name and + * password, unless the calling process is running as root in which case + * no futher authentication is needed. + */ + +/* + * The keys in one Usage Constraints dictionary. + */ +#define kSecTrustSettingsPolicy CFSTR("kSecTrustSettingsPolicy") +#define kSecTrustSettingsApplication CFSTR("kSecTrustSettingsApplication") +#define kSecTrustSettingsPolicyString CFSTR("kSecTrustSettingsPolicyString") +#define kSecTrustSettingsKeyUsage CFSTR("kSecTrustSettingsKeyUsage") +#define kSecTrustSettingsAllowedError CFSTR("kSecTrustSettingsAllowedError") +#define kSecTrustSettingsResult CFSTR("kSecTrustSettingsResult") + +/* + * Key usage bits, the value for Usage Constraints key kSecTrustSettingsKeyUsage. + */ +typedef CF_OPTIONS(uint32_t, SecTrustSettingsKeyUsage) { + /* sign/verify data */ + kSecTrustSettingsKeyUseSignature = 0x00000001, + /* bulk encryption */ + kSecTrustSettingsKeyUseEnDecryptData = 0x00000002, + /* key wrap/unwrap */ + kSecTrustSettingsKeyUseEnDecryptKey = 0x00000004, + /* sign/verify cert */ + kSecTrustSettingsKeyUseSignCert = 0x00000008, + /* sign/verify CRL and OCSP */ + kSecTrustSettingsKeyUseSignRevocation = 0x00000010, + /* key exchange, e.g., Diffie-Hellman */ + kSecTrustSettingsKeyUseKeyExchange = 0x00000020, + /* any usage (the default if this value is not specified) */ + kSecTrustSettingsKeyUseAny = 0xffffffff +}; + +/*! + @enum SecTrustSettingsResult + @abstract Result of a trust settings evaluation. +*/ +typedef CF_ENUM(uint32_t, SecTrustSettingsResult) { + kSecTrustSettingsResultInvalid = 0, /* Never valid in a Trust Settings array or + * in an API call. */ + kSecTrustSettingsResultTrustRoot, /* Root cert is explicitly trusted */ + kSecTrustSettingsResultTrustAsRoot, /* Non-root cert is explicitly trusted */ + kSecTrustSettingsResultDeny, /* Cert is explicitly distrusted */ + kSecTrustSettingsResultUnspecified /* Neither trusted nor distrusted; evaluation + * proceeds as usual */ +}; + +/* + * Specify user, local administrator, or system domain Trust Settings. + * Note that kSecTrustSettingsDomainSystem settings are read-only, even by + * root. + */ +typedef CF_ENUM(uint32_t, SecTrustSettingsDomain) { + kSecTrustSettingsDomainUser = 0, + kSecTrustSettingsDomainAdmin, + kSecTrustSettingsDomainSystem +}; + +/* + * This constant is deprecated and ineffective as of macOS 10.12. + * Please discontinue use. + */ +#define kSecTrustSettingsDefaultRootCertSetting ((SecCertificateRef)-1) + +#if SEC_OS_OSX_INCLUDES +/* + * Obtain Trust Settings for specified cert. + * Caller must CFRelease() the returned CFArray. + * Returns errSecItemNotFound if no Trust settings exist for the cert. + */ +OSStatus SecTrustSettingsCopyTrustSettings( + SecCertificateRef certRef, + SecTrustSettingsDomain domain, + CFArrayRef * __nonnull CF_RETURNS_RETAINED trustSettings); /* RETURNED */ + +/* + * Specify Trust Settings for specified cert. If specified cert + * already has Trust Settings in the specified domain, they will + * be replaced. + * The trustSettingsDictOrArray parameter is either a CFDictionary, + * a CFArray of them, or NULL. NULL indicates "always trust this + * root cert regardless of usage". + */ +OSStatus SecTrustSettingsSetTrustSettings( + SecCertificateRef certRef, + SecTrustSettingsDomain domain, + CFTypeRef __nullable trustSettingsDictOrArray); + +/* + * Delete Trust Settings for specified cert. + * Returns errSecItemNotFound if no Trust settings exist for the cert. + */ +OSStatus SecTrustSettingsRemoveTrustSettings( + SecCertificateRef certRef, + SecTrustSettingsDomain domain); + +/* + * Obtain an array of all certs which have Trust Settings in the + * specified domain. Elements in the returned certArray are + * SecCertificateRefs. + * Caller must CFRelease() the returned array. + * Returns errSecNoTrustSettings if no trust settings exist + * for the specified domain. + */ +OSStatus SecTrustSettingsCopyCertificates( + SecTrustSettingsDomain domain, + CFArrayRef * __nullable CF_RETURNS_RETAINED certArray); + +/* + * Obtain the time at which a specified cert's Trust Settings + * were last modified. Caller must CFRelease the result. + * Returns errSecItemNotFound if no Trust Settings exist for specified + * cert and domain. + */ +OSStatus SecTrustSettingsCopyModificationDate( + SecCertificateRef certRef, + SecTrustSettingsDomain domain, + CFDateRef * __nonnull CF_RETURNS_RETAINED modificationDate); /* RETURNED */ + +/* + * Obtain an external, portable representation of the specified + * domain's TrustSettings. Caller must CFRelease the returned data. + * Returns errSecNoTrustSettings if no trust settings exist + * for the specified domain. + */ +OSStatus SecTrustSettingsCreateExternalRepresentation( + SecTrustSettingsDomain domain, + CFDataRef * __nonnull CF_RETURNS_RETAINED trustSettings); + +/* + * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation, + * into the specified domain. + */ +OSStatus SecTrustSettingsImportExternalRepresentation( + SecTrustSettingsDomain domain, + CFDataRef trustSettings); + +CF_ASSUME_NONNULL_END + +#endif /* SEC_OS_OSX_INCLUDES */ + +__END_DECLS + +#endif /* _SECURITY_SECTRUSTSETTINGS_H_ */ diff --git a/trust/headers/SecTrustSettingsPriv.h b/trust/headers/SecTrustSettingsPriv.h new file mode 100644 index 00000000..62b1c9b4 --- /dev/null +++ b/trust/headers/SecTrustSettingsPriv.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _SECURITY_SECTRUSTSETTINGSPRIV_H_ +#define _SECURITY_SECTRUSTSETTINGSPRIV_H_ + +#include + +#include +#include +#include +#include +#if SEC_OS_OSX +#include +#endif + +__BEGIN_DECLS + +/* + * Private Keys in the Usage Contraints dictionary. + * kSecTrustSettingsPolicyName Specifies a cert verification policy, e.g., + * sslServer, eapClient, etc, using policy names. + * This entry can be used to restrict the policy where + * the same Policy Constant is used for multiple policyNames. + * kSectrustSettingsPolicyOptions Specifies a dictionary of policy options (from + * SecPolicyInternal.h). This entry can be used to require + * a particular SecPolicyCheck whenever this certificate is + * encountered during trust evaluation. + */ +#define kSecTrustSettingsPolicyName CFSTR("kSecTrustSettingsPolicyName") +#define kSecTrustSettingsPolicyOptions CFSTR("kSecTrustSettingsPolicyOptions") + +extern const CFStringRef kSecCTExceptionsCAsKey; +extern const CFStringRef kSecCTExceptionsDomainsKey; +extern const CFStringRef kSecCTExceptionsHashAlgorithmKey; +extern const CFStringRef kSecCTExceptionsSPKIHashKey; + +/* + @function SecTrustStoreSetCTExceptions + @abstract Set the certificate transparency enforcement exceptions + @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the callers entitlements. + @param exceptions Dictionary of exceptions to set for this application. These exceptions replace existing exceptions for the keys in the dictionary. Exceptions for omitted keys are not affected. Null removes all exceptions for this application. See the discussion sections below for a complete overview of options. + @param error Upon failure describes cause of the failure. + @result boolean indicating success of the operation. If false, error will be filled in with a description of the error. + @discussions An exceptions dictionary has two optional keys: + kSecCTExceptionsDomainsKey takes an array of strings. These strings are the domains that are excluded from enforcing CT. A leading "." is supported to signify subdomains. Wildcard domains are not supported. + kSecCTExceptionsCAsKey takes an array of dictionaries. Each dictionary has two required keys: + kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currenlty only "sha256" is supported. + kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificates SubjectPublicKeyInfo. + */ +bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error); + +/* + @function SecTrustStoreCopyCTExceptions + @abstract Return the certificate transparency enforcement exceptions + @param applicationIdentifier Identifier for the caller's exceptions to fetch. If null, all set exceptions will be returned (regardless of which caller set them). + @param error Upon failure describes cause of the failure. + @result The dictionary of currently set exceptions. Null if none exist or upon failure. + @discussion The returned exceptions dictionary has the same options as input exceptions. See the discussion of SecTrustStoreSetCTExceptions. + */ +CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error); + +#if SEC_OS_OSX + +/* + * Fundamental routine used by TP to ascertain status of one cert. + * + * Returns true in *foundMatchingEntry if a trust setting matching + * specific constraints was found for the cert. Returns true in + * *foundAnyEntry if any entry was found for the cert, even if it + * did not match the specified constraints. The TP uses this to + * optimize for the case where a cert is being evaluated for + * one type of usage, and then later for another type. If + * foundAnyEntry is false, the second evaluation need not occur. + * + * Returns the domain in which a setting was found in *foundDomain. + * + * Allowed errors applying to the specified cert evaluation + * are returned in a mallocd array in *allowedErrors and must + * be freed by caller. + */ +OSStatus SecTrustSettingsEvaluateCert( + CFStringRef certHashStr, + /* parameters describing the current cert evalaution */ + const CSSM_OID *policyOID, + const char *policyString, /* optional */ + uint32 policyStringLen, + SecTrustSettingsKeyUsage keyUsage, /* optional */ + bool isRootCert, /* for checking default setting */ + /* RETURNED values */ + SecTrustSettingsDomain *foundDomain, + CSSM_RETURN **allowedErrors, /* mallocd and RETURNED */ + uint32 *numAllowedErrors, /* RETURNED */ + SecTrustSettingsResult *resultType, /* RETURNED */ + bool *foundMatchingEntry, /* RETURNED */ + bool *foundAnyEntry) /* RETURNED */ +DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/* + * Obtain trusted certs which match specified usage. + * Only certs with a SecTrustSettingsResult of + * kSecTrustSettingsResultTrustRoot or + * or kSecTrustSettingsResultTrustAsRoot will be returned. + * + * To be used by SecureTransport for its (hopefully soon-to-be- + * deprecated) SSLSetTrustedRoots() call; I hope nothing else has + * to use this... + * + * Caller must CFRelease the returned CFArrayRef. + */ +OSStatus SecTrustSettingsCopyQualifiedCerts( + const CSSM_OID *policyOID, + const char *policyString, /* optional */ + uint32 policyStringLen, + SecTrustSettingsKeyUsage keyUsage, /* optional */ + CFArrayRef *certArray) /* RETURNED */ +DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + +/* + * Obtain unrestricted root certificates from the specified domain(s). + * Only returns root certificates with no usage constraints. + * Caller must CFRelease the returned CFArrayRef. + */ +OSStatus SecTrustSettingsCopyUnrestrictedRoots( + Boolean userDomain, + Boolean adminDomain, + Boolean systemDomain, + CFArrayRef *certArray); /* RETURNED */ + +/* + * Obtain a string representing a cert's SHA1 digest. This string is + * the key used to look up per-cert trust settings in a TrustSettings record. + */ +CFStringRef CF_RETURNS_RETAINED SecTrustSettingsCertHashStrFromCert( + SecCertificateRef certRef); + +CFStringRef CF_RETURNS_RETAINED SecTrustSettingsCertHashStrFromData( + const void *cert, + size_t certLen); + +/* + * Add a cert's TrustSettings to a non-persistent TrustSettings record. + * Primarily intended for use in creating a system TrustSettings record + * (which is itself immutable via this module). + * + * The settingsIn argument is an external representation of a TrustSettings + * record, obtained from this function or from + * SecTrustSettingsCreateExternalRepresentation(). + * If settingsIn is NULL, a new (empty) TrustSettings will be created. + * + * The certRef and trustSettingsDictOrArray arguments are as in + * SecTrustSettingsSetTrustSettings(). May be NULL, when e.g. creating + * a new and empty TrustSettings record. + * + * The external representation is written to the settingOut argument, + * which must eventually be CFReleased by the caller. + */ +OSStatus SecTrustSettingsSetTrustSettingsExternal( + CFDataRef settingsIn, /* optional */ + SecCertificateRef certRef, /* optional */ + CFTypeRef trustSettingsDictOrArray, /* optional */ + CFDataRef *settingsOut); /* RETURNED */ + +/* + * Add user trust settings for a SSL certificate and a given hostname. + * This is a wrapper around the SecTrustSettingsSetTrustSettings API + * and should be functionally equivalent to "Always trust" in the UI. + * + * When this function is called, the user will be prompted to authorize + * the trust settings change. After they successfully authenticate, or + * cancel the dialog, the result block will be called to indicate the + * current trust status. If an error occurred (such as errUserCanceled), + * the error reference provided to the block will be non-NULL. + */ +void SecTrustSettingsSetTrustedCertificateForSSLHost( + SecCertificateRef certificate, + CFStringRef hostname, + void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error)) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_NA); +#endif // SEC_OS_OSX + +#if SEC_OS_OSX_INCLUDES +/* + * Purge the cache of User and Admin Certs + */ +void SecTrustSettingsPurgeUserAdminCertsCache(void); + +/* + * A wrapper around SecTrustSettingsCopyCertificates that combines user and admin + * domain outputs. + */ +OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains( + CFArrayRef CF_RETURNS_RETAINED *certArray); +#endif /* SEC_OS_OSX_INCLUDES */ + +__END_DECLS + +#endif // _SECURITY_SECTRUSTSETTINGSPRIV_H_ diff --git a/trust/headers/oids.h b/trust/headers/oids.h new file mode 100644 index 00000000..4a1d490d --- /dev/null +++ b/trust/headers/oids.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2005-2009,2011-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +/* + * oids.h - declaration of OID consts + * + */ + +#ifndef _SECURITY_OIDS_H_ +#define _SECURITY_OIDS_H_ + +#include +#include + +__BEGIN_DECLS + +/* This is a subset of libDER's oids.h. If the types header has + * already been included, we should skip these typedef declarations. */ +#ifndef _LIB_DER_H_ +/* + * Basic data types + */ +typedef uint8_t DERByte; +typedef size_t DERSize; + +/* + * Primary representation of a block of memory. + */ +typedef struct { + DERByte *data; + DERSize length; +} DERItem; +#endif /* _LIB_DER_H_ */ + +/* Algorithm oids. */ +extern const DERItem + oidRsa, /* PKCS1 RSA encryption, used to identify RSA keys */ + oidMd2Rsa, /* PKCS1 md2withRSAEncryption signature alg */ + oidMd4Rsa, /* PKCS1 md4withRSAEncryption signature alg */ + oidMd5Rsa, /* PKCS1 md5withRSAEncryption signature alg */ + oidSha1Rsa, /* PKCS1 sha1withRSAEncryption signature alg */ + oidSha256Rsa, /* PKCS1 sha256WithRSAEncryption signature alg */ + oidSha384Rsa, /* PKCS1 sha384WithRSAEncryption signature alg */ + oidSha512Rsa, /* PKCS1 sha512WithRSAEncryption signature alg */ + oidSha224Rsa, /* PKCS1 sha224WithRSAEncryption signature alg */ + oidEcPubKey, /* ECDH or ECDSA public key in a certificate */ + oidSha1Ecdsa, /* ECDSA with SHA1 signature alg */ + oidSha224Ecdsa, /* ECDSA with SHA224 signature alg */ + oidSha256Ecdsa, /* ECDSA with SHA256 signature alg */ + oidSha384Ecdsa, /* ECDSA with SHA384 signature alg */ + oidSha512Ecdsa, /* ECDSA with SHA512 signature alg */ + oidSha1Dsa, /* ANSI X9.57 DSA with SHA1 signature alg */ + oidMd2, /* OID_RSA_HASH 2 */ + oidMd4, /* OID_RSA_HASH 4 */ + oidMd5, /* OID_RSA_HASH 5 */ + oidSha1, /* OID_OIW_ALGORITHM 26 */ + oidSha1DsaOIW, /* OID_OIW_ALGORITHM 27 */ + oidSha1DsaCommonOIW,/* OID_OIW_ALGORITHM 28 */ + oidSha1RsaOIW, /* OID_OIW_ALGORITHM 29 */ + oidSha256, /* OID_NIST_HASHALG 1 */ + oidSha384, /* OID_NIST_HASHALG 2 */ + oidSha512, /* OID_NIST_HASHALG 3 */ + oidSha224, /* OID_NIST_HASHALG 4 */ + oidFee, /* APPLE_ALG_OID 1 */ + oidMd5Fee, /* APPLE_ALG_OID 3 */ + oidSha1Fee, /* APPLE_ALG_OID 4 */ + oidEcPrime192v1, /* OID_EC_CURVE 1 prime192v1/secp192r1/ansiX9p192r1*/ + oidEcPrime256v1, /* OID_EC_CURVE 7 prime256v1/secp256r1*/ + oidAnsip384r1, /* OID_CERTICOM_EC_CURVE 34 ansip384r1/secp384r1*/ + oidAnsip521r1; /* OID_CERTICOM_EC_CURVE 35 ansip521r1/secp521r1*/ + +/* Standard X.509 Cert and CRL extensions. */ +extern const DERItem + oidSubjectKeyIdentifier, + oidKeyUsage, + oidPrivateKeyUsagePeriod, + oidSubjectAltName, + oidIssuerAltName, + oidBasicConstraints, + oidNameConstraints, + oidCrlDistributionPoints, + oidCertificatePolicies, + oidAnyPolicy, + oidPolicyMappings, + oidAuthorityKeyIdentifier, + oidPolicyConstraints, + oidExtendedKeyUsage, + oidAnyExtendedKeyUsage, + oidInhibitAnyPolicy, + oidAuthorityInfoAccess, + oidSubjectInfoAccess, + oidAdOCSP, + oidAdCAIssuer, + oidNetscapeCertType, + oidEntrustVersInfo, + oidMSNTPrincipalName; + +/* Policy Qualifier IDs for Internet policy qualifiers. */ +extern const DERItem + oidQtCps, + oidQtUNotice; + +/* X.501 Name IDs. */ +extern const DERItem + oidCommonName, + oidCountryName, + oidLocalityName, + oidStateOrProvinceName, + oidOrganizationName, + oidOrganizationalUnitName, + oidDescription, + oidEmailAddress, + oidFriendlyName, + oidLocalKeyId; + +/* X.509 Extended Key Usages */ +extern const DERItem + oidExtendedKeyUsageServerAuth, + oidExtendedKeyUsageClientAuth, + oidExtendedKeyUsageCodeSigning, + oidExtendedKeyUsageEmailProtection, + oidExtendedKeyUsageTimeStamping, + oidExtendedKeyUsageOCSPSigning, + oidExtendedKeyUsageIPSec, + oidExtendedKeyUsageMicrosoftSGC, + oidExtendedKeyUsageNetscapeSGC; + +/* Google Certificate Transparency OIDs */ +extern const DERItem + oidGoogleEmbeddedSignedCertificateTimestamp, + oidGoogleOCSPSignedCertificateTimestamp; + +__END_DECLS + +#endif /* _SECURITY_OIDS_H_ */ diff --git a/trust/oids.h b/trust/oids.h deleted file mode 100644 index 4a1d490d..00000000 --- a/trust/oids.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2005-2009,2011-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/* - * oids.h - declaration of OID consts - * - */ - -#ifndef _SECURITY_OIDS_H_ -#define _SECURITY_OIDS_H_ - -#include -#include - -__BEGIN_DECLS - -/* This is a subset of libDER's oids.h. If the types header has - * already been included, we should skip these typedef declarations. */ -#ifndef _LIB_DER_H_ -/* - * Basic data types - */ -typedef uint8_t DERByte; -typedef size_t DERSize; - -/* - * Primary representation of a block of memory. - */ -typedef struct { - DERByte *data; - DERSize length; -} DERItem; -#endif /* _LIB_DER_H_ */ - -/* Algorithm oids. */ -extern const DERItem - oidRsa, /* PKCS1 RSA encryption, used to identify RSA keys */ - oidMd2Rsa, /* PKCS1 md2withRSAEncryption signature alg */ - oidMd4Rsa, /* PKCS1 md4withRSAEncryption signature alg */ - oidMd5Rsa, /* PKCS1 md5withRSAEncryption signature alg */ - oidSha1Rsa, /* PKCS1 sha1withRSAEncryption signature alg */ - oidSha256Rsa, /* PKCS1 sha256WithRSAEncryption signature alg */ - oidSha384Rsa, /* PKCS1 sha384WithRSAEncryption signature alg */ - oidSha512Rsa, /* PKCS1 sha512WithRSAEncryption signature alg */ - oidSha224Rsa, /* PKCS1 sha224WithRSAEncryption signature alg */ - oidEcPubKey, /* ECDH or ECDSA public key in a certificate */ - oidSha1Ecdsa, /* ECDSA with SHA1 signature alg */ - oidSha224Ecdsa, /* ECDSA with SHA224 signature alg */ - oidSha256Ecdsa, /* ECDSA with SHA256 signature alg */ - oidSha384Ecdsa, /* ECDSA with SHA384 signature alg */ - oidSha512Ecdsa, /* ECDSA with SHA512 signature alg */ - oidSha1Dsa, /* ANSI X9.57 DSA with SHA1 signature alg */ - oidMd2, /* OID_RSA_HASH 2 */ - oidMd4, /* OID_RSA_HASH 4 */ - oidMd5, /* OID_RSA_HASH 5 */ - oidSha1, /* OID_OIW_ALGORITHM 26 */ - oidSha1DsaOIW, /* OID_OIW_ALGORITHM 27 */ - oidSha1DsaCommonOIW,/* OID_OIW_ALGORITHM 28 */ - oidSha1RsaOIW, /* OID_OIW_ALGORITHM 29 */ - oidSha256, /* OID_NIST_HASHALG 1 */ - oidSha384, /* OID_NIST_HASHALG 2 */ - oidSha512, /* OID_NIST_HASHALG 3 */ - oidSha224, /* OID_NIST_HASHALG 4 */ - oidFee, /* APPLE_ALG_OID 1 */ - oidMd5Fee, /* APPLE_ALG_OID 3 */ - oidSha1Fee, /* APPLE_ALG_OID 4 */ - oidEcPrime192v1, /* OID_EC_CURVE 1 prime192v1/secp192r1/ansiX9p192r1*/ - oidEcPrime256v1, /* OID_EC_CURVE 7 prime256v1/secp256r1*/ - oidAnsip384r1, /* OID_CERTICOM_EC_CURVE 34 ansip384r1/secp384r1*/ - oidAnsip521r1; /* OID_CERTICOM_EC_CURVE 35 ansip521r1/secp521r1*/ - -/* Standard X.509 Cert and CRL extensions. */ -extern const DERItem - oidSubjectKeyIdentifier, - oidKeyUsage, - oidPrivateKeyUsagePeriod, - oidSubjectAltName, - oidIssuerAltName, - oidBasicConstraints, - oidNameConstraints, - oidCrlDistributionPoints, - oidCertificatePolicies, - oidAnyPolicy, - oidPolicyMappings, - oidAuthorityKeyIdentifier, - oidPolicyConstraints, - oidExtendedKeyUsage, - oidAnyExtendedKeyUsage, - oidInhibitAnyPolicy, - oidAuthorityInfoAccess, - oidSubjectInfoAccess, - oidAdOCSP, - oidAdCAIssuer, - oidNetscapeCertType, - oidEntrustVersInfo, - oidMSNTPrincipalName; - -/* Policy Qualifier IDs for Internet policy qualifiers. */ -extern const DERItem - oidQtCps, - oidQtUNotice; - -/* X.501 Name IDs. */ -extern const DERItem - oidCommonName, - oidCountryName, - oidLocalityName, - oidStateOrProvinceName, - oidOrganizationName, - oidOrganizationalUnitName, - oidDescription, - oidEmailAddress, - oidFriendlyName, - oidLocalKeyId; - -/* X.509 Extended Key Usages */ -extern const DERItem - oidExtendedKeyUsageServerAuth, - oidExtendedKeyUsageClientAuth, - oidExtendedKeyUsageCodeSigning, - oidExtendedKeyUsageEmailProtection, - oidExtendedKeyUsageTimeStamping, - oidExtendedKeyUsageOCSPSigning, - oidExtendedKeyUsageIPSec, - oidExtendedKeyUsageMicrosoftSGC, - oidExtendedKeyUsageNetscapeSGC; - -/* Google Certificate Transparency OIDs */ -extern const DERItem - oidGoogleEmbeddedSignedCertificateTimestamp, - oidGoogleOCSPSignedCertificateTimestamp; - -__END_DECLS - -#endif /* _SECURITY_OIDS_H_ */ diff --git a/trust/trustd/OTATrustUtilities.h b/trust/trustd/OTATrustUtilities.h new file mode 100644 index 00000000..4b770f9d --- /dev/null +++ b/trust/trustd/OTATrustUtilities.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * OTATrustUtilities.h + */ + +#ifndef _OTATRUSTUTILITIES_H_ +#define _OTATRUSTUTILITIES_H_ 1 + +#include +#include +#include +#include + +__BEGIN_DECLS + +// Opaque type that holds the data for a specific version of the OTA PKI assets +typedef struct _OpaqueSecOTAPKI *SecOTAPKIRef; + +// Returns a boolean for whether the current instance is the system trustd +bool SecOTAPKIIsSystemTrustd(void); + +// Returns the trust server workloop +dispatch_queue_t SecTrustServerGetWorkloop(void); + +// Convert a trusted CT log array to a trusted CT log dictionary, indexed by the LogID +CF_RETURNS_RETAINED +CFDictionaryRef SecOTAPKICreateTrustedCTLogsDictionaryFromArray(CFArrayRef trustedCTLogsArray); + +// Get a reference to the current OTA PKI asset data +// Caller is responsible for releasing the returned SecOTAPKIRef +CF_EXPORT CF_RETURNS_RETAINED +SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef(void); + +// Accessor to retrieve a copy of the current black listed key. +// Caller is responsible for releasing the returned CFSetRef +CF_EXPORT +CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve a copy of the current gray listed key. +// Caller is responsible for releasing the returned CFSetRef +CF_EXPORT +CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve a copy of the current allow list dictionary. +// Caller is responsible for releasing the returned CFDictionaryRef +CF_EXPORT +CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve a copy of the allow list for a specific authority key ID. +// Caller is responsible for releasing the returned CFArrayRef +CF_EXPORT +CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID); + +// Accessor to retrieve a copy of the current trusted certificate transparency logs. +// Caller is responsible for releasing the returned CFArrayRef +CF_EXPORT +CFDictionaryRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the path of the current pinning list. +// Caller is responsible for releasing the returned CFURLRef +CF_EXPORT +CFURLRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the array of Escrow certificates. +// Caller is responsible for releasing the returned CFArrayRef +CF_EXPORT +CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the dictionary of EV Policy OIDs to Anchor digest. +// Caller is responsible for releasing the returned CFDictionaryRef +CF_EXPORT +CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the dictionary of anchor digest to file offset. +// Caller is responsible for releasing the returned CFDictionaryRef +CF_EXPORT +CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the pointer to the top of the anchor certs file. +// Caller should NOT free the returned pointer. The caller should hold +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the full path to the valid update snapshot resource. +// The return value may be NULL if the resource does not exist. +// Caller should NOT free the returned pointer. The caller should hold +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the full path to the valid database snapshot resource. +// The return value may be NULL if the resource does not exist. +// Caller should NOT free the returned pointer. The caller should hold +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the current valid snapshot version. +CF_EXPORT +CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the current valid snapshot format. +CF_EXPORT +CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the OTAPKI trust store version +// Note: Trust store is not mutable by assets +CF_EXPORT +uint64_t SecOTAPKIGetTrustStoreVersion(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the OTAPKI asset version +CF_EXPORT +uint64_t SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef); + +// Accessors to retrieve the last check in time for the OTAPKI asset +CF_EXPORT +CFDateRef SecOTAPKICopyLastAssetCheckInDate(SecOTAPKIRef otapkiRef); + +#define kSecOTAPKIAssetStalenessAtRisk (60*60*24*30) // 30 days +#define kSecOTAPKIAssetStalenessWarning (60*60*24*45) // 45 days +#define kSecOTAPKIAssetStalenessDisable (60*60*24*60) // 60 days +bool SecOTAPKIAssetStalenessLessThanSeconds(SecOTAPKIRef otapkiRef, CFTimeInterval seconds); + +#if __OBJC__ +// SPI to return the current sampling rate for the event name +// This rate is actually n where we sample 1 out of every n +NSNumber *SecOTAPKIGetSamplingRateForEvent(SecOTAPKIRef otapkiRef, NSString *eventName); +#endif // __OBJC__ + +CFArrayRef SecOTAPKICopyAppleCertificateAuthorities(SecOTAPKIRef otapkiRef); + +extern const CFStringRef kOTAPKIKillSwitchCT; +bool SecOTAPKIKillSwitchEnabled(SecOTAPKIRef otapkiRef, CFStringRef switchKey); + +// SPI to return the array of currently trusted Escrow certificates +CF_EXPORT +CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error); + +// SPI to return the array of currently trusted CT logs +CF_EXPORT +CFDictionaryRef SecOTAPKICopyCurrentTrustedCTLogs(CFErrorRef* error); + +// SPI to return dictionary of CT log matching specified key id */ +CF_EXPORT +CFDictionaryRef SecOTAPKICopyCTLogForKeyID(CFDataRef keyID, CFErrorRef* error); + +// SPI to return the current OTA PKI trust store version +// Note: Trust store is not mutable by assets +CF_EXPORT +uint64_t SecOTAPKIGetCurrentTrustStoreVersion(CFErrorRef* CF_RETURNS_RETAINED error); + +// SPI to return the current OTA PKI asset version +CF_EXPORT +uint64_t SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error); + +// SPI to return the current OTA SecExperiment asset version +CF_EXPORT +uint64_t SecOTASecExperimentGetCurrentAssetVersion(CFErrorRef* error); + +// SPI to reset the current OTA PKI asset version to the version shipped +// with the system +CF_EXPORT +uint64_t SecOTAPKIResetCurrentAssetVersion(CFErrorRef* CF_RETURNS_RETAINED error); + +// SPI to signal trustd to get a new set of trust data +// Always returns the current asset version. Returns an error with +// a reason if the update was not successful. +CF_EXPORT +uint64_t SecOTAPKISignalNewAsset(CFErrorRef* CF_RETURNS_RETAINED error); + +// SPI to signal trustd to get a new set of SecExperiment data +// Always returns the current asset version. Returns an error with +// a reason if the update was not successful. +CF_EXPORT +uint64_t SecOTASecExperimentGetNewAsset(CFErrorRef* error); + +// SPI to copy current SecExperiment asset data +CF_EXPORT +CFDictionaryRef SecOTASecExperimentCopyAsset(CFErrorRef* error); + +/* "Internal" interfaces for tests */ +#if !TARGET_OS_BRIDGE && __OBJC__ +BOOL UpdateOTACheckInDate(void); +void UpdateKillSwitch(NSString *key, bool value); +#endif + +__END_DECLS + +#endif /* _OTATRUSTUTILITIES_H_ */ diff --git a/trust/trustd/OTATrustUtilities.m b/trust/trustd/OTATrustUtilities.m new file mode 100644 index 00000000..f3e59709 --- /dev/null +++ b/trust/trustd/OTATrustUtilities.m @@ -0,0 +1,2281 @@ +/* + * Copyright (c) 2003-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * OTATrustUtilities.m + */ + +#import +#include "OTATrustUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SecFramework.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "trust/trustd/SecPinningDb.h" +#import + +#if !TARGET_OS_BRIDGE +#import +#import +#include +#include +#include +#import "trust/trustd/SecTrustLoggingServer.h" +#endif + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR +#import +#include +#endif + +static inline bool isNSNumber(id nsType) { + return nsType && [nsType isKindOfClass:[NSNumber class]]; +} + +static inline bool isNSDictionary(id nsType) { + return nsType && [nsType isKindOfClass:[NSDictionary class]]; +} + +static inline bool isNSArray(id nsType) { + return nsType && [nsType isKindOfClass:[NSArray class]]; +} + +static inline bool isNSDate(id nsType) { + return nsType && [nsType isKindOfClass:[NSDate class]]; +} + +static inline bool isNSData(id nsType) { + return nsType && [nsType isKindOfClass:[NSData class]]; +} + +#define SECURITYD_ROLE_ACCOUNT 64 +#define ROOT_ACCOUNT 0 + +bool SecOTAPKIIsSystemTrustd() { + static bool result = false; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#ifdef NO_SERVER + // Test app running as trustd +#elif TARGET_OS_IPHONE + if (getuid() == SECURITYD_ROLE_ACCOUNT || + (getuid() == ROOT_ACCOUNT && gTrustd)) // Test app running as trustd +#else + if (getuid() == ROOT_ACCOUNT) +#endif + { + result = true; + } + }); + return result; +} + +dispatch_queue_t SecTrustServerGetWorkloop(void) { + static dispatch_workloop_t workloop = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + workloop = dispatch_workloop_create("com.apple.trustd.evaluation"); + }); + return workloop; +} + +/* MARK: - */ +/* MARK: System Trust Store */ +static CFStringRef kSecSystemTrustStoreBundlePath = CFSTR("/System/Library/Security/Certificates.bundle"); + +CFGiblisGetSingleton(CFBundleRef, SecSystemTrustStoreGetBundle, bundle, ^{ + CFStringRef bundlePath = NULL; +#if TARGET_OS_SIMULATOR + char *simulatorRoot = getenv("SIMULATOR_ROOT"); + if (simulatorRoot) + bundlePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s%@"), simulatorRoot, kSecSystemTrustStoreBundlePath); +#endif + if (!bundlePath) + bundlePath = CFRetainSafe(kSecSystemTrustStoreBundlePath); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath, kCFURLPOSIXPathStyle, true); + *bundle = (url) ? CFBundleCreate(kCFAllocatorDefault, url) : NULL; + CFReleaseSafe(url); + CFReleaseSafe(bundlePath); +}) + +static CFURLRef SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName, + CFStringRef resourceType, CFStringRef subDirName) { + CFURLRef url = NULL; + CFBundleRef bundle = SecSystemTrustStoreGetBundle(); + if (bundle) { + url = CFBundleCopyResourceURL(bundle, resourceName, + resourceType, subDirName); + } + if (!url) { + secwarning("resource: %@.%@ in %@ not found", resourceName, + resourceType, subDirName); + } + return url; +} + +static NSURL *SecSystemTrustStoreCopyResourceNSURL(NSString *resourceFileName) { + CFBundleRef bundle = SecSystemTrustStoreGetBundle(); + if (!bundle) { + return NULL; + } + NSURL *resourceDir = CFBridgingRelease(CFBundleCopyResourcesDirectoryURL(bundle)); + if (!resourceDir) { + return NULL; + } + NSURL *fileURL = [NSURL URLWithString:resourceFileName + relativeToURL:resourceDir]; + if (!fileURL) { + secwarning("resource: %@ not found", resourceFileName); + } + return fileURL; +} + +static CFDataRef SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName, + CFStringRef resourceType, CFStringRef subDirName) { + CFURLRef url = SecSystemTrustStoreCopyResourceURL(resourceName, resourceType, subDirName); + CFDataRef data = NULL; + if (url) { + SInt32 error; + if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, + url, &data, NULL, NULL, &error)) { + secwarning("read: %ld", (long) error); + } + CFRelease(url); + } + return data; +} + +/* MARK: - */ +/* MARK: MobileAsset Updates */ +// MARK: Forward Declarations +static uint64_t GetAssetVersion(CFErrorRef *error); +static uint64_t GetSystemVersion(CFStringRef key); +#if !TARGET_OS_BRIDGE +static BOOL UpdateFromAsset(NSURL *localURL, NSNumber *asset_version, NSError **error); +static NSNumber *SecExperimentUpdateAsset(MAAsset *asset, NSNumber *asset_version, NSError **error); +static void TriggerUnlockNotificationOTATrustAssetCheck(NSString* assetType, dispatch_queue_t queue); +#endif + +/* This queue is for fetching changes to the OTAPKI reference or otherwise doing maintenance activities */ +static dispatch_queue_t kOTABackgroundQueue = NULL; + +// MARK: Constants +NSString *kOTATrustContentVersionKey = @"MobileAssetContentVersion"; +NSString *kOTATrustLastCheckInKey = @"MobileAssetLastCheckIn"; +NSString *kOTATrustContextFilename = @"OTAPKIContext.plist"; +NSString *kOTATrustTrustedCTLogsFilename = @"TrustedCTLogs.plist"; +NSString *kOTATrustAnalyticsSamplingRatesFilename = @"AnalyticsSamplingRates.plist"; +NSString *kOTATrustAppleCertifcateAuthoritiesFilename = @"AppleCertificateAuthorities.plist"; +NSString *kOTASecExperimentConfigFilename = @"SecExperimentAssets.plist"; + +const CFStringRef kOTAPKIKillSwitchCT = CFSTR("CTKillSwitch"); + +#if !TARGET_OS_BRIDGE +NSString *OTATrustMobileAssetType = @"com.apple.MobileAsset.PKITrustSupplementals"; +NSString *OTASecExperimentMobileAssetType = @"com.apple.MobileAsset.SecExperimentAssets"; +#define kOTATrustMobileAssetNotification "com.apple.MobileAsset.PKITrustSupplementals.ma.cached-metadata-updated" +#define kOTATrustOnDiskAssetNotification "com.apple.trustd.asset-updated" +#define kOTATrustCheckInNotification "com.apple.trustd.asset-check-in" +#define kOTATrustKillSwitchNotification "com.apple.trustd.kill-switch" +#define kOTASecExperimentNewAssetNotification "com.apple.trustd.secexperiment.asset-updated" +const NSUInteger OTATrustMobileAssetCompatibilityVersion = 1; +const NSUInteger OTASecExperimentMobileAssetCompatibilityVersion = 1; +#define kOTATrustDefaultUpdatePeriod 60*60*12 // 12 hours +#define kOTATrustMinimumUpdatePeriod 60*5 // 5 min +#define kOTATrustDefaultWaitPeriod 60 // 1 min + +#if TARGET_OS_OSX +const CFStringRef kSecSUPrefDomain = CFSTR("com.apple.SoftwareUpdate"); +const CFStringRef kSecSUScanPrefConfigDataInstallKey = CFSTR("ConfigDataInstall"); +#endif + +// MARK: Helper functions +typedef enum { + OTATrustLogLevelNone, + OTATrustLogLevelDebug, + OTATrustLogLevelInfo, + OTATrustLogLevelNotice, + OTATrustLogLevelError, +} OTATrustLogLevel; + +static void MakeOTATrustError(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, NSString *format,...) NS_FORMAT_FUNCTION(6,7); +static void MakeOTATrustErrorWithAttributes(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, + NSDictionary *attributes, NSString *format,...) + NS_FORMAT_FUNCTION(7,8); + +static void MakeOTATrustErrorArgs(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, + NSDictionary *attributes, NSString *format, va_list arguments) + NS_FORMAT_FUNCTION(7,0); + +static void LogLocally(OTATrustLogLevel level, NSString *errorString) { + switch (level) { + case OTATrustLogLevelNone: + break; + case OTATrustLogLevelDebug: + secdebug("OTATrust", "%@", errorString); + break; + case OTATrustLogLevelInfo: + secinfo("OTATrust", "%@", errorString); + break; + case OTATrustLogLevelNotice: + secnotice("OTATrust", "%@", errorString); + break; + case OTATrustLogLevelError: + secerror("OTATrust: %@", errorString); + break; + } +} + +static void LogRemotelyWithAttributes(OTATrustLogLevel level, NSError **error, NSDictionary *attributes) { +#if ENABLE_TRUSTD_ANALYTICS + /* only report errors and notices */ + if (error && level == OTATrustLogLevelError) { + [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:YES result:*error withAttributes:attributes]; + } else if (error && level == OTATrustLogLevelNotice) { + [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:NO result:*error withAttributes:attributes]; + } +#endif // ENABLE_TRUSTD_ANALYTICS +} + +static void LogRemotely(OTATrustLogLevel level, NSError **error) { + LogRemotelyWithAttributes(level, error, nil); +} + +static void MakeOTATrustErrorArgs(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, + NSDictionary *attributes, NSString *format, va_list args) { + NSString *formattedString = nil; + if (format) { + formattedString = [[NSString alloc] initWithFormat:format arguments:args]; + } + + NSError *localError = nil; + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + if (format) { + [userInfo setObject:formattedString forKey:NSLocalizedDescriptionKey]; + } + if (error && *error) { + userInfo[NSUnderlyingErrorKey] = *error; + } + localError = [NSError errorWithDomain:errDomain + code:errCode + userInfo:userInfo]; + + LogLocally(level, formattedString); + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + LogRemotelyWithAttributes(level, &localError, attributes); + } + if (error) { *error = localError; } +} + +static void MakeOTATrustErrorWithAttributes(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, + NSDictionary *attributes, NSString *format,...) { + va_list args; + va_start(args, format); + MakeOTATrustErrorArgs(assetType, error, level, errDomain, errCode, attributes, format, args); + va_end(args); +} + +static void MakeOTATrustError(NSString *assetType, NSError **error, OTATrustLogLevel level, NSErrorDomain errDomain, OSStatus errCode, NSString *format,...) { + va_list args; + va_start(args, format); + MakeOTATrustErrorArgs(assetType, error, level, errDomain, errCode, nil, format, args); + va_end(args); +} + +static BOOL CanCheckMobileAsset(void) { + BOOL result = YES; +#if TARGET_OS_OSX + /* Check the user's SU preferences to determine if "Install system data files" is off */ + if (!CFPreferencesSynchronize(kSecSUPrefDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost)) { + secerror("OTATrust: unable to synchronize SoftwareUpdate prefs"); + return NO; + } + + id value = nil; + if (CFPreferencesAppValueIsForced(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)) { + value = CFBridgingRelease(CFPreferencesCopyAppValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)); + } else { + value = CFBridgingRelease(CFPreferencesCopyValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain, + kCFPreferencesAnyUser, kCFPreferencesCurrentHost)); + } + if (isNSNumber(value)) { + result = [value boolValue]; + } + + if (!result) { secnotice("OTATrust", "User has disabled system data installation."); } + + /* MobileAsset.framework isn't mastered into the BaseSystem. Check that the MA classes are linked. */ + if (![ASAssetQuery class] || ![ASAsset class] || ![MAAssetQuery class] || ![MAAsset class]) { + secnotice("OTATrust", "Weak-linked MobileAsset framework missing."); + result = NO; + } +#endif + return result; +} + +static BOOL ShouldUpdateWithAsset(NSString *assetType, NSNumber *asset_version) { + if (![asset_version isKindOfClass:[NSNumber class]]) { + return NO; + } + CFErrorRef error = nil; + uint64_t current_version; + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + current_version = SecOTAPKIGetCurrentAssetVersion(&error); + } else if ([assetType isEqualToString:OTASecExperimentMobileAssetType]) { + current_version = SecOTASecExperimentGetCurrentAssetVersion(&error); + } else { + return NO; + } + if (error) { + CFReleaseNull(error); + return NO; + } + if ([asset_version compare:[NSNumber numberWithUnsignedLongLong:current_version]] == NSOrderedDescending) { + return YES; + } + return NO; +} + +// MARK: File management functions +static bool verify_create_path(const char *path) { + int ret = mkpath_np(path, 0755); + if (!(ret == 0 || ret == EEXIST)) { + secerror("could not create path: %s (%s)", path, strerror(ret)); + return false; + } + return true; +} + +static NSURL *GetAssetFileURL(NSString *filename) { + /* Make sure the /Library/Keychains directory is there */ + NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(nil)); + NSURL *directory = [keychainsDirectory URLByAppendingPathComponent:@"SupplementalsAssets/" isDirectory:YES]; + if (!verify_create_path([directory fileSystemRepresentation])) { + return nil; + } + + if (filename) { + return [directory URLByAppendingPathComponent:filename]; + } else { + return directory; + } +} + +static void DeleteFileWithName(NSString *filename) { + NSURL *fileURL = GetAssetFileURL(filename); + if (remove([fileURL fileSystemRepresentation]) == -1) { + int error = errno; + if (error != ENOENT) { + secnotice("OTATrust", "failed to remove %@: %s", fileURL, strerror(error)); + } + } +} + +static BOOL UpdateOTAContextOnDisk(NSString *key, id value, NSError **error) { + if (SecOTAPKIIsSystemTrustd()) { + /* Get current context, if applicable, and update/add key/value */ + NSURL *otaContextFile = GetAssetFileURL(kOTATrustContextFilename); + NSDictionary *currentContext = [NSDictionary dictionaryWithContentsOfURL:otaContextFile]; + NSMutableDictionary *newContext = nil; + if (currentContext) { + newContext = [currentContext mutableCopy]; + } else { + newContext = [NSMutableDictionary dictionary]; + } + newContext[key] = value; + + /* Write dictionary to disk */ + if (![newContext writeToURL:otaContextFile error:error]) { + secerror("OTATrust: unable to write OTA Context to disk: %@", error ? *error : nil); + LogRemotely(OTATrustLogLevelError, error); + return NO; + } + return YES; + } + return NO; +} + +static BOOL UpdateOTAContext(NSNumber *asset_version, NSError **error) { + return UpdateOTAContextOnDisk(kOTATrustContentVersionKey, asset_version, error) && UpdateOTACheckInDate(); +} + +/* Delete only the asset data but not the check-in time. */ +static void DeleteOldAssetData(void) { + if (SecOTAPKIIsSystemTrustd()) { + /* Delete the asset files, but keep the check-in time and version */ + DeleteFileWithName(kOTATrustTrustedCTLogsFilename); + DeleteFileWithName(kOTATrustAnalyticsSamplingRatesFilename); + DeleteFileWithName(kOTATrustAppleCertifcateAuthoritiesFilename); + } +} + +/* Delete all asset data, intended for error cases */ +static BOOL DeleteAssetFromDisk(void) { + if (SecOTAPKIIsSystemTrustd()) { + DeleteOldAssetData(); + DeleteFileWithName(kOTATrustContextFilename); + return YES; + } + return NO; +} + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR +static bool ChangeFileProtectionToClassD(NSURL *fileURL, NSError **error) { + BOOL result = YES; + int file_fd = open([fileURL fileSystemRepresentation], O_RDONLY); + if (file_fd) { + int retval = fcntl(file_fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_D); + if (retval < 0) { + MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, + @"set proteciton class error for asset %d: %s", errno, strerror(errno)); + result = NO; + } + close(file_fd); + } else { + MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, + @"open error for asset %d: %s", errno, strerror(errno)); + result = NO; + } + return result; +} +#endif + +static BOOL CopyFileToDisk(NSString *filename, NSURL *localURL, NSError **error) { + if (SecOTAPKIIsSystemTrustd()) { + NSURL *toFileURL = GetAssetFileURL(filename); + secdebug("OTATrust", "will copy asset file data from \"%@\"", localURL); + copyfile_state_t state = copyfile_state_alloc(); + int retval = copyfile([localURL fileSystemRepresentation], [toFileURL fileSystemRepresentation], + state, COPYFILE_DATA); + copyfile_state_free(state); + if (retval < 0) { + MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSPOSIXErrorDomain, errno, + @"copyfile error for asset %d: %s", errno, strerror(errno)); + return NO; + } else { + /* make sure we can read this file before first unlock */ +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + return ChangeFileProtectionToClassD(toFileURL, error); +#else + return YES; +#endif + } + } + return NO; +} + +static void GetKillSwitchAttributes(NSDictionary *attributes) { + bool killSwitchEnabled = false; + + // CT Kill Switch + NSNumber *ctKillSwitch = [attributes objectForKey:(__bridge NSString*)kOTAPKIKillSwitchCT]; + if (isNSNumber(ctKillSwitch)) { + NSError *error = nil; + UpdateOTAContextOnDisk((__bridge NSString*)kOTAPKIKillSwitchCT, ctKillSwitch, &error); + UpdateKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT, [ctKillSwitch boolValue]); + secnotice("OTATrust", "got CT kill switch = %d", [ctKillSwitch boolValue]); + killSwitchEnabled = true; + } + + /* Other kill switches TBD. + * When adding one, make sure to add to the Analytics Samplers since these kill switches + * are installed before the full asset is downloaded and installed. (A device can have the + * kill switches without having the asset version that contained them.) */ + + // notify the other trustds if any kill switch was read + if (SecOTAPKIIsSystemTrustd() && killSwitchEnabled) { + notify_post(kOTATrustKillSwitchNotification); + } +} + +// MARK: Fetch and Update Functions +static NSNumber *PKIUpdateAndPurgeAsset(MAAsset *asset, NSNumber *asset_version, NSError **error) { + if (SecPinningDbUpdateFromURL([asset getLocalFileUrl], error) && + UpdateFromAsset([asset getLocalFileUrl], asset_version, error)) { + secnotice("OTATrust", "finished update to version %@ from installed asset. purging asset.", asset_version); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logSuccessForEventNamed:TrustdHealthAnalyticsEventOTAPKIEvent]; +#endif // ENABLE_TRUSTD_ANALYTICS + [asset purge:^(MAPurgeResult purge_result) { + if (purge_result != MAPurgeSucceeded) { + secerror("OTATrust: purge failed: %ld", (long)purge_result); + } + }]; + return asset_version; + } else { + MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecCallbackFailed, + @"Failed to install new asset version %@ from %@", asset_version, [asset getLocalFileUrl]); + return nil; + } +} + +static NSNumber *UpdateAndPurgeAsset(NSString* assetType, MAAsset *asset, NSNumber *asset_version, NSError **error) { + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + return PKIUpdateAndPurgeAsset(asset, asset_version, error); + } else if ([assetType isEqualToString:OTASecExperimentMobileAssetType]) { + return SecExperimentUpdateAsset(asset, asset_version, error); + } else { + return nil; + } +} + +static MADownloadOptions *GetMADownloadOptions(BOOL wait) { + /* default behavior */ + MADownloadOptions *options = [[MADownloadOptions alloc] init]; + options.discretionary = YES; + options.allowsCellularAccess = NO; + + /* If an XPC interface is waiting on this, all expenses allowed */ + if (wait) { + options.discretionary = NO; + options.allowsCellularAccess = YES; + return options; + } + + /* If last asset check-in was too long ago, use more expensive options */ + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (!SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessWarning)) { + secnotice("OTATrust", "Asset staleness state: warning"); + options.allowsCellularAccess = YES; + options.discretionary = NO; + } else if (!SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessAtRisk)) { + secnotice("OTATrust", "Asset staleness state: at risk"); + options.discretionary = NO; + } + CFReleaseNull(otapkiref); + return options; +} + +static BOOL assetVersionCheck(NSString *assetType, MAAsset *asset) { + NSUInteger compatVersion; + NSError *ma_error = nil; + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + compatVersion = OTATrustMobileAssetCompatibilityVersion; + } else { + compatVersion = OTASecExperimentMobileAssetCompatibilityVersion; + } + /* Check Compatibility Version against this software version */ + NSNumber *compatibilityVersion = [asset assetProperty:@"_CompatibilityVersion"]; + if (!isNSNumber(compatibilityVersion) || + [compatibilityVersion unsignedIntegerValue] != compatVersion) { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecIncompatibleVersion, + @"skipping asset %@ because Compatibility Version doesn't match %@", assetType, compatibilityVersion); + return NO; + } + /* Check Content Version against the current content version */ + NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; + if (!ShouldUpdateWithAsset(assetType, asset_version)) { + /* write the version and last (successful) check-in time */ + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + UpdateOTAContext(asset_version, &ma_error); + NSDictionary *eventAttributes = @{ + @"assetVersion" : asset_version, + @"systemVersion" : @(GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey)), + @"installedVersion" : @(SecOTAPKIGetCurrentAssetVersion(nil)), + }; + MakeOTATrustErrorWithAttributes(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecDuplicateItem, eventAttributes, + @"skipping asset %@ because we already have _ContentVersion %@ (or newer)", assetType, asset_version); + } else { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecDuplicateItem, + @"skipping asset %@ because we already have _ContentVersion %@ (or newer)", assetType, asset_version); + } + return NO; + } + return YES; +} + +static int downloadWaitTime(void) { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + NSNumber *updateTimeout = [defaults valueForKey:@"TrustdAssetDownloadWaitTimeout"]; + int timeout = kOTATrustDefaultWaitPeriod; + if (isNSNumber(updateTimeout)) { + timeout = [updateTimeout intValue]; + } + return timeout; +} + +static BOOL DownloadOTATrustAsset(BOOL isLocalOnly, BOOL wait, NSString *assetType, NSError **error) { + if (!CanCheckMobileAsset()) { + MakeOTATrustError(assetType, error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecServiceNotAvailable, + @"MobileAsset disabled, skipping check."); + return NO; + } + + __block NSNumber *updated_version = nil; + __block dispatch_semaphore_t done = wait ? dispatch_semaphore_create(0) : nil; + __block NSError *ma_error = nil; + + secnotice("OTATrust", "begin MobileAsset query for catalog %@", assetType); + [MAAsset startCatalogDownload:assetType options:GetMADownloadOptions(wait) then:^(MADownLoadResult result) { + @autoreleasepool { + os_transaction_t transaction = os_transaction_create("com.apple.trustd.asset.download"); + if (result != MADownloadSuccessful) { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MADownLoadResult", (OSStatus)result, + @"failed to download catalog for asset %@: %ld", assetType, (long)result); + if (result == MADownloadDaemonNotReady && ([assetType isEqualToString:OTATrustMobileAssetType])) { + /* mobileassetd has to wait for first unlock to download. trustd usually launches before first unlock. */ + TriggerUnlockNotificationOTATrustAssetCheck(assetType, kOTABackgroundQueue); + } + return; + } + MAAssetQuery *query = [[MAAssetQuery alloc] initWithType:(NSString *)assetType]; + [query augmentResultsWithState:true]; + + secnotice("OTATrust", "begin MobileAsset metadata sync request %{public}@", assetType); + MAQueryResult queryResult = [query queryMetaDataSync]; + if (queryResult != MAQuerySuccessful) { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MAQueryResult", (OSStatus)queryResult, + @"failed to query MobileAsset %@ metadata: %ld", assetType, (long)queryResult); + return; + } + + if (!query.results) { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, + @"no results in MobileAsset query for %@", assetType); + return; + } + + bool began_async_job = false; + for (MAAsset *asset in query.results) { + /* Check Compatibility Version against this software version */ + NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; + if (!assetVersionCheck(assetType, asset)) { + continue; + } + + if ([assetType isEqualToString:OTATrustMobileAssetType]) { + GetKillSwitchAttributes(asset.attributes); + } + + switch (asset.state) { + default: + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, + @"unknown asset state %ld", (long)asset.state); + continue; + case MAInstalled: + /* The asset is already in the cache, get it from disk. */ + secdebug("OTATrust", "OTATrust asset %{public}@ already installed", assetType); + updated_version = UpdateAndPurgeAsset(assetType, asset, asset_version, &ma_error); + break; + case MAUnknown: + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MAAssetState", (OSStatus)asset.state, + @"asset %@ is unknown", assetType); + continue; + case MADownloading: + secnotice("OTATrust", "asset %{public}@ is downloading", assetType); + /* fall through */ + case MANotPresent: + secnotice("OTATrust", "begin download of OTATrust asset"); + began_async_job = true; + [asset startDownload:GetMADownloadOptions(wait) then:^(MADownLoadResult downloadResult) { + @autoreleasepool { + os_transaction_t inner_transaction = os_transaction_create("com.apple.trustd.asset.downloadAsset"); + if (downloadResult != MADownloadSuccessful) { + MakeOTATrustError(assetType, &ma_error, OTATrustLogLevelError, @"MADownLoadResult", (OSStatus)downloadResult, + @"failed to download asset %@: %ld", assetType, (long)downloadResult); + return; + } + updated_version = UpdateAndPurgeAsset(assetType, asset, asset_version, &ma_error); + if (wait) { + dispatch_semaphore_signal(done); + } + (void)inner_transaction; // dead store + inner_transaction = nil; + } + }]; + break; + } /* switch (asset.state) */ + } /* for (MAAsset.. */ + if (wait && !began_async_job) { + dispatch_semaphore_signal(done); + } + /* Done with the transaction */ + (void)transaction; // dead store + transaction = nil; + } /* autoreleasepool */ + }]; /* [MAAsset startCatalogDownload: ] */ + + /* If the caller is waiting for a response, wait up to one minute for the update to complete. + * If the MAAsset callback does not complete in that time, report a timeout. + * If the MAAsset callback completes and did not successfully update, it should report an error; + * forward that error to the caller. + * If the MAAsset callback completes and did not update and did not provide an error; report + * an unknown error. */ + BOOL result = NO; + if (wait) { + if (dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * downloadWaitTime())) != 0) { + MakeOTATrustError(assetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecNetworkFailure, + @"Failed to get asset %@ metadata within %d seconds.", assetType, downloadWaitTime()); + } else { + result = (updated_version != nil); + if (error && ma_error) { + *error = ma_error; + } else if (!result) { + MakeOTATrustError(assetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternalComponent, + @"Unknown error occurred."); + } + } + } + return result; +} + +static void TriggerUnlockNotificationOTATrustAssetCheck(NSString* assetType, dispatch_queue_t queue) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + /* If the last check-in is recent enough, wait for our regularly scheduled check-in. */ + if (SecOTAPKIAssetStalenessLessThanSeconds(otapkiref, kSecOTAPKIAssetStalenessAtRisk)) { + CFReleaseNull(otapkiref); + return; + } + CFReleaseNull(otapkiref); +#if !TARGET_OS_SIMULATOR + /* register for unlock notifications */ + int out_token = 0; + notify_register_dispatch(kMobileKeyBagLockStatusNotificationID, &out_token, queue, ^(int token) { + secnotice("OTATrust", "Got lock status notification for at-risk last check-in after MA daemon error"); + (void)DownloadOTATrustAsset(NO, NO, assetType, nil); + notify_cancel(token); + }); +#endif +} + +static bool InitializeKillSwitch(NSString *key) { +#if !TARGET_OS_BRIDGE + NSError *error = nil; + NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&error]; + if (isNSDictionary(OTAPKIContext)) { + NSNumber *killSwitchValue = OTAPKIContext[key]; + if (isNSNumber(killSwitchValue)) { + secinfo("OTATrust", "found on-disk kill switch %{public}@ with value %d", key, [killSwitchValue boolValue]); + return [killSwitchValue boolValue]; + } else { + MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, + @"OTAContext.plist missing check-in"); + } + } else { + MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, + @"OTAContext.plist missing dictionary"); + } +#endif + return false; +} + +static void InitializeOTATrustAsset(dispatch_queue_t queue) { + /* Only the "system" trustd does updates */ + if (SecOTAPKIIsSystemTrustd()) { + /* Asynchronously ask MobileAsset for most recent asset. */ + dispatch_async(queue, ^{ + secnotice("OTATrust", "Initial check with MobileAsset for newer PKITrustSupplementals asset"); + (void)DownloadOTATrustAsset(NO, NO, OTATrustMobileAssetType, nil); + }); + + /* Register for changes in our asset */ + if (CanCheckMobileAsset()) { + int out_token = 0; + notify_register_dispatch(kOTATrustMobileAssetNotification, &out_token, queue, ^(int __unused token) { + secnotice("OTATrust", "Got notification about a new PKITrustSupplementals asset from mobileassetd."); + (void)DownloadOTATrustAsset(YES, NO, OTATrustMobileAssetType, nil); + }); + } + } else { + /* Register for changes signaled by the system trustd */ + secnotice("OTATrust", "Initializing listener for PKI Asset changes from system trustd."); + int out_token = 0; + notify_register_dispatch(kOTATrustOnDiskAssetNotification, &out_token, queue, ^(int __unused token) { + secnotice("OTATrust", "Got notification about a new PKITrustSupplementals asset from system trustd."); + NSError *nserror = nil; + CFErrorRef error = nil; + NSNumber *asset_version = [NSNumber numberWithUnsignedLongLong:GetAssetVersion(&error)]; + if (error) { + nserror = CFBridgingRelease(error); + } + if (!UpdateFromAsset(GetAssetFileURL(nil), asset_version, &nserror)) { + secerror("OTATrust: failed to update from asset after notification: %@", nserror); + /* Reset our last check-in time and reset the asset version to the system asset version -- even + * though we may be using something newer than that (but not as new as what's on disk). On re-launch + * (provided reading from disk still fails) we'd be using the system asset version anyway. */ + SecOTAPKIResetCurrentAssetVersion(&error); + } + }); + int out_token2 = 0; + notify_register_dispatch(kOTATrustCheckInNotification, &out_token2, queue, ^(int __unused token) { + secinfo("OTATrust", "Got notification about successful PKITrustSupplementals asset check-in"); + (void)UpdateOTACheckInDate(); + }); + int out_token3 = 0; + notify_register_dispatch(kOTATrustKillSwitchNotification, &out_token3, queue, ^(int __unused token) { + UpdateKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT, InitializeKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT)); + }); + } +} + +static void InitializeOTASecExperimentAsset(dispatch_queue_t queue) { + /* Only the "system" trustd does updates */ + if (SecOTAPKIIsSystemTrustd()) { + /* Asynchronously ask MobileAsset for most recent asset. */ + dispatch_async(queue, ^{ + secnotice("OTATrust", "Initial check with MobileAsset for newer SecExperiment asset"); + (void)DownloadOTATrustAsset(NO, NO, OTASecExperimentMobileAssetType, nil); + }); + } else { + /* Register for changes signaled by the system trustd */ + secnotice("OTATrust", "Initializing listener for SecExperiment Asset changes from system trustd."); + int out_token = 0; + notify_register_dispatch(kOTASecExperimentNewAssetNotification, &out_token, queue, ^(int __unused token) { + NSError *error = nil; + secnotice("OTATrust", "Got notification about a new SecExperiment asset from system trustd."); + MAAssetQuery *assetQuery = [[MAAssetQuery alloc] initWithType:OTASecExperimentMobileAssetType]; + [assetQuery returnTypes:MAInstalledOnly]; + MAQueryResult queryResult = [assetQuery queryMetaDataSync]; + + if (queryResult != MAQuerySuccessful) { + secerror("OTATrust: failed to update SecExperiment Asset after notification: %ld", (long)queryResult); + } else { + secnotice("OTATrust", "Updated SecExperiment asset successfully"); + for (MAAsset *asset in assetQuery.results) { + NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; + if (!assetVersionCheck(OTASecExperimentMobileAssetType, asset)) { + continue; + } + UpdateAndPurgeAsset(OTASecExperimentMobileAssetType, asset, asset_version, &error); + } + } + }); + } +} + +static void TriggerPeriodicOTATrustAssetChecks(dispatch_queue_t queue) { + if (SecOTAPKIIsSystemTrustd()) { + static sec_action_t action; + static bool first_launch = true; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + NSNumber *updateDeltas = [defaults valueForKey:@"PKITrustSupplementalsUpdatePeriod"]; + int delta = kOTATrustDefaultUpdatePeriod; + if (isNSNumber(updateDeltas)) { + delta = [updateDeltas intValue]; + if (delta < kOTATrustMinimumUpdatePeriod) { + delta = kOTATrustMinimumUpdatePeriod; + } + } + secnotice("OTATrust", "Setting periodic update delta to %d seconds", delta); + action = sec_action_create_with_queue(queue,"OTATrust", delta); + sec_action_set_handler(action, ^{ + if (!first_launch) { + (void)DownloadOTATrustAsset(NO, NO, OTASecExperimentMobileAssetType, nil); + (void)DownloadOTATrustAsset(NO, NO, OTATrustMobileAssetType, nil); + } + first_launch = false; + }); + }); + sec_action_perform(action); + } +} +#endif /* !TARGET_OS_BRIDGE */ + +/* MARK: - */ +/* MARK: Initialization functions */ +static CFPropertyListRef CFPropertyListCopyFromSystem(CFStringRef asset) { + CFPropertyListRef plist = NULL; + CFDataRef xmlData = SecSystemTrustStoreCopyResourceContents(asset, CFSTR("plist"), NULL); + + if (xmlData) { + plist = CFPropertyListCreateWithData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL, NULL); + CFRelease(xmlData); + } + + return plist; +} + +static uint64_t GetSystemVersion(CFStringRef key) { + uint64_t system_version = 0; + int64_t asset_number = 0; + + CFDataRef assetVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL); + if (NULL != assetVersionData) { + CFPropertyListFormat propFormat; + CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, assetVersionData, 0, &propFormat, NULL); + if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist)) { + CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)key); + if (NULL != versionNumber){ + CFNumberGetValue(versionNumber, kCFNumberSInt64Type, &asset_number); + if (asset_number < 0) { // Not valid + asset_number = 0; + } + system_version = (uint64_t)asset_number; + } + } + CFReleaseSafe(versionPlist); + CFReleaseSafe(assetVersionData); + } + + return system_version; +} + +static bool initialization_error_from_asset_data = false; + +static bool ShouldInitializeWithAsset(void) { + uint64_t system_version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); + uint64_t asset_version = GetAssetVersion(nil); + + if (asset_version > system_version) { + secnotice("OTATrust", "Using asset v%llu instead of system v%llu", asset_version, system_version); + return !initialization_error_from_asset_data; + } + return false; +} + +static CFSetRef CFSetCreateFromPropertyList(CFPropertyListRef plist) { + CFSetRef result = NULL; + + if (plist) { + CFMutableSetRef tempSet = NULL; + if (CFGetTypeID(plist) == CFArrayGetTypeID()) { + tempSet = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks); + if (NULL == tempSet) { + return result; + } + CFArrayRef array = (CFArrayRef)plist; + CFIndex num_keys = CFArrayGetCount(array); + for (CFIndex idx = 0; idx < num_keys; idx++) { + CFDataRef data = (CFDataRef)CFArrayGetValueAtIndex(array, idx); + CFSetAddValue(tempSet, data); + } + } else { + return result; + } + + result = tempSet; + } + return result; +} + +static CF_RETURNS_RETAINED CFSetRef InitializeBlackList() { + CFPropertyListRef plist = CFPropertyListCopyFromSystem(CFSTR("Blocked")); + CFSetRef result = CFSetCreateFromPropertyList(plist); + CFReleaseSafe(plist); + + return result; +} + +static CF_RETURNS_RETAINED CFSetRef InitializeGrayList() { + CFPropertyListRef plist = CFPropertyListCopyFromSystem(CFSTR("GrayListedKeys")); + CFSetRef result = CFSetCreateFromPropertyList(plist); + CFReleaseSafe(plist); + + return result; +} + +static CF_RETURNS_RETAINED CFURLRef InitializePinningList() { + return SecSystemTrustStoreCopyResourceURL(CFSTR("CertificatePinning"), CFSTR("plist"), NULL); +} + +static CF_RETURNS_RETAINED CFDictionaryRef InitializeAllowList() { + CFPropertyListRef allowList = CFPropertyListCopyFromSystem(CFSTR("Allowed")); + + if (allowList && (CFGetTypeID(allowList) == CFDictionaryGetTypeID())) { + return allowList; + } else { + CFReleaseNull(allowList); + return NULL; + } +} + +static NSDictionary *ConvertTrustedCTLogsArrayToDictionary(NSArray *trustedLogsArray) { + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:trustedLogsArray.count]; + [trustedLogsArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (!isNSDictionary(obj)) { + secerror("OTATrust: failed to read entry from trusted CT logs array at index %lu", (unsigned long)idx); + return; + } + NSDictionary *log_data = (NSDictionary *)obj; + NSData *log_id = log_data[@"log_id"]; + if (!isNSData(log_id)) { + secinfo("OTATrust", "failed to read log_id from trusted CT log array entry at index %lu, computing log_id", (unsigned long)idx); + // We can make the log_id from the key + NSData *key = log_data[@"key"]; + if (!isNSData(key)) { + secerror("failed to read key from trusted CT log array entry at index %lu", (unsigned long)idx); + return; + } + log_id = CFBridgingRelease(SecSHA256DigestCreateFromData(NULL, (__bridge CFDataRef)key)); + } + [result setObject:log_data forKey:log_id]; + }]; + return result; +} + +CFDictionaryRef SecOTAPKICreateTrustedCTLogsDictionaryFromArray(CFArrayRef trustedCTLogsArray) +{ + @autoreleasepool { + return CFBridgingRetain(ConvertTrustedCTLogsArrayToDictionary((__bridge NSArray*)trustedCTLogsArray)); + } +} + +static CF_RETURNS_RETAINED CFDictionaryRef InitializeTrustedCTLogs() { + @autoreleasepool { + NSArray *trustedCTLogs = nil; + NSError *error = nil; +#if !TARGET_OS_BRIDGE + if (ShouldInitializeWithAsset()) { + trustedCTLogs = [NSArray arrayWithContentsOfURL:GetAssetFileURL(kOTATrustTrustedCTLogsFilename) error:&error]; + if (!isNSArray(trustedCTLogs)) { + secerror("OTATrust: failed to read CT list from asset data: %@", error); + LogRemotely(OTATrustLogLevelError, &error); + if (!DeleteAssetFromDisk()) { + initialization_error_from_asset_data = true; + } + } + } +#endif + if (!isNSArray(trustedCTLogs)) { + trustedCTLogs = [NSArray arrayWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustTrustedCTLogsFilename)]; + } + if (isNSArray(trustedCTLogs)) { + return CFBridgingRetain(ConvertTrustedCTLogsArrayToDictionary(trustedCTLogs)); + } + return NULL; + } +} + +static CF_RETURNS_RETAINED CFDictionaryRef InitializeEVPolicyToAnchorDigestsTable() { + CFDictionaryRef result = NULL; + CFPropertyListRef evroots = CFPropertyListCopyFromSystem(CFSTR("EVRoots")); + + if (evroots) { + if (CFGetTypeID(evroots) == CFDictionaryGetTypeID()) { + /* @@@ Ensure that each dictionary key is a dotted list of digits, + each value is an NSArrayRef and each element in the array is a + 20 byte digest. */ + result = (CFDictionaryRef)evroots; + } + else { + secwarning("EVRoot.plist is wrong type."); + CFRelease(evroots); + } + } + + return result; +} + +static CFIndex InitializeValidSnapshotVersion(CFIndex *outFormat) { + CFIndex validVersion = 0; + CFIndex validFormat = 0; + CFDataRef validVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("ValidUpdate"), CFSTR("plist"), NULL); + if (NULL != validVersionData) + { + CFPropertyListFormat propFormat; + CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, validVersionData, 0, &propFormat, NULL); + if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist)) + { + CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Version")); + if (NULL != versionNumber) + { + CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &validVersion); + } + CFNumberRef formatNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Format")); + if (NULL != formatNumber) + { + CFNumberGetValue(formatNumber, kCFNumberCFIndexType, &validFormat); + } + } + CFReleaseSafe(versionPlist); + CFReleaseSafe(validVersionData); + } + if (outFormat) { + *outFormat = validFormat; + } + return validVersion; +} + +static Boolean PathExists(const char* path, size_t* pFileSize) { + const char *checked_path = (path) ? path : ""; + Boolean result = false; + struct stat sb; + + if (NULL != pFileSize) { + *pFileSize = 0; + } + + int stat_result = stat(checked_path, &sb); + result = (stat_result == 0); + + if (result && !S_ISDIR(sb.st_mode)) { + // It is a file + if (NULL != pFileSize) { + *pFileSize = (size_t)sb.st_size; + } + } + + return result; +} + +static const char* InitializeValidSnapshotData(CFStringRef filename_str) { + char *result = NULL; + const char *base_error_str = "could not get valid snapshot"; + + CFURLRef valid_url = SecSystemTrustStoreCopyResourceURL(filename_str, CFSTR("sqlite3"), NULL); + if (NULL == valid_url) { + secerror("%s", base_error_str); + } else { + CFStringRef valid_str = CFURLCopyFileSystemPath(valid_url, kCFURLPOSIXPathStyle); + char file_path_buffer[PATH_MAX]; + memset(file_path_buffer, 0, PATH_MAX); + if (NULL == valid_str) { + secerror("%s path", base_error_str); + } else { + const char *valid_cstr = CFStringGetCStringPtr(valid_str, kCFStringEncodingUTF8); + if (NULL == valid_cstr) { + if (CFStringGetCString(valid_str, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8)) { + valid_cstr = file_path_buffer; + } + } + if (NULL == valid_cstr) { + secerror("%s path as UTF8 string", base_error_str); + } else { + asprintf(&result, "%s", valid_cstr); + } + } + CFReleaseSafe(valid_str); + } + CFReleaseSafe(valid_url); + if (result && !PathExists(result, NULL)) { + free(result); + result = NULL; + } + return (const char*)result; +} + +static const char* InitializeValidDatabaseSnapshot() { + return InitializeValidSnapshotData(CFSTR("valid")); +} + +static const uint8_t* MapFile(const char* path, size_t* out_file_size) { + int rtn, fd; + const uint8_t *buf = NULL; + struct stat sb; + size_t size = 0; + + if (NULL == path || NULL == out_file_size) { + return NULL; + } + + *out_file_size = 0; + + fd = open(path, O_RDONLY); + if (fd < 0) { return NULL; } + rtn = fstat(fd, &sb); + if (rtn || (sb.st_size > (off_t) ((UINT32_MAX >> 1)-1))) { + close(fd); + return NULL; + } + size = (size_t)sb.st_size; + + buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!buf || buf == MAP_FAILED) { + secerror("unable to map %s (errno %d)", path, errno); + close(fd); + return NULL; + } + + close(fd); + *out_file_size = size; + return buf; +} + +static void UnMapFile(void* mapped_data, size_t data_size) { + if (!mapped_data) { + return; + } + int rtn = munmap(mapped_data, data_size); + if (rtn != 0) { + secerror("unable to unmap %ld bytes at %p (error %d)", data_size, mapped_data, rtn); + } +} + +struct index_record { + unsigned char hash[CC_SHA1_DIGEST_LENGTH]; + uint32_t offset; +}; +typedef struct index_record index_record; + +static bool InitializeAnchorTable(CFDictionaryRef* pLookupTable, const char** ppAnchorTable) { + + bool result = false; + + if (NULL == pLookupTable || NULL == ppAnchorTable) { + return result; + } + + *pLookupTable = NULL; + *ppAnchorTable = NULL;; + + CFDataRef cert_index_file_data = NULL; + char file_path_buffer[PATH_MAX]; + CFURLRef table_data_url = NULL; + CFStringRef table_data_cstr_path = NULL; + const char* table_data_path = NULL; + const index_record* pIndex = NULL; + size_t index_offset = 0; + size_t index_data_size = 0; + CFMutableDictionaryRef anchorLookupTable = NULL; + uint32_t offset_int_value = 0; + CFNumberRef index_offset_value = NULL; + CFDataRef index_hash = NULL; + CFMutableArrayRef offsets = NULL; + Boolean release_offset = false; + + char* local_anchorTable = NULL; + size_t local_anchorTableSize = 0; + + // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used. + CFReleaseSafe(cert_index_file_data); + cert_index_file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL); + if (!cert_index_file_data) { + secerror("could not find certsIndex"); + } + table_data_url = SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL); + if (!table_data_url) { + secerror("could not find certsTable"); + } + + if (NULL != table_data_url) { + table_data_cstr_path = CFURLCopyFileSystemPath(table_data_url, kCFURLPOSIXPathStyle); + if (NULL != table_data_cstr_path) { + memset(file_path_buffer, 0, PATH_MAX); + table_data_path = CFStringGetCStringPtr(table_data_cstr_path, kCFStringEncodingUTF8); + if (NULL == table_data_path) { + if (CFStringGetCString(table_data_cstr_path, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8)) { + table_data_path = file_path_buffer; + } + } + local_anchorTable = (char *)MapFile(table_data_path, &local_anchorTableSize); + CFReleaseSafe(table_data_cstr_path); + } + } + CFReleaseSafe(table_data_url); + + if (NULL == local_anchorTable || NULL == cert_index_file_data) { + // we are in trouble + if (NULL != local_anchorTable) { + UnMapFile(local_anchorTable, local_anchorTableSize); + local_anchorTable = NULL; + local_anchorTableSize = 0; + } + CFReleaseSafe(cert_index_file_data); + return result; + } + + // ------------------------------------------------------------------------ + // Now that the locations of the files are known and the table file has + // been mapped into memory, create a dictionary that maps the SHA1 hash of + // normalized issuer to the offset in the mapped anchor table file which + // contains a index_record to the correct certificate + // ------------------------------------------------------------------------ + pIndex = (const index_record*)CFDataGetBytePtr(cert_index_file_data); + index_data_size = CFDataGetLength(cert_index_file_data); + + anchorLookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + for (index_offset = index_data_size; index_offset > 0; index_offset -= sizeof(index_record), pIndex++) { + offset_int_value = pIndex->offset; + + index_offset_value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &offset_int_value); + index_hash = CFDataCreate(kCFAllocatorDefault, pIndex->hash, CC_SHA1_DIGEST_LENGTH); + + // see if the dictionary already has this key + release_offset = false; + offsets = (CFMutableArrayRef)CFDictionaryGetValue(anchorLookupTable, index_hash); + if (NULL == offsets) { + offsets = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + release_offset = true; + } + + // Add the offset + CFArrayAppendValue(offsets, index_offset_value); + + // set the key value pair in the dictionary + CFDictionarySetValue(anchorLookupTable, index_hash, offsets); + + CFRelease(index_offset_value); + CFRelease(index_hash); + if (release_offset) { + CFRelease(offsets); + } + } + + CFRelease(cert_index_file_data); + + if (NULL != anchorLookupTable && NULL != local_anchorTable) { + *pLookupTable = anchorLookupTable; + *ppAnchorTable = local_anchorTable; + result = true; + } else { + CFReleaseSafe(anchorLookupTable); + if (NULL != local_anchorTable) { + UnMapFile(local_anchorTable, local_anchorTableSize); + local_anchorTable = NULL; + local_anchorTableSize = 0; + } + } + + return result; +} + +static void InitializeEscrowCertificates(CFArrayRef *escrowRoots, CFArrayRef *escrowPCSRoots) { + CFDataRef file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL); + + if (NULL == file_data) { + return; + } + + CFPropertyListFormat propFormat; + CFDictionaryRef certsDictionary = CFPropertyListCreateWithData(kCFAllocatorDefault, file_data, 0, &propFormat, NULL); + if (NULL != certsDictionary && CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef)certsDictionary)) { + CFArrayRef certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionEscrowKey")); + if (NULL != certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)certs) && CFArrayGetCount(certs) > 0) { + *escrowRoots = CFArrayCreateCopy(kCFAllocatorDefault, certs); + } + CFArrayRef pcs_certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionPCSEscrowKey")); + if (NULL != pcs_certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)pcs_certs) && CFArrayGetCount(pcs_certs) > 0) { + *escrowPCSRoots = CFArrayCreateCopy(kCFAllocatorDefault, pcs_certs); + } + } + CFReleaseSafe(certsDictionary); + CFRelease(file_data); +} + +static CF_RETURNS_RETAINED CFDictionaryRef InitializeEventSamplingRates() { + NSDictionary *analyticsSamplingRates = nil; + NSDictionary *eventSamplingRates = nil; + NSError *error = nil; +#if !TARGET_OS_BRIDGE + if (ShouldInitializeWithAsset()) { + analyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustAnalyticsSamplingRatesFilename) error:&error]; + if (!isNSDictionary(analyticsSamplingRates)) { + secerror("OTATrust: failed to read sampling rates from asset data: %@", error); + LogRemotely(OTATrustLogLevelError, &error); + if (!DeleteAssetFromDisk()) { + initialization_error_from_asset_data = true; + } + } + eventSamplingRates = analyticsSamplingRates[@"Events"]; + } +#endif + if (!isNSDictionary(eventSamplingRates)) { + analyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustAnalyticsSamplingRatesFilename)]; + } + if (isNSDictionary(analyticsSamplingRates)) { + eventSamplingRates = analyticsSamplingRates[@"Events"]; + if (isNSDictionary(eventSamplingRates)) { + return CFBridgingRetain(eventSamplingRates); + } + } + return NULL; +} + +static CF_RETURNS_RETAINED CFArrayRef InitializeAppleCertificateAuthorities() { + NSArray *appleCAs = nil; + NSError *error = nil; +#if !TARGET_OS_BRIDGE + if (ShouldInitializeWithAsset()) { + appleCAs = [NSArray arrayWithContentsOfURL:GetAssetFileURL(kOTATrustAppleCertifcateAuthoritiesFilename) error:&error]; + if (!isNSArray(appleCAs)) { + secerror("OTATrust: failed to read Apple CAs list from asset data: %@", error); + LogRemotely(OTATrustLogLevelError, &error); + if (!DeleteAssetFromDisk()) { + initialization_error_from_asset_data = true; + } + } + } +#endif + if (!isNSArray(appleCAs)) { + appleCAs = [NSArray arrayWithContentsOfURL:SecSystemTrustStoreCopyResourceNSURL(kOTATrustAppleCertifcateAuthoritiesFilename)]; + } + if (isNSArray(appleCAs)) { + return CFBridgingRetain(appleCAs); + } + return NULL; +} + +/* MARK: - */ +/* MARK: SecOTA */ + +/* We keep track of one OTAPKI reference */ +static SecOTAPKIRef kCurrentOTAPKIRef = NULL; +/* This queue is for making changes to the OTAPKI reference */ +static dispatch_queue_t kOTAQueue = NULL; + +struct _OpaqueSecOTAPKI { + CFRuntimeBase _base; + CFSetRef _blackListSet; + CFSetRef _grayListSet; + CFDictionaryRef _allowList; + CFDictionaryRef _trustedCTLogs; + CFURLRef _pinningList; + CFArrayRef _escrowCertificates; + CFArrayRef _escrowPCSCertificates; + CFDictionaryRef _evPolicyToAnchorMapping; + CFDictionaryRef _anchorLookupTable; + const char* _anchorTable; + uint64_t _trustStoreVersion; + const char* _validDatabaseSnapshot; + CFIndex _validSnapshotVersion; + CFIndex _validSnapshotFormat; + uint64_t _assetVersion; + CFDateRef _lastAssetCheckIn; + CFDictionaryRef _eventSamplingRates; + CFArrayRef _appleCAs; + CFDictionaryRef _secExperimentConfig; + uint64_t _secExperimentAssetVersion; + bool _ctKillSwitch; +}; + +CFGiblisFor(SecOTAPKI) + +static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf; + return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR(""), + otapkiRef->_trustStoreVersion, otapkiRef->_assetVersion); +} + +static void SecOTAPKIDestroy(CFTypeRef cf) { + SecOTAPKIRef otapkiref = (SecOTAPKIRef)cf; + + CFReleaseNull(otapkiref->_blackListSet); + CFReleaseNull(otapkiref->_grayListSet); + CFReleaseNull(otapkiref->_escrowCertificates); + CFReleaseNull(otapkiref->_escrowPCSCertificates); + + CFReleaseNull(otapkiref->_evPolicyToAnchorMapping); + CFReleaseNull(otapkiref->_anchorLookupTable); + + CFReleaseNull(otapkiref->_trustedCTLogs); + CFReleaseNull(otapkiref->_pinningList); + CFReleaseNull(otapkiref->_eventSamplingRates); + CFReleaseNull(otapkiref->_appleCAs); + CFReleaseNull(otapkiref->_lastAssetCheckIn); + CFReleaseNull(otapkiref->_secExperimentConfig); + + if (otapkiref->_anchorTable) { + free((void *)otapkiref->_anchorTable); + otapkiref->_anchorTable = NULL; + } + if (otapkiref->_validDatabaseSnapshot) { + free((void *)otapkiref->_validDatabaseSnapshot); + otapkiref->_validDatabaseSnapshot = NULL; + } +} + +static uint64_t GetSystemTrustStoreVersion(void) { + return GetSystemVersion(CFSTR("VersionNumber")); +} + +static uint64_t GetAssetVersion(CFErrorRef *error) { + @autoreleasepool { + /* Get system asset version */ + uint64_t version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); + +#if !TARGET_OS_BRIDGE + uint64_t asset_version = 0; + NSError *nserror = nil; + NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&nserror]; + if (isNSDictionary(OTAPKIContext)) { + NSNumber *tmpNumber = OTAPKIContext[kOTATrustContentVersionKey]; + if (isNSNumber(tmpNumber)) { + asset_version = [tmpNumber unsignedLongLongValue]; + } else if (error) { + MakeOTATrustError(OTATrustMobileAssetType, &nserror, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, + @"OTAContext.plist missing version"); + } + } else if (error) { + MakeOTATrustError(OTATrustMobileAssetType, &nserror, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, + @"OTAContext.plist missing dictionary"); + } + + if (asset_version > version) { + return asset_version; + } else { + /* Don't delete the last check-in time so that we know we're up to date with the MobileAsset. */ + if (error) { + /* only log this if we're tracking errors */ + secnotice("OTATrust", "asset (%llu) is not newer than the system version (%llu); deleting stale data", asset_version, version); + *error = CFRetainSafe((__bridge CFErrorRef)nserror); + } + DeleteOldAssetData(); + } +#endif + return version; + } +} + +static CF_RETURNS_RETAINED CFDateRef InitializeLastAssetCheckIn(void) { +#if !TARGET_OS_BRIDGE + NSError *error = nil; + NSDictionary *OTAPKIContext = [NSDictionary dictionaryWithContentsOfURL:GetAssetFileURL(kOTATrustContextFilename) error:&error]; + if (isNSDictionary(OTAPKIContext)) { + NSDate *checkIn = OTAPKIContext[kOTATrustLastCheckInKey]; + if (isNSDate(checkIn)) { + return CFRetainSafe((__bridge CFDateRef)checkIn); + } else { + MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecInvalidValue, + @"OTAContext.plist missing check-in"); + } + } else { + MakeOTATrustError(OTATrustMobileAssetType, &error, OTATrustLogLevelNotice, NSOSStatusErrorDomain, errSecMissingValue, + @"OTAContext.plist missing dictionary"); + } +#endif + return NULL; +} + +static SecOTAPKIRef SecOTACreate() { + + SecOTAPKIRef otapkiref = NULL; + + otapkiref = CFTypeAllocate(SecOTAPKI, struct _OpaqueSecOTAPKI , kCFAllocatorDefault); + + if (NULL == otapkiref) { + return otapkiref; + } + + // Make sure that if this routine has to bail that the clean up + // will do the right thing + memset(otapkiref, 0, sizeof(*otapkiref)); + + // Start off by getting the trust store version + otapkiref->_trustStoreVersion = GetSystemTrustStoreVersion(); + + // Get the set of black listed keys + CFSetRef blackKeysSet = InitializeBlackList(); + if (NULL == blackKeysSet) { + CFReleaseNull(otapkiref); + return otapkiref; + } + otapkiref->_blackListSet = blackKeysSet; + + // Get the set of gray listed keys + CFSetRef grayKeysSet = InitializeGrayList(); + if (NULL == grayKeysSet) { + CFReleaseNull(otapkiref); + return otapkiref; + } + otapkiref->_grayListSet = grayKeysSet; + + // Get the allow list dictionary + // (now loaded lazily in SecOTAPKICopyAllowList) + + // Get the trusted Certificate Transparency Logs + otapkiref->_trustedCTLogs = InitializeTrustedCTLogs(); + + // Get the pinning list + otapkiref->_pinningList = InitializePinningList(); + + // Get the Event Sampling Rates + otapkiref->_eventSamplingRates = InitializeEventSamplingRates(); + + // Get the list of CAs used by Apple + otapkiref->_appleCAs = InitializeAppleCertificateAuthorities(); + + // Get the asset version (after possible reset due to missing asset data) + if (!initialization_error_from_asset_data) { + CFErrorRef error = nil; + otapkiref->_assetVersion = GetAssetVersion(&error); + otapkiref->_lastAssetCheckIn = InitializeLastAssetCheckIn(); + CFReleaseNull(error); + } else { + otapkiref->_assetVersion = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); + } + otapkiref->_secExperimentAssetVersion = 0; + // Get the valid update snapshot version and format + CFIndex update_format = 0; + otapkiref->_validSnapshotVersion = InitializeValidSnapshotVersion(&update_format); + otapkiref->_validSnapshotFormat = update_format; + + // Get the valid database snapshot path (if it exists, NULL otherwise) + otapkiref->_validDatabaseSnapshot = InitializeValidDatabaseSnapshot(); + + CFArrayRef escrowCerts = NULL; + CFArrayRef escrowPCSCerts = NULL; + InitializeEscrowCertificates(&escrowCerts, &escrowPCSCerts); + if (NULL == escrowCerts || NULL == escrowPCSCerts) { + CFReleaseNull(escrowCerts); + CFReleaseNull(escrowPCSCerts); + CFReleaseNull(otapkiref); + return otapkiref; + } + otapkiref->_escrowCertificates = escrowCerts; + otapkiref->_escrowPCSCertificates = escrowPCSCerts; + + // Get the mapping of EV Policy OIDs to Anchor digest + CFDictionaryRef evOidToAnchorDigestMap = InitializeEVPolicyToAnchorDigestsTable(); + if (NULL == evOidToAnchorDigestMap) { + CFReleaseNull(otapkiref); + return otapkiref; + } + otapkiref->_evPolicyToAnchorMapping = evOidToAnchorDigestMap; + + CFDictionaryRef anchorLookupTable = NULL; + const char* anchorTablePtr = NULL; + + if (!InitializeAnchorTable(&anchorLookupTable, &anchorTablePtr)) { + CFReleaseSafe(anchorLookupTable); + if (anchorTablePtr) { + free((void *)anchorTablePtr); + } + CFReleaseNull(otapkiref); + return otapkiref; + } + otapkiref->_anchorLookupTable = anchorLookupTable; + otapkiref->_anchorTable = anchorTablePtr; + +#if !TARGET_OS_BRIDGE + /* Initialize our update handling */ + InitializeOTATrustAsset(kOTABackgroundQueue); + otapkiref->_ctKillSwitch = InitializeKillSwitch((__bridge NSString*)kOTAPKIKillSwitchCT); + InitializeOTASecExperimentAsset(kOTABackgroundQueue); +#else // TARGET_OS_BRIDGE + otapkiref->_ctKillSwitch = true; // bridgeOS never enforces CT +#endif // TARGET_OS_BRIDGE + + return otapkiref; +} + +SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef() { + __block SecOTAPKIRef result = NULL; + static dispatch_once_t kInitializeOTAPKI = 0; + dispatch_once(&kInitializeOTAPKI, ^{ + @autoreleasepool { + kOTAQueue = dispatch_queue_create("com.apple.security.OTAPKIQueue", NULL); + dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, + QOS_CLASS_BACKGROUND, 0); + attr = dispatch_queue_attr_make_with_autorelease_frequency(attr, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM); + kOTABackgroundQueue = dispatch_queue_create("com.apple.security.OTAPKIBackgroundQueue", attr); + if (!kOTAQueue || !kOTABackgroundQueue) { + secerror("Failed to create OTAPKI Queues. May crash later."); + } + dispatch_sync(kOTAQueue, ^{ + kCurrentOTAPKIRef = SecOTACreate(); + }); + } + }); + + dispatch_sync(kOTAQueue, ^{ + result = kCurrentOTAPKIRef; + CFRetainSafe(result); + }); + return result; +} + +#if !TARGET_OS_BRIDGE +BOOL UpdateOTACheckInDate(void) { + __block NSDate *checkIn = [NSDate date]; + dispatch_sync(kOTAQueue, ^{ + CFRetainAssign(kCurrentOTAPKIRef->_lastAssetCheckIn, (__bridge CFDateRef)checkIn); + }); + + if (SecOTAPKIIsSystemTrustd()) { + /* Let the other trustds know we successfully checked in */ + notify_post(kOTATrustCheckInNotification); + + /* Update the on-disk check-in date, so when we re-launch we remember */ + NSError *error = nil; + BOOL result = NO; + if (!(result = UpdateOTAContextOnDisk(kOTATrustLastCheckInKey, checkIn, &error))) { + secerror("OTATrust: failed to write last check-in time: %@", error); + } + return result; + } else { + return NO; + } +} + +void UpdateKillSwitch(NSString *key, bool value) { + dispatch_sync(kOTAQueue, ^{ + if ([key isEqualToString:(__bridge NSString*)kOTAPKIKillSwitchCT]) { + kCurrentOTAPKIRef->_ctKillSwitch = value; + } + }); +} + +static BOOL UpdateFromAsset(NSURL *localURL, NSNumber *asset_version, NSError **error) { + if (!localURL || !asset_version) { + MakeOTATrustError(OTATrustMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, + @"missing url and version for downloaded asset"); + return NO; + } + __block NSArray *newTrustedCTLogs = NULL; + __block uint64_t version = [asset_version unsignedLongLongValue]; + __block NSDictionary *newAnalyticsSamplingRates = NULL; + __block NSArray *newAppleCAs = NULL; + + NSURL *TrustedCTLogsFileLoc = [NSURL URLWithString:kOTATrustTrustedCTLogsFilename + relativeToURL:localURL]; + newTrustedCTLogs = [NSArray arrayWithContentsOfURL:TrustedCTLogsFileLoc error:error]; + if (!newTrustedCTLogs) { + secerror("OTATrust: unable to create TrustedCTLogs from asset file: %@", error ? *error: nil); + LogRemotely(OTATrustLogLevelError, error); + return NO; + } + + NSURL *AnalyticsSamplingRatesFileLoc = [NSURL URLWithString:kOTATrustAnalyticsSamplingRatesFilename + relativeToURL:localURL]; + newAnalyticsSamplingRates = [NSDictionary dictionaryWithContentsOfURL:AnalyticsSamplingRatesFileLoc error:error]; + if (!newAnalyticsSamplingRates) { + secerror("OTATrust: unable to create AnalyticsSamplingRates from asset file: %@", error ? *error: nil); + LogRemotely(OTATrustLogLevelError, error); + return NO; + } + + NSURL *AppleCAsFileLoc = [NSURL URLWithString:kOTATrustAppleCertifcateAuthoritiesFilename + relativeToURL:localURL]; + newAppleCAs = [NSArray arrayWithContentsOfURL:AppleCAsFileLoc error:error]; + if (!newAppleCAs) { + secerror("OTATrust: unable to create AppleCAs from asset file: %@", error ? *error: nil); + LogRemotely(OTATrustLogLevelError, error); + return NO; + } + + /* Update the Current OTAPKIRef with the new data */ + dispatch_sync(kOTAQueue, ^{ + secnotice("OTATrust", "updating asset version from %llu to %llu", kCurrentOTAPKIRef->_assetVersion, version); + CFRetainAssign(kCurrentOTAPKIRef->_trustedCTLogs, (__bridge CFDictionaryRef)ConvertTrustedCTLogsArrayToDictionary(newTrustedCTLogs)); + CFRetainAssign(kCurrentOTAPKIRef->_eventSamplingRates, (__bridge CFDictionaryRef)newAnalyticsSamplingRates); + CFRetainAssign(kCurrentOTAPKIRef->_appleCAs, (__bridge CFArrayRef)newAppleCAs); + kCurrentOTAPKIRef->_assetVersion = version; + }); + + /* Write the data to disk (so that we don't have to re-download the asset on re-launch) */ + DeleteAssetFromDisk(); + if (CopyFileToDisk(kOTATrustTrustedCTLogsFilename, TrustedCTLogsFileLoc, error) && + CopyFileToDisk(kOTATrustAnalyticsSamplingRatesFilename, AnalyticsSamplingRatesFileLoc, error) && + CopyFileToDisk(kOTATrustAppleCertifcateAuthoritiesFilename, AppleCAsFileLoc, error) && + UpdateOTAContext(asset_version, error)) { // Set version and check-in time last (after success) + /* If we successfully updated the "asset" on disk, signal the other trustds to pick up the changes */ + notify_post(kOTATrustOnDiskAssetNotification); + } else { + return NO; + } + + return YES; +} +#endif // !TARGET_OS_BRIDGE + +#if !TARGET_OS_BRIDGE +static NSNumber *SecExperimentUpdateAsset(MAAsset *asset, NSNumber *asset_version, NSError **error) { + NSURL *localURL = [asset getLocalFileUrl]; + if (!localURL || !asset_version) { + MakeOTATrustError(OTASecExperimentMobileAssetType, error, OTATrustLogLevelError, NSOSStatusErrorDomain, errSecInternal, + @"missing url and version for downloaded SecExperiment asset"); + return nil; + } + NSDictionary *newSecExpConfig = NULL; + uint64_t version = [asset_version unsignedLongLongValue]; + + NSURL *secExpConfigFileLoc = [NSURL URLWithString:kOTASecExperimentConfigFilename + relativeToURL:localURL]; + newSecExpConfig = [NSDictionary dictionaryWithContentsOfURL:secExpConfigFileLoc error:error]; + if (!newSecExpConfig) { + secerror("OTATrust: unable to create SecExperiment from asset file: %@", error ? *error: nil); + return nil; + } + /* Update the Current OTAPKIRef with the new data */ + dispatch_sync(kOTAQueue, ^{ + secnotice("OTATrust", "updating SecExperiment asset version from %llu to %llu", kCurrentOTAPKIRef->_secExperimentAssetVersion, version); + CFRetainAssign(kCurrentOTAPKIRef->_secExperimentConfig, (__bridge CFDictionaryRef)newSecExpConfig); + kCurrentOTAPKIRef->_secExperimentAssetVersion = version; + }); + /* Signal the other trustds to pick up the changes */ + notify_post(kOTASecExperimentNewAssetNotification); + return asset_version; +} +#endif // !TARGET_OS_BRIDGE + +CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return CFRetainSafe(otapkiRef->_blackListSet); +} + + +CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return CFRetainSafe(otapkiRef->_grayListSet); +} + +CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + CFDictionaryRef result = otapkiRef->_allowList; + if (!result) { + result = InitializeAllowList(); + otapkiRef->_allowList = result; + } + + return CFRetainSafe(result); +} + +CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID) { + // %%% temporary performance optimization: + // only load dictionary if we know an allow list exists for this key + const CFStringRef keyIDs[3] = { + CFSTR("7C724B39C7C0DB62A54F9BAA183492A2CA838259"), + CFSTR("65F231AD2AF7F7DD52960AC702C10EEFA6D53B11"), + CFSTR("D2A716207CAFD9959EEB430A19F2E0B9740EA8C7") + }; + CFArrayRef result = NULL; + bool hasAllowList = false; + CFIndex count = (sizeof(keyIDs) / sizeof(keyIDs[0])); + for (CFIndex ix=0; ix_trustedCTLogs; + CFRetainSafe(result); + return result; +} + +CFURLRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return CFRetainSafe(otapkiRef->_pinningList); +} + + +/* Returns an array of certificate data (CFDataRef) */ +CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef) { + CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if (NULL == otapkiRef) { + return result; + } + + switch (escrowRootType) { + // Note: we shouldn't be getting called to return baseline roots, + // since this function vends production roots by definition. + case kSecCertificateBaselineEscrowRoot: + case kSecCertificateProductionEscrowRoot: + case kSecCertificateBaselineEscrowBackupRoot: + case kSecCertificateProductionEscrowBackupRoot: + if (otapkiRef->_escrowCertificates) { + CFArrayRef escrowCerts = otapkiRef->_escrowCertificates; + CFArrayAppendArray(result, escrowCerts, CFRangeMake(0, CFArrayGetCount(escrowCerts))); + } + break; + case kSecCertificateBaselineEscrowEnrollmentRoot: + case kSecCertificateProductionEscrowEnrollmentRoot: + if (otapkiRef->_escrowCertificates) { + // for enrollment purposes, exclude the v100 root + static const unsigned char V100EscrowRoot[] = { + 0x65,0x5C,0xB0,0x3C,0x39,0x3A,0x32,0xA6,0x0B,0x96, + 0x40,0xC0,0xCA,0x73,0x41,0xFD,0xC3,0x9E,0x96,0xB3 + }; + CFArrayRef escrowCerts = otapkiRef->_escrowCertificates; + CFIndex idx, count = CFArrayGetCount(escrowCerts); + for (idx=0; idx < count; idx++) { + CFDataRef tmpData = (CFDataRef) CFArrayGetValueAtIndex(escrowCerts, idx); + SecCertificateRef tmpCert = (tmpData) ? SecCertificateCreateWithData(NULL, tmpData) : NULL; + CFDataRef sha1Hash = (tmpCert) ? SecCertificateGetSHA1Digest(tmpCert) : NULL; + const uint8_t *dp = (sha1Hash) ? CFDataGetBytePtr(sha1Hash) : NULL; + if (!(dp && !memcmp(V100EscrowRoot, dp, sizeof(V100EscrowRoot))) && tmpData) { + CFArrayAppendValue(result, tmpData); + } + CFReleaseSafe(tmpCert); + } + } + break; + case kSecCertificateBaselinePCSEscrowRoot: + case kSecCertificateProductionPCSEscrowRoot: + if (otapkiRef->_escrowPCSCertificates) { + CFArrayRef escrowPCSCerts = otapkiRef->_escrowPCSCertificates; + CFArrayAppendArray(result, escrowPCSCerts, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts))); + } + break; + default: + break; + } + + return result; +} + + +CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return CFRetainSafe(otapkiRef->_evPolicyToAnchorMapping); +} + + +CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return CFRetainSafe(otapkiRef->_anchorLookupTable); +} + +const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return otapkiRef->_anchorTable; +} + +const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + + return otapkiRef->_validDatabaseSnapshot; +} + +CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return 0; + } + + return otapkiRef->_validSnapshotVersion; +} + +CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return 0; + } + + return otapkiRef->_validSnapshotFormat; +} + +uint64_t SecOTAPKIGetTrustStoreVersion(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return 0; + } + + return otapkiRef->_trustStoreVersion; +} + +uint64_t SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return 0; + } + + return otapkiRef->_assetVersion; +} + +CFDateRef SecOTAPKICopyLastAssetCheckInDate(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + return CFRetainSafe(otapkiRef->_lastAssetCheckIn); +} + +bool SecOTAPKIAssetStalenessLessThanSeconds(SecOTAPKIRef otapkiRef, CFTimeInterval seconds) { + if (NULL == otapkiRef) { + return false; + } + + bool result = false; + CFDateRef lastCheckIn = CFRetainSafe(otapkiRef->_lastAssetCheckIn); + if (isDate(lastCheckIn) && (fabs([(__bridge NSDate *)lastCheckIn timeIntervalSinceNow]) < seconds)) { + result = true; + } + CFReleaseNull(lastCheckIn); + return result; +} + +NSNumber *SecOTAPKIGetSamplingRateForEvent(SecOTAPKIRef otapkiRef, NSString *eventName) { + if (NULL == otapkiRef) { + return nil; + } + +#if !TARGET_OS_BRIDGE + /* Trigger periodic background MA checks in system trustd + * We also check on trustd launch and listen for notifications. */ + TriggerPeriodicOTATrustAssetChecks(kOTABackgroundQueue); +#endif + + if (otapkiRef->_eventSamplingRates) { + CFTypeRef value = CFDictionaryGetValue(otapkiRef->_eventSamplingRates, (__bridge CFStringRef)eventName); + if (isNumberOfType(value, kCFNumberSInt64Type)) { + return (__bridge NSNumber *)value; + } + } + return nil; +} + +CFArrayRef SecOTAPKICopyAppleCertificateAuthorities(SecOTAPKIRef otapkiRef) { + if (NULL == otapkiRef) { + return NULL; + } + +#if !TARGET_OS_BRIDGE + /* Trigger periodic background MA checks in system trustd + * We also check on trustd launch and listen for notifications. */ + TriggerPeriodicOTATrustAssetChecks(kOTABackgroundQueue); +#endif + + return CFRetainSafe(otapkiRef->_appleCAs); +} + +bool SecOTAPKIKillSwitchEnabled(SecOTAPKIRef otapkiRef, CFStringRef key) { + if (NULL == otapkiRef || NULL == key) { + return false; + } + if (CFEqualSafe(key, kOTAPKIKillSwitchCT)) { + return otapkiRef->_ctKillSwitch; + } + return false; +} + +/* Returns an array of certificate data (CFDataRef) */ +CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return NULL; + } + + CFArrayRef result = SecOTAPKICopyEscrowCertificates(escrowRootType, otapkiref); + CFRelease(otapkiref); + + if (NULL == result) { + SecError(errSecInternal, error, CFSTR("Could not get escrow certificates from the current OTAPKIRef")); + } + return result; +} + +static CF_RETURNS_RETAINED CFDictionaryRef convertDataKeysToBase64Strings(CFDictionaryRef CF_CONSUMED dictionaryWithDataKeys) { + @autoreleasepool { + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:((__bridge NSDictionary*)dictionaryWithDataKeys).count]; + NSDictionary *input = CFBridgingRelease(dictionaryWithDataKeys); + for (NSData *key in input) { + id obj = [input objectForKey:key]; + NSString *base64Key = [key base64EncodedStringWithOptions:0]; + result[base64Key] = obj; + } + return CFBridgingRetain(result); + } +} + +/* Returns an dictionary of dictionaries for currently trusted CT logs, indexed by the base64-encoded LogID */ +CFDictionaryRef SecOTAPKICopyCurrentTrustedCTLogs(CFErrorRef* error) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return NULL; + } + + CFDictionaryRef result = convertDataKeysToBase64Strings(SecOTAPKICopyTrustedCTLogs(otapkiref)); + CFReleaseSafe(otapkiref); + + if (NULL == result) { + SecError(errSecInternal, error, CFSTR("Could not get CT logs from the current OTAPKIRef")); + } + return result; +} + +/* Returns a dictionary for the CT log matching specified LogID */ +CFDictionaryRef SecOTAPKICopyCTLogForKeyID(CFDataRef keyID, CFErrorRef* error) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return NULL; + } + + CFDictionaryRef trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref); + CFReleaseNull(otapkiref); + if (!trustedLogs) { + return NULL; + } + CFDictionaryRef logDict = CFDictionaryGetValue(trustedLogs, keyID); + CFRetainSafe(logDict); + CFReleaseSafe(trustedLogs); + return logDict; +} + +uint64_t SecOTAPKIGetCurrentTrustStoreVersion(CFErrorRef* error){ + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return 0; + } + + uint64_t result = otapkiref->_trustStoreVersion; + CFReleaseNull(otapkiref); + return result; +} + +uint64_t SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return 0; + } + + uint64_t result = otapkiref->_assetVersion; + CFReleaseNull(otapkiref); + return result; +} + +uint64_t SecOTASecExperimentGetCurrentAssetVersion(CFErrorRef* error) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) { + SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef")); + return 0; + } + + uint64_t result = otapkiref->_secExperimentAssetVersion; + CFReleaseNull(otapkiref); + return result; + } + +uint64_t SecOTAPKIResetCurrentAssetVersion(CFErrorRef* error) { + uint64_t system_version = GetSystemVersion((__bridge CFStringRef)kOTATrustContentVersionKey); + + dispatch_sync(kOTAQueue, ^{ + kCurrentOTAPKIRef->_assetVersion = system_version; + CFReleaseNull(kCurrentOTAPKIRef->_lastAssetCheckIn); + kCurrentOTAPKIRef->_lastAssetCheckIn = NULL; + }); + +#if !TARGET_OS_BRIDGE + DeleteAssetFromDisk(); +#endif + return system_version; +} + +uint64_t SecOTAPKISignalNewAsset(CFErrorRef* error) { + NSError *nserror = nil; + uint64_t version = 0; +#if !TARGET_OS_BRIDGE + if (SecOTAPKIIsSystemTrustd()) { + if (!DownloadOTATrustAsset(NO, YES, OTATrustMobileAssetType, &nserror) && error) { + *error = CFRetainSafe((__bridge CFErrorRef)nserror); + } + } else { + SecError(errSecServiceNotAvailable, error, CFSTR("This function may only be performed by the system trustd.")); + } + version = GetAssetVersion(nil); +#else + SecError(errSecUnsupportedService, error, CFSTR("This function is not available on this platform")); + version = GetAssetVersion(error); +#endif + return version; +} + +uint64_t SecOTASecExperimentGetNewAsset(CFErrorRef* error) { + NSError *nserror = nil; +#if !TARGET_OS_BRIDGE + if (SecOTAPKIIsSystemTrustd()) { + if (!DownloadOTATrustAsset(NO, YES, OTASecExperimentMobileAssetType, &nserror) && error) { + *error = CFRetainSafe((__bridge CFErrorRef)nserror); + } + } else { + SecError(errSecServiceNotAvailable, error, CFSTR("This function may only be performed by the system trustd.")); + } +#else + SecError(errSecUnsupportedService, error, CFSTR("This function is not available on this platform")); +#endif + return SecOTASecExperimentGetCurrentAssetVersion(error); +} + +CFDictionaryRef SecOTASecExperimentCopyAsset(CFErrorRef* error) { + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiRef) { + secnotice("OTATrust", "Null otapkiref"); + return NULL; + } + CFDictionaryRef asset = NULL; + if (otapkiRef->_secExperimentConfig) { + asset = CFRetainSafe(otapkiRef->_secExperimentConfig); + secnotice("OTATrust", "asset found"); + } else { + secnotice("OTATrust", "asset NULL"); + } + CFReleaseNull(otapkiRef); + return asset; +} diff --git a/trust/trustd/SecCAIssuerCache.c b/trust/trustd/SecCAIssuerCache.c new file mode 100644 index 00000000..70175d40 --- /dev/null +++ b/trust/trustd/SecCAIssuerCache.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/* + * SecCAIssuerCache.c - securityd + */ + +#include "trust/trustd/SecCAIssuerCache.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilities/sqlutils.h" +#include "utilities/iOSforOSX.h" + +#include +#include +#include + +static const char expireSQL[] = "DELETE FROM issuers WHERE expires PATH_MAX) + return SQLITE_CANTOPEN; + memcpy(pathbuf, path, len); + for (pos = len-1; pos > 0; --pos) + { + /* Search backwards for trailing '/'. */ + if (pathbuf[pos] == '/') + { + pathbuf[pos] = '\0'; + /* Attempt to create parent directories of the database. */ + if (!mkdir(pathbuf, 0777)) + break; + else + { + int err = errno; + if (err == EEXIST) + return 0; + if (err == ENOTDIR) + return SQLITE_CANTOPEN; + if (err == EROFS) + return SQLITE_READONLY; + if (err == EACCES) + return SQLITE_PERM; + if (err == ENOSPC || err == EDQUOT) + return SQLITE_FULL; + if (err == EIO) + return SQLITE_IOERR; + + /* EFAULT || ELOOP | ENAMETOOLONG || something else */ + return SQLITE_INTERNAL; + } + } + } + return SQLITE_OK; +} + +static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h, + bool create_path) +{ + int s3e; + s3e = sqlite3_open(db_name, s3h); + if (s3e == SQLITE_CANTOPEN && create_path) { + /* Make sure the path to db_name exists and is writable, then + try again. */ + s3e = sec_create_path(db_name); + if (!s3e) + s3e = sqlite3_open(db_name, s3h); + } + + return s3e; +} + +static int sec_sqlite3_reset(sqlite3_stmt *stmt, int s3e) { + int s3e2; + if (s3e == SQLITE_ROW || s3e == SQLITE_DONE) + s3e = SQLITE_OK; + s3e2 = sqlite3_reset(stmt); + if (s3e2 && !s3e) + s3e = s3e2; + s3e2 = sqlite3_clear_bindings(stmt); + if (s3e2 && !s3e) + s3e = s3e2; + return s3e; +} + +static int SecCAIssuerCacheEnsureTxn(SecCAIssuerCacheRef this) { + int s3e, s3e2; + + if (this->in_transaction) + return SQLITE_OK; + + s3e = sqlite3_step(this->beginTxn); + if (s3e == SQLITE_DONE) { + this->in_transaction = true; + s3e = SQLITE_OK; + } else { + secdebug("caissuercache", "sqlite3_step returned [%d]: %s", s3e, + sqlite3_errmsg(this->s3h)); + } + s3e2 = sqlite3_reset(this->beginTxn); + if (s3e2 && !s3e) + s3e = s3e2; + + return s3e; +} + +static int SecCAIssuerCacheCommitTxn(SecCAIssuerCacheRef this) { + int s3e, s3e2; + + if (!this->in_transaction) + return SQLITE_OK; + + s3e = sqlite3_step(this->endTxn); + if (s3e == SQLITE_DONE) { + this->in_transaction = false; + s3e = SQLITE_OK; + } else { + secdebug("caissuercache", "sqlite3_step returned [%d]: %s", s3e, + sqlite3_errmsg(this->s3h)); + } + s3e2 = sqlite3_reset(this->endTxn); + if (s3e2 && !s3e) + s3e = s3e2; + + return s3e; +} + +static SecCAIssuerCacheRef SecCAIssuerCacheCreate(const char *db_name) { + SecCAIssuerCacheRef this; + int s3e = SQLITE_OK; + bool create = true; + + require(this = (SecCAIssuerCacheRef)calloc(sizeof(struct __SecCAIssuerCache), 1), errOut); + require_action_quiet((this->queue = dispatch_queue_create("caissuercache", 0)), errOut, s3e = errSecAllocate); + require_noerr(s3e = sec_sqlite3_open(db_name, &this->s3h, create), errOut); + this->in_transaction = false; + + s3e = sqlite3_prepare_v2(this->s3h, beginTxnSQL, sizeof(beginTxnSQL), + &this->beginTxn, NULL); + require_noerr(s3e, errOut); + s3e = sqlite3_prepare_v2(this->s3h, endTxnSQL, sizeof(endTxnSQL), + &this->endTxn, NULL); + require_noerr(s3e, errOut); + + s3e = sqlite3_prepare_v2(this->s3h, expireSQL, sizeof(expireSQL), + &this->expire, NULL); + if (create && s3e == SQLITE_ERROR) { + s3e = SecCAIssuerCacheEnsureTxn(this); + require_noerr(s3e, errOut); + + /* sqlite3_prepare returns SQLITE_ERROR if the table we are + compiling this statement for doesn't exist. */ + char *errmsg = NULL; + s3e = sqlite3_exec(this->s3h, + "CREATE TABLE issuers(" + "uri BLOB PRIMARY KEY," + "expires DOUBLE NOT NULL," + "certificate BLOB NOT NULL" + ");" + "CREATE INDEX iexpires ON issuers(expires);" + , NULL, NULL, &errmsg); + if (errmsg) { + secerror("caissuer db CREATE TABLES: %s", errmsg); + sqlite3_free(errmsg); + } + require_noerr(s3e, errOut); + s3e = sqlite3_prepare_v2(this->s3h, expireSQL, sizeof(expireSQL), + &this->expire, NULL); + } + require_noerr(s3e, errOut); + s3e = sqlite3_prepare_v2(this->s3h, insertIssuerSQL, sizeof(insertIssuerSQL), + &this->insertIssuer, NULL); + require_noerr(s3e, errOut); + s3e = sqlite3_prepare_v2(this->s3h, selectIssuerSQL, sizeof(selectIssuerSQL), + &this->selectIssuer, NULL); + require_noerr(s3e, errOut); + + return this; + +errOut: + if (s3e != SQLITE_OK) { + TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationCreate, TAFatalError, s3e); + } + if (this) { + if (this->queue) + dispatch_release(this->queue); + if (this->s3h) + sqlite3_close(this->s3h); + free(this); + } + + return NULL; +} + +static void SecCAIssuerCacheInit(void) { +#if TARGET_OS_IPHONE + WithPathInKeychainDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { + kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); + }); +#else + /* macOS caches should be in user cache dir */ + WithPathInUserCacheDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { + kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); + }); +#endif + + if (kSecCAIssuerCache) + atexit(SecCAIssuerCacheGC); +} + +static CF_RETURNS_RETAINED CFDataRef convertArrayOfCertsToData(CFArrayRef certificates) { + if (!certificates || CFArrayGetCount(certificates) == 0) { + return NULL; + } + + CFMutableDataRef output = CFDataCreateMutable(NULL, 0); + CFArrayForEach(certificates, ^(const void *value) { + CFDataRef certData = SecCertificateCopyData((SecCertificateRef)value); + if (certData) { + CFDataAppend(output, certData); + } + CFReleaseNull(certData); + }); + + return output; +} + +static CF_RETURNS_RETAINED CFArrayRef convertDataToArrayOfCerts(uint8_t *data, size_t dataLen) { + if (!data || dataLen == 0) { + return NULL; + } + + CFMutableArrayRef output = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + uint8_t *nextCertPtr = data; + size_t remainingDataLen = dataLen; + while (nextCertPtr < data + dataLen) { + SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, nextCertPtr, remainingDataLen); + if (cert) { + CFArrayAppendValue(output, cert); + nextCertPtr += SecCertificateGetLength(cert); + remainingDataLen -= SecCertificateGetLength(cert); + CFReleaseNull(cert); + } else { + /* We don't know where the next cert starts, so we should just stop */ + break; + } + } + + if (CFArrayGetCount(output) < 1) { + CFReleaseNull(output); + } + return output; +} + +/* Instance implemenation. */ + +static void _SecCAIssuerCacheAddCertificates(SecCAIssuerCacheRef this, + CFArrayRef certificates, + CFURLRef uri, CFAbsoluteTime expires) { + int s3e; + CFDataRef certsData = NULL; + CFDataRef uriData = NULL; + + secdebug("caissuercache", "adding certificate from %@", uri); + require_noerr(s3e = SecCAIssuerCacheEnsureTxn(this), errOut); + + /* issuer.uri */ + require_action(uriData = CFURLCreateData(kCFAllocatorDefault, uri, + kCFStringEncodingUTF8, false), errOut, s3e = SQLITE_NOMEM); + s3e = sqlite3_bind_blob_wrapper(this->insertIssuer, 1, + CFDataGetBytePtr(uriData), CFDataGetLength(uriData), SQLITE_TRANSIENT); + CFRelease(uriData); + + /* issuer.expires */ + if (!s3e) s3e = sqlite3_bind_double(this->insertIssuer, 2, expires); + + /* issuer.certificate */ + require_action(certsData = convertArrayOfCertsToData(certificates), errOut, + s3e = SQLITE_NOMEM); + if (!s3e) { + s3e = sqlite3_bind_blob_wrapper(this->insertIssuer, 3, + CFDataGetBytePtr(certsData), + CFDataGetLength(certsData), SQLITE_TRANSIENT); + } + CFReleaseNull(certsData); + + /* Execute the insert statement. */ + if (!s3e) s3e = sqlite3_step(this->insertIssuer); + require_noerr(s3e = sec_sqlite3_reset(this->insertIssuer, s3e), errOut); + +errOut: + if (s3e != SQLITE_OK) { + secerror("caissuer cache add failed: %s", sqlite3_errmsg(this->s3h)); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); + /* TODO: Blow away the cache and create a new db. */ + } +} + +static CFArrayRef _SecCAIssuerCacheCopyMatching(SecCAIssuerCacheRef this, + CFURLRef uri) { + CFArrayRef certificates = NULL; + int s3e = SQLITE_OK; + + CFDataRef uriData = NULL; + require(uriData = CFURLCreateData(kCFAllocatorDefault, uri, + kCFStringEncodingUTF8, false), errOut); + s3e = sqlite3_bind_blob_wrapper(this->selectIssuer, 1, CFDataGetBytePtr(uriData), + CFDataGetLength(uriData), SQLITE_TRANSIENT); + CFRelease(uriData); + + if (!s3e) s3e = sqlite3_step(this->selectIssuer); + if (s3e == SQLITE_ROW) { + /* Found an entry! */ + secdebug("caissuercache", "found cached response for %@", uri); + + const void *respData = sqlite3_column_blob(this->selectIssuer, 0); + int respLen = sqlite3_column_bytes(this->selectIssuer, 0); + certificates = convertDataToArrayOfCerts((uint8_t *)respData, respLen); + } + + require_noerr(s3e = sec_sqlite3_reset(this->selectIssuer, s3e), errOut); + +errOut: + if (s3e != SQLITE_OK) { + if (s3e != SQLITE_DONE) { + secerror("caissuer cache lookup failed: %s", sqlite3_errmsg(this->s3h)); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationRead, TAFatalError, s3e); + /* TODO: Blow away the cache and create a new db. */ + } + + if (certificates) { + CFRelease(certificates); + certificates = NULL; + } + } + + secdebug("caissuercache", "returning %s for %@", (certificates ? "cached response" : "NULL"), uri); + return certificates; +} + +static void _SecCAIssuerCacheGC(void *context) { + SecCAIssuerCacheRef this = context; + int s3e; + + require_noerr(s3e = SecCAIssuerCacheEnsureTxn(this), errOut); + secdebug("caissuercache", "expiring stale responses"); + s3e = sqlite3_bind_double(this->expire, 1, CFAbsoluteTimeGetCurrent()); + if (!s3e) s3e = sqlite3_step(this->expire); + require_noerr(s3e = sec_sqlite3_reset(this->expire, s3e), errOut); + require_noerr(s3e = SecCAIssuerCacheCommitTxn(this), errOut); + +errOut: + if (s3e != SQLITE_OK) { + secerror("caissuer cache expire failed: %s", sqlite3_errmsg(this->s3h)); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); + /* TODO: Blow away the cache and create a new db. */ + } +} + +static void _SecCAIssuerCacheFlush(void *context) { + SecCAIssuerCacheRef this = context; + int s3e; + + secdebug("caissuercache", "flushing pending changes"); + s3e = SecCAIssuerCacheCommitTxn(this); + + if (s3e != SQLITE_OK) { + secerror("caissuer cache flush failed: %s", sqlite3_errmsg(this->s3h)); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TACAIssuerCache, TAOperationWrite, TAFatalError, s3e); + /* TODO: Blow away the cache and create a new db. */ + } +} + +/* Public API */ + +void SecCAIssuerCacheAddCertificates(CFArrayRef certificates, + CFURLRef uri, CFAbsoluteTime expires) { + dispatch_once(&kSecCAIssuerCacheOnce, ^{ + SecCAIssuerCacheInit(); + }); + if (!kSecCAIssuerCache) + return; + + dispatch_sync(kSecCAIssuerCache->queue, ^{ + _SecCAIssuerCacheAddCertificates(kSecCAIssuerCache, certificates, uri, expires); + _SecCAIssuerCacheFlush(kSecCAIssuerCache); + }); +} + +CFArrayRef SecCAIssuerCacheCopyMatching(CFURLRef uri) { + dispatch_once(&kSecCAIssuerCacheOnce, ^{ + SecCAIssuerCacheInit(); + }); + __block CFArrayRef certs = NULL; + if (kSecCAIssuerCache) + dispatch_sync(kSecCAIssuerCache->queue, ^{ + certs = _SecCAIssuerCacheCopyMatching(kSecCAIssuerCache, uri); + }); + return certs; +} + +/* This should be called on a normal non emergency exit. This function + effectively does a SecCAIssuerCacheFlush. + Currently this is called from our atexit handeler. + This function expires any records that are stale and commits. + + Idea for future cache management policies: + Expire old cache entires from database if: + - The time to do so has arrived based on the nextExpire date in the + policy table. + - If the size of the database exceeds the limit set in the maxSize field + in the policy table, vacuum the db. If the database is still too + big, expire records on a LRU basis. + */ +void SecCAIssuerCacheGC(void) { + if (kSecCAIssuerCache) + dispatch_sync(kSecCAIssuerCache->queue, ^{ + _SecCAIssuerCacheGC(kSecCAIssuerCache); + }); +} diff --git a/trust/trustd/SecCAIssuerCache.h b/trust/trustd/SecCAIssuerCache.h new file mode 100644 index 00000000..e82ba1d8 --- /dev/null +++ b/trust/trustd/SecCAIssuerCache.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/*! + @header SecCAIssuerCache + The functions provided in SecCAIssuerCache.h provide an interface to + an CAIssuer caching module. + */ + +#ifndef _SECURITY_SECCAISSUERCACHE_H_ +#define _SECURITY_SECCAISSUERCACHE_H_ + +#include "trust/trustd/SecCAIssuerRequest.h" +#include +#include +#include + +__BEGIN_DECLS + + +void SecCAIssuerCacheAddCertificates(CFArrayRef certificates, + CFURLRef uri, CFAbsoluteTime expires); + +CFArrayRef SecCAIssuerCacheCopyMatching(CFURLRef uri); + +/* This should be called on a normal non emergency exit. */ +void SecCAIssuerCacheGC(void); + +__END_DECLS + +#endif /* _SECURITY_SECCAISSUERCACHE_H_ */ diff --git a/trust/trustd/SecCAIssuerRequest.h b/trust/trustd/SecCAIssuerRequest.h new file mode 100644 index 00000000..61ea4dc4 --- /dev/null +++ b/trust/trustd/SecCAIssuerRequest.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include + +bool SecCAIssuerCopyParents(SecCertificateRef certificate, void *context, void (*callback)(void *, CFArrayRef)); diff --git a/trust/trustd/SecCAIssuerRequest.m b/trust/trustd/SecCAIssuerRequest.m new file mode 100644 index 00000000..b38d91cd --- /dev/null +++ b/trust/trustd/SecCAIssuerRequest.m @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2009-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecCAIssuerRequest.m - asynchronous CAIssuer request fetching engine. + */ + + +#include "SecCAIssuerRequest.h" +#include "SecCAIssuerCache.h" + +#import +#import +#include +#include +#include +#include +#include +#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/TrustURLSessionDelegate.h" +#include +#include + +#define MAX_CA_ISSUERS 3 +#define CA_ISSUERS_REQUEST_THRESHOLD 10 + +typedef void (*CompletionHandler)(void *context, CFArrayRef parents); + +/* CA Issuer lookup code. */ +@interface CAIssuerDelegate: TrustURLSessionDelegate +@property (assign) CompletionHandler callback; +@end + +static NSArray *certificatesFromData(NSData *data) { + /* RFC5280 4.2.2.1: + "accessLocation MUST be a uniformResourceIdentifier and the URI + MUST point to either a single DER encoded certificate as speci- + fied in [RFC2585] or a collection of certificates in a BER or + DER encoded "certs-only" CMS message as specified in [RFC2797]." */ + + /* DER-encoded certificate */ + SecCertificateRef parent = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); + if (parent) { + NSArray *result = @[(__bridge id)parent]; + CFReleaseNull(parent); + return result; + } + + /* "certs-only" CMS Message */ + CFArrayRef certificates = SecCMSCertificatesOnlyMessageCopyCertificates((__bridge CFDataRef)data); + if (certificates) { + return CFBridgingRelease(certificates); + } + + /* Retry in case the certificate is in PEM format. Some CAs + incorrectly return a PEM encoded cert, despite RFC 5280 4.2.2.1 */ + parent = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data); + if (parent) { + NSArray *result = @[(__bridge id)parent]; + CFReleaseNull(parent); + return result; + } + return nil; +} + +@implementation CAIssuerDelegate +- (BOOL)fetchNext:(NSURLSession *)session { + SecPathBuilderRef builder = (SecPathBuilderRef)self.context; + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + + BOOL result = false; + if (!(result = [super fetchNext:session]) && analytics) { + analytics->ca_issuer_fetches++; + } + return result; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + /* call the superclass's method to set taskTime and expiration */ + [super URLSession:session task:task didCompleteWithError:error]; + + __block SecPathBuilderRef builder =(SecPathBuilderRef)self.context; + if (!builder) { + /* We already returned to the PathBuilder state machine. */ + return; + } + + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + __block NSArray *parents = nil; + if (error) { + /* Log the error */ + secnotice("caissuer", "Failed to download issuer %@, with error %@", task.originalRequest.URL, error); + if (analytics) { + analytics->ca_issuer_fetch_failed++; + } + } else if (self.response) { + /* Get the parent cert from the data */ + parents = certificatesFromData(self.response); + if (analytics && !parents) { + analytics->ca_issuer_unsupported_data = true; + } else if (analytics && [parents count] > 1) { + analytics->ca_issuer_multiple_certs = true; + } + } + + if (parents) { + /* Found some parents, add to cache, close session, and return to SecPathBuilder */ + secdebug("caissuer", "found parents for %@", task.originalRequest.URL); + SecCAIssuerCacheAddCertificates((__bridge CFArrayRef)parents, (__bridge CFURLRef)task.originalRequest.URL, self.expiration); + self.context = nil; // set the context to NULL before we call back because the callback may free the builder + [session invalidateAndCancel]; + dispatch_async(SecPathBuilderGetQueue(builder), ^{ + self.callback(builder, (__bridge CFArrayRef)parents); + }); + } else { + secdebug("caissuer", "no parents for %@", task.originalRequest.URL); + if ([self fetchNext:session]) { // Try the next CAIssuer URI + /* no fetch scheduled, close this session and jump back into the state machine on the builder's queue */ + secdebug("caissuer", "no more fetches. returning to builder"); + self.context = nil; // set the context to NULL before we call back because the callback may free the builder + [session invalidateAndCancel]; + dispatch_async(SecPathBuilderGetQueue(builder), ^{ + self.callback(builder, NULL); + }); + } + } +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)taskMetrics { + secdebug("caissuer", "got metrics with task interval %f", taskMetrics.taskInterval.duration); + SecPathBuilderRef builder =(SecPathBuilderRef)self.context; + if (builder) { + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + if (analytics) { + analytics->ca_issuer_fetch_time += (uint64_t)(taskMetrics.taskInterval.duration * NSEC_PER_SEC); + } + } +} +@end + +/* Releases parent unconditionally, and return a CFArrayRef containing + parent if the normalized subject of parent matches the normalized issuer + of certificate. */ +static CF_RETURNS_RETAINED CFArrayRef SecCAIssuerConvertToParents(SecCertificateRef certificate, CFArrayRef CF_CONSUMED putativeParents) { + CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); + NSMutableArray *parents = [NSMutableArray array]; + NSArray *possibleParents = CFBridgingRelease(putativeParents); + for (id parent in possibleParents) { + CFDataRef parent_nic = SecCertificateGetNormalizedSubjectContent((__bridge SecCertificateRef)parent); + if (nic && parent_nic && CFEqual(nic, parent_nic)) { + [parents addObject:parent]; + } + } + + if ([parents count] > 0) { + return CFBridgingRetain(parents); + } else { + return nil; + } +} + +static CFArrayRef SecCAIssuerRequestCacheCopyParents(SecCertificateRef cert, + CFArrayRef issuers) { + CFIndex ix = 0, ex = CFArrayGetCount(issuers); + for (;ix < ex; ++ix) { + CFURLRef issuer = CFArrayGetValueAtIndex(issuers, ix); + CFStringRef scheme = CFURLCopyScheme(issuer); + if (scheme) { + if (CFEqual(CFSTR("http"), scheme)) { + CFArrayRef parents = SecCAIssuerConvertToParents(cert, + SecCAIssuerCacheCopyMatching(issuer)); + if (parents) { + secdebug("caissuer", "cache hit, for %@. no request issued", issuer); + CFRelease(scheme); + return parents; + } + } + CFRelease(scheme); + } + } + return NULL; +} + +bool SecCAIssuerCopyParents(SecCertificateRef certificate, void *context, void (*callback)(void *, CFArrayRef)) { + @autoreleasepool { + CFArrayRef issuers = CFRetainSafe(SecCertificateGetCAIssuers(certificate)); + NSArray *nsIssuers = CFBridgingRelease(issuers); + if (!issuers) { + /* certificate has no caissuer urls, we're done. */ + callback(context, NULL); + return true; + } + + SecPathBuilderRef builder = (SecPathBuilderRef)context; + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + CFArrayRef parents = SecCAIssuerRequestCacheCopyParents(certificate, (__bridge CFArrayRef)nsIssuers); + if (parents) { + if (analytics) { + /* We found parents in the cache */ + analytics->ca_issuer_cache_hit = true; + } + callback(context, parents); + CFReleaseSafe(parents); + return true; + } + if (analytics) { + /* We're going to have to make a network call */ + analytics->ca_issuer_network = true; + } + + NSInteger count = [nsIssuers count]; + if (count >= CA_ISSUERS_REQUEST_THRESHOLD) { + secnotice("caissuer", "too many caIssuer entries (%ld)", (long)count); + callback(context, NULL); + return true; + } + + NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + config.timeoutIntervalForResource = TrustURLSessionGetResourceTimeout(); + config.HTTPAdditionalHeaders = @{@"User-Agent" : @"com.apple.trustd/2.0"}; + + NSData *auditToken = CFBridgingRelease(SecPathBuilderCopyClientAuditToken(builder)); + if (auditToken) { + config._sourceApplicationAuditTokenData = auditToken; + } + + CAIssuerDelegate *delegate = [[CAIssuerDelegate alloc] init]; + delegate.context = context; + delegate.callback = callback; + delegate.URIs = nsIssuers; + delegate.URIix = 0; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; + secdebug("caissuer", "created URLSession for %@", certificate); + + bool result = false; + if ((result = [delegate fetchNext:session])) { + /* no fetch scheduled, close the session */ + [session invalidateAndCancel]; + } + return result; + } +} + diff --git a/trust/trustd/SecCertificateServer.c b/trust/trustd/SecCertificateServer.c new file mode 100644 index 00000000..6ddca031 --- /dev/null +++ b/trust/trustd/SecCertificateServer.c @@ -0,0 +1,1391 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecCertificateServer.c - SecCertificate and SecCertificatePathVC types + * with additonal validation context. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "trust/trustd/policytree.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecRevocationServer.h" + +// MARK: - +// MARK: SecCertificateVC +/******************************************************** + ************* SecCertificateVC object *************** + ********************************************************/ + +struct SecCertificateVC { + CFRuntimeBase _base; + SecCertificateRef certificate; + CFArrayRef usageConstraints; + CFNumberRef revocationReason; + bool optionallyEV; + bool isWeakHash; + bool require_revocation_response; +}; +CFGiblisWithHashFor(SecCertificateVC) + +static void SecCertificateVCDestroy(CFTypeRef cf) { + SecCertificateVCRef cvc = (SecCertificateVCRef) cf; + CFReleaseNull(cvc->certificate); + CFReleaseNull(cvc->usageConstraints); + CFReleaseNull(cvc->revocationReason); +} + +static Boolean SecCertificateVCCompare(CFTypeRef cf1, CFTypeRef cf2) { + SecCertificateVCRef cv1 = (SecCertificateVCRef) cf1; + SecCertificateVCRef cv2 = (SecCertificateVCRef) cf2; + if (!CFEqual(cv1->certificate, cv2->certificate)) { + return false; + } + /* CertificateVCs are the same if either does not have usage constraints. */ + if (cv1->usageConstraints && cv2->usageConstraints && + !CFEqual(cv1->usageConstraints, cv2->usageConstraints)) { + return false; + } + + return true; +} + +static CFHashCode SecCertificateVCHash(CFTypeRef cf) { + SecCertificateVCRef cvc = (SecCertificateVCRef) cf; + CFHashCode hashCode = 0; + hashCode += CFHash(cvc->certificate); + if (cvc->usageConstraints) { + hashCode += CFHash(cvc->usageConstraints); + } + return hashCode; +} + +static CFStringRef SecCertificateVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecCertificateVCRef cvc = (SecCertificateVCRef)cf; + return CFCopyDescription(cvc->certificate); +} + +static bool SecCertificateVCCouldBeEV(SecCertificateRef certificate) { + CFMutableDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + bool isEV = false; + + /* 3. Subscriber Certificate. */ + + /* (a) certificate Policies */ + const SecCECertificatePolicies *cp; + cp = SecCertificateGetCertificatePolicies(certificate); + require_quiet(cp && cp->numPolicies > 0, notEV); + /* Now find at least one policy in here that has a qualifierID of id-qt 2 + and a policyQualifier that is a URI to the CPS and an EV policy OID. */ + uint32_t ix = 0; + bool found_ev_anchor_for_leaf_policy = false; + for (ix = 0; ix < cp->numPolicies; ++ix) { + if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) { + found_ev_anchor_for_leaf_policy = true; + } + } + require_quiet(found_ev_anchor_for_leaf_policy, notEV); + + /* (b) cRLDistributionPoint + (c) authorityInformationAccess + BRv1.3.4: MUST be present with OCSP Responder unless stapled response. + */ + + /* (d) basicConstraints + If present, the cA field MUST be set false. */ + const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); + if (bc) { + require_action_quiet(bc->isCA == false, notEV, + secnotice("ev", "Leaf has invalid basic constraints")); + } + + /* (e) keyUsage. */ + SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); + if (ku) { + require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV, + secnotice("ev", "Leaf has invalid key usage %u", ku)); + } + +#if 0 + /* The EV Cert Spec errata specifies this, though this is a check for SSL + not specifically EV. */ + + /* (e) extKeyUsage + + Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */ + SecCertificateCopyExtendedKeyUsage(certificate); +#endif + + /* 6.1.5 Key Sizes */ + CFAbsoluteTime jan2014 = 410227200; + require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); + require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); + if (SecCertificateNotValidBefore(certificate) < jan2014) { + /* At least RSA 1024 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "Leaf's public key is too small for issuance before 2014")); + } else { + /* At least RSA 2028 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "Leaf's public key is too small for issuance after 2013")); + } + + /* 6.3.2 Validity Periods */ + // Will be checked by the policy server (see SecPolicyCheckValidityPeriodMaximums) + + /* 7.1.3 Algorithm Object Identifiers */ + CFAbsoluteTime jan2016 = 473299200; + if (SecCertificateNotValidBefore(certificate) > jan2016) { + /* SHA-2 only */ + require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, + notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015")); + } + + isEV = true; + +notEV: + CFReleaseNull(rsaSize); + CFReleaseNull(ecSize); + CFReleaseNull(keySizes); + return isEV; +} + + +SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageConstraints) { + if (!certificate) { return NULL; } + CFIndex size = sizeof(struct SecCertificateVC); + SecCertificateVCRef result = + (SecCertificateVCRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, + SecCertificateVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + result->certificate = CFRetainSafe(certificate); + result->isWeakHash = SecCertificateIsWeakHash(certificate); + result->optionallyEV = SecCertificateVCCouldBeEV(certificate); + + CFArrayRef emptyArray = NULL; + if (!usageConstraints) { + require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); + usageConstraints = emptyArray; + } + result->usageConstraints = CFRetainSafe(usageConstraints); +exit: + CFReleaseNull(emptyArray); + return result; +} + +// MARK: - +// MARK: SecCertificatePathVC +/******************************************************** + ************* SecCertificatePathVC object *************** + ********************************************************/ +struct SecCertificatePathVC { + CFRuntimeBase _base; + CFIndex count; + + /* Index of next parent source to search for parents. */ + CFIndex nextParentSource; + + /* Index of last certificate in chain whose signature has been verified. + 0 means nothing has been checked. 1 means the leaf has been verified + against its issuer, etc. */ + CFIndex lastVerifiedSigner; + + /* Index of first self issued certificate in the chain. -1 mean there is + none. 0 means the leaf is self signed. */ + CFIndex selfIssued; + + /* True iff cert at index selfIssued does in fact self verify. */ + bool isSelfSigned; + + /* True if the root of this path is an anchor. Trustedness of the + * anchor is determined by the PVC. */ + bool isAnchored; + + policy_tree_t policy_tree; + uint8_t policy_tree_verification_result; + + bool isEV; + bool isCT; + bool is_allowlisted; + bool hasStrongHashes; + + void * rvcs; + CFIndex rvcCount; + + /* This is the score of the path after determining acceptance. */ + CFIndex score; + + bool pathValidated; + + /* If checkedIssuers is true, then the value of unknownCAIndex contains + * the index of the first CA which violates known-only constraints, or + * -1 if all CA certificates are either known or not constrained. */ + bool checkedIssuers; + CFIndex unknownCAIndex; + + /* Enumerated value to determine whether CT is required for the leaf + * certificate (because a CA in the path has a require-ct constraint). + * If non-zero, CT is required; value indicates overridable status. */ + SecPathCTPolicy requiresCT; + + /* Issuance time, as determined by earliest SCT timestamp for leaf. */ + CFAbsoluteTime issuanceTime; + + SecCertificateVCRef certificates[]; +}; +CFGiblisWithHashFor(SecCertificatePathVC) + +static void SecCertificatePathVCPrunePolicyTree(SecCertificatePathVCRef certificatePath) { + if (certificatePath->policy_tree) { + policy_tree_prune(&certificatePath->policy_tree); + } +} + +void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path) { + if (path->rvcs) { + CFIndex certIX, certCount = path->rvcCount; + for (certIX = 0; certIX < certCount; ++certIX) { + SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; + SecRVCDelete(rvc); + } + free(path->rvcs); + path->rvcs = NULL; + } +} + +static void SecCertificatePathVCDestroy(CFTypeRef cf) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFIndex ix; + SecCertificatePathVCDeleteRVCs(certificatePath); + SecCertificatePathVCPrunePolicyTree(certificatePath); + for (ix = 0; ix < certificatePath->count; ++ix) { + CFReleaseNull(certificatePath->certificates[ix]); + } +} + +static Boolean SecCertificatePathVCCompare(CFTypeRef cf1, CFTypeRef cf2) { + SecCertificatePathVCRef cp1 = (SecCertificatePathVCRef) cf1; + SecCertificatePathVCRef cp2 = (SecCertificatePathVCRef) cf2; + if (cp1->count != cp2->count) + return false; + CFIndex ix; + for (ix = 0; ix < cp1->count; ++ix) { + if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix])) + return false; + } + + return true; +} + +static CFHashCode SecCertificatePathVCHash(CFTypeRef cf) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFHashCode hashCode = 0; + CFIndex ix; + for (ix = 0; ix < certificatePath->count; ++ix) { + hashCode += CFHash(certificatePath->certificates[ix]); + } + return hashCode; +} + +static CFStringRef SecCertificatePathVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf)); + CFStringAppendFormat(desc, NULL, + CFSTR("<%@ certs: "), typeStr); + CFRelease(typeStr); + CFIndex ix; + for (ix = 0; ix < certificatePath->count; ++ix) { + if (ix > 0) { + CFStringAppend(desc, CFSTR(", ")); + } + CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]); + CFStringAppend(desc, str); + CFRelease(str); + } + CFStringAppend(desc, CFSTR(" >")); + + return desc; +} + +/* Create a new certificate path from an old one. */ +SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, + SecCertificateRef certificate, CFArrayRef usageConstraints) { + CFAllocatorRef allocator = kCFAllocatorDefault; + check(certificate); + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + if (path) { + count = path->count + 1; + lastVerifiedSigner = path->lastVerifiedSigner; + selfIssued = path->selfIssued; + isSelfSigned = path->isSelfSigned; + } else { + count = 1; + lastVerifiedSigner = 0; + selfIssued = -1; + isSelfSigned = false; + } + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + CFIndex ix; + for (ix = 0; ix < count - 1; ++ix) { + result->certificates[ix] = path->certificates[ix]; + CFRetain(result->certificates[ix]); + } + + SecCertificateVCRef cvc = SecCertificateVCCreate(certificate, usageConstraints); + result->certificates[count - 1] = cvc; + + return result; +} + +SecCertificatePathVCRef SecCertificatePathVCCopyFromParent( + SecCertificatePathVCRef path, CFIndex skipCount) { + CFAllocatorRef allocator = kCFAllocatorDefault; + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + + /* Ensure we are at least returning a path of length 1. */ + if (skipCount < 0 || path->count < 1 + skipCount) + return NULL; + + count = path->count - skipCount; + lastVerifiedSigner = path->lastVerifiedSigner > skipCount + ? path->lastVerifiedSigner - skipCount : 0; + selfIssued = path->selfIssued >= skipCount + ? path->selfIssued - skipCount : -1; + isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false; + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + result->isAnchored = path->isAnchored; + CFIndex ix; + for (ix = 0; ix < count; ++ix) { + CFIndex pathIX = ix + skipCount; + result->certificates[ix] = path->certificates[pathIX]; + CFRetain(result->certificates[ix]); + } + + return result; +} + +SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, + SecCertificateRef leaf) { + CFAllocatorRef allocator = kCFAllocatorDefault; + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + + /* First make sure the new leaf is signed by path's current leaf. */ + SecKeyRef issuerKey = SecCertificatePathVCCopyPublicKeyAtIndex(path, 0); + if (!issuerKey) + return NULL; + OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey); + CFRelease(issuerKey); + if (status) + return NULL; + + count = path->count + 1; + lastVerifiedSigner = path->lastVerifiedSigner + 1; + selfIssued = path->selfIssued; + isSelfSigned = path->isSelfSigned; + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + result->isAnchored = path->isAnchored; + + CFIndex ix; + for (ix = 1; ix < count; ++ix) { + result->certificates[ix] = path->certificates[ix - 1]; + CFRetain(result->certificates[ix]); + } + SecCertificateVCRef leafVC = SecCertificateVCCreate(leaf, NULL); + result->certificates[0] = leafVC; + + return result; +} + +CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path) { + CFMutableArrayRef outCerts = NULL; + size_t count = path->count; + require_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit); + SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) { + CFArrayAppendValue(outCerts, cert); + }); +exit: + return outCerts; +} + +CFArrayRef SecCertificatePathVCCreateSerialized(SecCertificatePathVCRef path) { + CFMutableArrayRef serializedCerts = NULL; + require_quiet(path, exit); + size_t count = path->count; + require_quiet(serializedCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit); + SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) { + CFDataRef certData = SecCertificateCopyData(cert); + if (certData) { + CFArrayAppendValue(serializedCerts, certData); + CFRelease(certData); + } + }); +exit: + return serializedCerts; +} + + +/* Record the fact that we found our own root cert as our parent + certificate. */ +void SecCertificatePathVCSetSelfIssued( + SecCertificatePathVCRef certificatePath) { + if (certificatePath->selfIssued >= 0) { + secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath, + certificatePath->selfIssued); + return; + } + secdebug("trust", "%@ is self issued", certificatePath); + certificatePath->selfIssued = certificatePath->count - 1; + + /* now check that the selfIssued cert was actually self-signed */ + if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) { + SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->selfIssued]; + Boolean isSelfSigned = false; + OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); + if ((status == errSecSuccess) && isSelfSigned) { + certificatePath->isSelfSigned = true; + } else { + certificatePath->selfIssued = -1; + } + } +} + +void SecCertificatePathVCSetIsAnchored( + SecCertificatePathVCRef certificatePath) { + secdebug("trust", "%@ is anchored", certificatePath); + certificatePath->isAnchored = true; + + /* Now check if that anchor (last cert) was actually self-signed. + * In the non-anchor case, this is handled by SecCertificatePathVCSetSelfIssued. + * Because anchored chains immediately go into the candidate bucket in the trust + * server, we need to ensure that the self-signed/self-issued members are set + * for the purposes of scoring. */ + if (!certificatePath->isSelfSigned && certificatePath->count > 0) { + SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->count - 1]; + Boolean isSelfSigned = false; + OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); + if ((status == errSecSuccess) && isSelfSigned) { + certificatePath->isSelfSigned = true; + if (certificatePath->selfIssued == -1) { + certificatePath->selfIssued = certificatePath->count - 1; + } + } + } +} + +/* Return the index of the first non anchor certificate in the chain that is + self signed counting from the leaf up. Return -1 if there is none. */ +CFIndex SecCertificatePathVCSelfSignedIndex( + SecCertificatePathVCRef certificatePath) { + if (certificatePath->isSelfSigned) + return certificatePath->selfIssued; + return -1; +} + +Boolean SecCertificatePathVCIsAnchored( + SecCertificatePathVCRef certificatePath) { + return certificatePath->isAnchored; +} + + +void SecCertificatePathVCSetNextSourceIndex( + SecCertificatePathVCRef certificatePath, CFIndex sourceIndex) { + certificatePath->nextParentSource = sourceIndex; +} + +CFIndex SecCertificatePathVCGetNextSourceIndex( + SecCertificatePathVCRef certificatePath) { + return certificatePath->nextParentSource; +} + +CFIndex SecCertificatePathVCGetCount( + SecCertificatePathVCRef certificatePath) { + check(certificatePath); + return certificatePath ? certificatePath->count : 0; +} + +SecCertificateRef SecCertificatePathVCGetCertificateAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + if (!certificatePath || ix < 0 || ix >= certificatePath->count) { + return NULL; + } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + return cvc ? cvc->certificate : NULL; +} + +void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)) { + bool stop = false; + CFIndex ix, count = path->count; + for (ix = 0; ix < count; ++ix) { + SecCertificateVCRef cvc = path->certificates[ix]; + operation(cvc->certificate, &stop); + if (stop) { break; } + } +} + +CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, + SecCertificateRef certificate) { + CFIndex ix, count = path->count; + for (ix = 0; ix < count; ++ix) { + SecCertificateVCRef cvc = path->certificates[ix]; + if (CFEqual(cvc->certificate, certificate)) + return ix; + } + return kCFNotFound; +} + +/* Return the root certificate for certificatePath. Note that root is just + the top of the path as far as it is constructed. It may or may not be + trusted or self signed. */ +SecCertificateRef SecCertificatePathVCGetRoot( + SecCertificatePathVCRef certificatePath) { + return SecCertificatePathVCGetCertificateAtIndex(certificatePath, + SecCertificatePathVCGetCount(certificatePath) - 1); +} + +SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + SecCertificateRef certificate = + SecCertificatePathVCGetCertificateAtIndex(certificatePath, ix); + return SecCertificateCopyKey(certificate); +} + +CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + return cvc->usageConstraints; +} + +void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, + CFArrayRef newConstraints, CFIndex ix) { + CFArrayRef emptyArray = NULL; + if (!newConstraints) { + require_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit); + newConstraints = emptyArray; + } + + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + cvc->usageConstraints = CFRetainSafe(newConstraints); +exit: + CFReleaseNull(emptyArray); + return; +} + +SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath) { + check(certificatePath); + if (!certificatePath) + return kSecPathVerifyFailed; + for (; + certificatePath->lastVerifiedSigner < certificatePath->count - 1; + ++certificatePath->lastVerifiedSigner) { + SecKeyRef issuerKey = + SecCertificatePathVCCopyPublicKeyAtIndex(certificatePath, + certificatePath->lastVerifiedSigner + 1); + if (!issuerKey) + return kSecPathVerifiesUnknown; + SecCertificateVCRef cvc = certificatePath->certificates[certificatePath->lastVerifiedSigner]; + OSStatus status = SecCertificateIsSignedBy(cvc->certificate, + issuerKey); + CFRelease(issuerKey); + if (status) { + return kSecPathVerifyFailed; + } + } + + return kSecPathVerifySuccess; +} + +/* Is the the issuer of the last cert a subject of a previous cert in the chain.See . */ +bool SecCertificatePathVCIsCycleInGraph(SecCertificatePathVCRef path) { + bool isCircle = false; + CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(SecCertificatePathVCGetRoot(path)); + if (!issuer) { return isCircle; } + CFIndex ix = path->count - 2; + for (; ix >= 0; ix--) { + SecCertificateVCRef cvc = path->certificates[ix]; + CFDataRef subject = SecCertificateGetNormalizedSubjectContent(cvc->certificate); + if (subject && CFEqual(issuer, subject)) { + isCircle = true; + break; + } + } + return isCircle; +} + +bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) { + __block bool result = true; + SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { + if (!SecCertificateIsValid(certificate, verifyTime)) { + result = false; + } + }); + return result; +} + +bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath) { + CFIndex ix, count = certificatePath->count; + + if (certificatePath->hasStrongHashes) { + return false; + } + + if (SecCertificatePathVCIsAnchored(certificatePath)) { + /* For anchored paths, don't check the hash algorithm of the anchored cert, + * since we already decided to trust it. */ + count--; + } + for (ix = 0; ix < count; ++ix) { + if (certificatePath->certificates[ix]->isWeakHash) { + return true; + } + } + certificatePath->hasStrongHashes = true; + return false; +} + +bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath) { + __block CFDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + __block bool result = false; + + /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */ + require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut); + require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut); + const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; + const void *values[] = { rsaSize, ecSize }; + require(keySizes = CFDictionaryCreate(NULL, keys, values, 2, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { + if (!SecCertificateIsAtLeastMinKeySize(certificate, keySizes)) { + result = true; + *stop = true; + } + }); + +errOut: + CFReleaseSafe(keySizes); + CFReleaseSafe(rsaSize); + CFReleaseSafe(ecSize); + return result; +} + +/* Return a score for this certificate chain. */ +CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) { + CFIndex score = 0; + + /* Paths that don't verify score terribly.c */ + if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) { + secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex, + certificatePath->lastVerifiedSigner, certificatePath->count); + score -= 100000; + } + + if (certificatePath->isAnchored) { + /* Anchored paths for the win! */ + score += 10000; + } + + if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) { + /* Chains that terminate in a self-signed certificate are preferred, + even if they don't end in an anchor. */ + score += 1000; + /* Shorter chains ending in a self-signed cert are preferred. */ + score -= 1 * certificatePath->count; + } else { + /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */ + score += 1 * certificatePath->count; + } + + if (SecCertificatePathVCIsValid(certificatePath, verifyTime)) { + score += 100; + } + + if (!SecCertificatePathVCHasWeakHash(certificatePath)) { + score += 10; + } + + if (!SecCertificatePathVCHasWeakKeySize(certificatePath)) { + score += 10; + } + + return score; +} + +CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return 0; } + return certificatePath->score; +} + +void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score) { + /* We may "score" the same path twice -- if we "accept" a path but then + * decide to keep looking for a better one, we we process the same path + * again in "reject" which creates a lower score. Don't replace a higher + * score with a lower score. Use reset below to post-reject a path. */ + if (score > certificatePath->score) { + certificatePath->score = score; + } +} + +void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath) { + certificatePath->score = 0; +} + +void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix) { + if (ix >= certificatePath->rvcCount) { + return NULL; + } + return &((SecRVCRef)certificatePath->rvcs)[ix]; +} + +bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath) { + return (bool)certificatePath->rvcs; +} + +void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount) { + certificatePath->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount); + certificatePath->rvcCount = certCount; +} + +/* Return 0 if any certs revocation checking failed, or the earliest date on + which one of the used revocation validation tokens (ocsp response or + crl) expires. */ +/* This function returns 0 to indicate revocation checking was not completed + for this certificate chain, otherwise returns the date at which the first + piece of revocation checking info we used expires. */ +CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path) { + CFIndex certIX, certCount = path->count; + CFAbsoluteTime enu = NULL_TIME; + if (certCount <= 1 || !path->rvcs) { + return enu; + } + + for (certIX = 0; certIX < path->rvcCount; ++certIX) { + SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; + CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc); + if (thisCertNextUpdate == 0) { + if (certIX > 0) { + /* We allow for CA certs to not be revocation checked if they + have no ocspResponders to check against, but the leaf + must be checked in order for us to claim we did revocation + checking. */ + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX); + CFArrayRef ocspResponders = NULL; + ocspResponders = SecCertificateGetOCSPResponders(cert); + if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) { + /* We can't check this cert so we don't consider it a soft + failure that we didn't. */ + continue; + } + } + /* Make sure to always skip roots for whom we can't check revocation */ + if (certIX == certCount - 1) { + continue; + } + secdebug("rvc", "revocation checking soft failure for cert: %ld", + certIX); + enu = thisCertNextUpdate; + break; + } + if (enu == 0 || thisCertNextUpdate < enu) { + enu = thisCertNextUpdate; + } + } + + secdebug("rvc", "revocation valid until: %lg", enu); + return enu; +} + +void SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix, CFNumberRef revocationReason) { + if (ix > certificatePath->count - 1) { return; } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + cvc->revocationReason = CFRetainSafe(revocationReason); +} + +CFNumberRef SecCertificatePathVCGetRevocationReason(SecCertificatePathVCRef certificatePath) { + for (CFIndex ix = 0; ix < certificatePath->count; ix++) { + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + if (cvc->revocationReason) { + return cvc->revocationReason; + } + } + return NULL; +} + +bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix) { + if (ix > certificatePath->count - 1) { return false; } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + return cvc->require_revocation_response; +} + +void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix) { + if (ix > certificatePath->count - 1) { return; } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + cvc->require_revocation_response = true; +} + +bool SecCertificatePathVCCheckedIssuers(SecCertificatePathVCRef certificatePath) { + return certificatePath->checkedIssuers; +} + +void SecCertificatePathVCSetCheckedIssuers(SecCertificatePathVCRef certificatePath, bool checked) { + certificatePath->checkedIssuers = checked; +} + +CFIndex SecCertificatePathVCUnknownCAIndex(SecCertificatePathVCRef certificatePath) { + return certificatePath->unknownCAIndex; +} + +void SecCertificatePathVCSetUnknownCAIndex(SecCertificatePathVCRef certificatePath, CFIndex index) { + certificatePath->unknownCAIndex = index; +} + +bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->pathValidated; +} + +void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath) { + certificatePath->pathValidated = true; +} + +bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->isEV; +} + +void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV) { + certificatePath->isEV = isEV; +} + +bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->certificates[0]->optionallyEV; +} + +bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->isCT; +} + +void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT) { + certificatePath->isCT = isCT; +} + +SecPathCTPolicy SecCertificatePathVCRequiresCT(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return kSecPathCTNotRequired; } + return certificatePath->requiresCT; +} + +void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath, SecPathCTPolicy requiresCT) { + if (certificatePath->requiresCT > requiresCT) { + return; /* once set, CT policy may be only be changed to a more strict value */ + } + certificatePath->requiresCT = requiresCT; +} + +CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return 0; } + return certificatePath->issuanceTime; +} + +void SecCertificatePathVCSetIssuanceTime(SecCertificatePathVCRef certificatePath, CFAbsoluteTime issuanceTime) { + certificatePath->issuanceTime = issuanceTime; +} + +bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->is_allowlisted; +} + +void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted) { + certificatePath->is_allowlisted = isAllowlisted; +} + +/* MARK: policy_tree path verification */ +struct policy_tree_add_ctx { + oid_t p_oid; + policy_qualifier_t p_q; +}; + +/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ +static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) { + struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; + policy_set_t policy_set; + for (policy_set = node->expected_policy_set; + policy_set; + policy_set = policy_set->oid_next) { + if (oid_equal(policy_set->oid, info->p_oid)) { + policy_tree_add_child(node, &info->p_oid, info->p_q); + return true; + } + } + return false; +} + +/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ +static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) { + struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; + if (oid_equal(node->valid_policy, oidAnyPolicy)) { + policy_tree_add_child(node, &info->p_oid, info->p_q); + return true; + } + return false; +} + +/* Return true iff node has a child with a valid_policy equal to oid. */ +static bool policy_tree_has_child_with_oid(policy_tree_t node, + const oid_t *oid) { + policy_tree_t child; + for (child = node->children; child; child = child->siblings) { + if (oid_equal(child->valid_policy, (*oid))) { + return true; + } + } + return false; +} + +/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */ +static bool policy_tree_add_expected(policy_tree_t node, void *ctx) { + policy_qualifier_t p_q = (policy_qualifier_t)ctx; + policy_set_t policy_set; + bool added_node = false; + for (policy_set = node->expected_policy_set; + policy_set; + policy_set = policy_set->oid_next) { + if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) { + policy_tree_add_child(node, &policy_set->oid, p_q); + added_node = true; + } + } + return added_node; +} + +/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ +static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) { + /* Can't map oidAnyPolicy. */ + if (oid_equal(node->valid_policy, oidAnyPolicy)) + return false; + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + policy_set_t policy_set = NULL; + /* Generate the policy_set of sdps for matching idp */ + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { + policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set)); + p_node->oid = mapping->subjectDomainPolicy; + p_node->oid_next = policy_set ? policy_set : NULL; + policy_set = p_node; + } + } + if (policy_set) { + policy_tree_set_expected_policy(node, policy_set); + return true; + } + return false; +} + +/* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows: + (i) set the valid_policy to ID-P; + (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and + (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ +static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) { + if (!oid_equal(node->valid_policy, oidAnyPolicy)) { + return false; + } + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + CFMutableDictionaryRef mappings = NULL; + CFDataRef idp = NULL; + CFDataRef sdp = NULL; + require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), + errOut); + /* First we need to walk the mappings to generate the dictionary idp->sdps */ + for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) { + oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy; + oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy; + idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull); + sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull); + CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); + if (sdps) { + CFArrayAppendValue(sdps, sdp); + } else { + require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks), errOut); + CFArrayAppendValue(sdps, sdp); + CFDictionarySetValue(mappings, idp, sdps); + CFRelease(sdps); + } + CFReleaseNull(idp); + CFReleaseNull(sdp); + } + + /* Now we use the dictionary to generate the new nodes */ + CFDictionaryForEach(mappings, ^(const void *key, const void *value) { + CFDataRef idp = key; + CFArrayRef sdps = value; + + /* (i) set the valid_policy to ID-P; */ + oid_t p_oid; + p_oid.data = (uint8_t *)CFDataGetBytePtr(idp); + p_oid.length = CFDataGetLength(idp); + + /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */ + policy_qualifier_t p_q = node->qualifier_set; + + /* (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ + __block policy_set_t p_expected = NULL; + CFArrayForEach(sdps, ^(const void *value) { + policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected)); + p_node->oid.data = (void *)CFDataGetBytePtr(value); + p_node->oid.length = CFDataGetLength(value); + p_node->oid_next = p_expected ? p_expected : NULL; + p_expected = p_node; + }); + + policy_tree_add_sibling(node, &p_oid, p_q, p_expected); + }); + CFReleaseNull(mappings); + return true; + +errOut: + CFReleaseNull(mappings); + CFReleaseNull(idp); + CFReleaseNull(sdp); + return false; +} + +static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) { + /* Can't map oidAnyPolicy. */ + if (oid_equal(node->valid_policy, oidAnyPolicy)) + return false; + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + /* If this node matches any of the idps, delete it. */ + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { + policy_tree_remove_node(&node); + break; + } + } + return true; +} + +bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix) { + /* The SecCertificatePath only tells us the last self-issued cert. + * The chain may have more than one self-issued cert, so we need to + * do the comparison. */ + bool result = false; + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, ix); + CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert); + CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert); + if (issuer && subject && CFEqual(issuer, subject)) { + result = true; + } + CFReleaseNull(issuer); + CFReleaseNull(subject); + return result; +} + +enum { + kSecPolicyTreeVerificationUnknown = 0, + kSecPolicyTreeVerificationFalse, + kSecPolicyTreeVerificationTrue, +}; + +/* RFC 5280 policy tree processing */ +bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted) { + if (!path) { return false; } + if (path->policy_tree_verification_result != kSecPolicyTreeVerificationUnknown) { + return (path->policy_tree_verification_result == kSecPolicyTreeVerificationTrue); + } + + /* Path Validation initialization */ + bool result = false; + path->policy_tree_verification_result = kSecPolicyTreeVerificationFalse; + bool initial_policy_mapping_inhibit = false; + bool initial_explicit_policy = false; + bool initial_any_policy_inhibit = false; + + SecCertificatePathVCPrunePolicyTree(path); + path->policy_tree = policy_tree_create(&oidAnyPolicy, NULL); + + assert((unsigned long)path->count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ + uint32_t n = (uint32_t)path->count; + if (anchor_trusted) { + n--; + } + + uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1; + uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1; + uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1; + + SecCertificateRef cert = NULL; + uint32_t i; + for (i = 1; i <= n; ++i) { + /* Process Cert */ + cert = SecCertificatePathVCGetCertificateAtIndex(path, n - i); + bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(path, n - i); + + /* (d) */ + if (path->policy_tree) { + const SecCECertificatePolicies *cp = + SecCertificateGetCertificatePolicies(cert); + size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; + for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { + const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; + oid_t p_oid = policy->policyIdentifier; + policy_qualifier_t p_q = &policy->policyQualifiers; + struct policy_tree_add_ctx ctx = { p_oid, p_q }; + if (!oid_equal(p_oid, oidAnyPolicy)) { + if (!policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_if_match, &ctx)) { + policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_if_any, &ctx); + } + } + } + /* The certificate policies extension includes the policy + anyPolicy with the qualifier set AP-Q and either + (a) inhibit_anyPolicy is greater than 0 or + (b) i < n and the certificate is self-issued. */ + if (inhibit_any_policy > 0 || (i < n && is_self_issued)) { + for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { + const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; + oid_t p_oid = policy->policyIdentifier; + policy_qualifier_t p_q = &policy->policyQualifiers; + if (oid_equal(p_oid, oidAnyPolicy)) { + policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_expected, (void *)p_q); + } + } + } + + policy_tree_prune_childless(&path->policy_tree, i - 1); + /* (e) */ + if (!cp) { + SecCertificatePathVCPrunePolicyTree(path); + } + } + + /* (f) Verify that either explicit_policy is greater than 0 or the + valid_policy_tree is not equal to NULL. */ + if (!path->policy_tree && explicit_policy == 0) { + /* valid_policy_tree is empty and explicit policy is 0, illegal. */ + secnotice("policy", "policy tree failure on cert %u", n - i); + goto errOut; + } + /* If Last Cert in Path */ + if (i == n) + break; + + /* Prepare for Next Cert */ + /* (a) verify that anyPolicy does not appear as an + issuerDomainPolicy or a subjectDomainPolicy */ + const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert); + if (pm && pm->present) { + size_t mapping_ix, mapping_count = pm->numMappings; + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy) + || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) { + /* Policy mapping uses anyPolicy, illegal. */ + secnotice("policy", "policy mapping anyPolicy failure %u", n - i); + goto errOut; + } + } + + /* (b) */ + /* (1) If the policy_mapping variable is greater than 0 */ + if (policy_mapping > 0 && path->policy_tree) { + if (!policy_tree_walk_depth(path->policy_tree, i, + policy_tree_map_if_match, (void *)pm)) { + /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1. */ + policy_tree_walk_depth(path->policy_tree, i, policy_tree_map_if_any, (void *)pm); + } + } else if (path->policy_tree) { + /* (i) delete each node of depth i in the valid_policy_tree + where ID-P is the valid_policy. */ + policy_tree_walk_depth(path->policy_tree, i, + policy_tree_map_delete_if_match, (void *)pm); + /* (ii) If there is a node in the valid_policy_tree of depth + i-1 or less without any child nodes, delete that + node. Repeat this step until there are no nodes of + depth i-1 or less without children. */ + policy_tree_prune_childless(&path->policy_tree, i - 1); + } + } + + /* (h) */ + if (!is_self_issued) { + if (explicit_policy) + explicit_policy--; + if (policy_mapping) + policy_mapping--; + if (inhibit_any_policy) + inhibit_any_policy--; + } + /* (i) */ + const SecCEPolicyConstraints *pc = + SecCertificateGetPolicyConstraints(cert); + if (pc) { + if (pc->requireExplicitPolicyPresent + && pc->requireExplicitPolicy < explicit_policy) { + explicit_policy = pc->requireExplicitPolicy; + } + if (pc->inhibitPolicyMappingPresent + && pc->inhibitPolicyMapping < policy_mapping) { + policy_mapping = pc->inhibitPolicyMapping; + } + } + /* (j) */ + const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert); + if (iap && iap->skipCerts < inhibit_any_policy) { + inhibit_any_policy = iap->skipCerts; + } + + } /* end of path for loop */ + + /* Wrap up */ + cert = SecCertificatePathVCGetCertificateAtIndex(path, 0); + /* (a) */ + if (explicit_policy) + explicit_policy--; + /* (b) */ + const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert); + if (pc) { + if (pc->requireExplicitPolicyPresent + && pc->requireExplicitPolicy == 0) { + explicit_policy = 0; + } + } + + /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */ + + if (path->policy_tree) { +#if !defined(NDEBUG) + policy_tree_dump(path->policy_tree); +#endif + /* (g3c4) */ + //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1); + } + + /* If either (1) the value of explicit_policy variable is greater than + zero or (2) the valid_policy_tree is not NULL, then path processing + has succeeded. */ + if (!path->policy_tree && explicit_policy == 0) { + /* valid_policy_tree is empty and explicit policy is 0, illegal. */ + secnotice("policy", "policy tree failure on leaf"); + goto errOut; + } + + path->policy_tree_verification_result = kSecPolicyTreeVerificationTrue; + result = true; + +errOut: + return result; +} diff --git a/trust/trustd/SecCertificateServer.h b/trust/trustd/SecCertificateServer.h new file mode 100644 index 00000000..91486de4 --- /dev/null +++ b/trust/trustd/SecCertificateServer.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecCertificateServer.h - SecCertificate and SecCertificatePath types + * with additonal validation context. + */ + + +#ifndef _SECURITY_SECCERTIFICATESERVER_H_ +#define _SECURITY_SECCERTIFICATESERVER_H_ + +#include + +#include + +#include "trust/trustd/policytree.h" + + +typedef struct SecCertificateVC *SecCertificateVCRef; + +SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageContraints); + +typedef struct SecCertificatePathVC *SecCertificatePathVCRef; + +/* Create a new certificate path from an old one. */ +SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, + SecCertificateRef certificate, CFArrayRef usageConstraints); + +SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, + SecCertificateRef leaf); + +/* Return a new certificate path without the first skipCount certificates. */ +SecCertificatePathVCRef SecCertificatePathVCCopyFromParent(SecCertificatePathVCRef path, CFIndex skipCount); + +/* Create an array of SecCertificateRefs from a certificate path. */ +CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path); + +/* Create an array of CFDataRefs from a certificate path. */ +CFArrayRef SecCertificatePathVCCreateSerialized(SecCertificatePathVCRef path); + +/* Record the fact that we found our own root cert as our parent + certificate. */ +void SecCertificatePathVCSetSelfIssued(SecCertificatePathVCRef certificatePath); +bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix); + +void SecCertificatePathVCSetIsAnchored(SecCertificatePathVCRef certificatePath); + +/* Return the index of the first non anchor certificate in the chain that is + self signed counting from the leaf up. Return -1 if there is none. */ +CFIndex SecCertificatePathVCSelfSignedIndex(SecCertificatePathVCRef certificatePath); + +Boolean SecCertificatePathVCIsAnchored(SecCertificatePathVCRef certificatePath); + +void SecCertificatePathVCSetNextSourceIndex(SecCertificatePathVCRef certificatePath, CFIndex sourceIndex); + +CFIndex SecCertificatePathVCGetNextSourceIndex(SecCertificatePathVCRef certificatePath); + +CFIndex SecCertificatePathVCGetCount(SecCertificatePathVCRef certificatePath); + +SecCertificateRef SecCertificatePathVCGetCertificateAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)); + +/* Return the index of certificate in path or kCFNotFound if certificate is + not in path. */ +CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, + SecCertificateRef certificate); + +/* Return the root certificate for certificatePath. Note that root is just + the top of the path as far as it is constructed. It may or may not be + trusted or self signed. */ +SecCertificateRef SecCertificatePathVCGetRoot(SecCertificatePathVCRef certificatePath); + +CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, + CFArrayRef newConstraints, CFIndex ix); + +SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +typedef CFIndex SecPathVerifyStatus; +enum { + kSecPathVerifiesUnknown = -1, + kSecPathVerifySuccess = 0, + kSecPathVerifyFailed = 1 +}; + +SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath); + +bool SecCertificatePathVCIsCycleInGraph(SecCertificatePathVCRef path); + +bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime); + +bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath); + +bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath); + +/* Score */ +CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, + CFAbsoluteTime verifyTime); +CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score); // only sets score if new score is higher +void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath); // reset score to 0 + +/* Revocation */ +void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path); +bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount); +CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path); +void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); // Returns a SecRVCRef +bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix); +void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix); +void SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix, CFNumberRef revocationReason); +CFNumberRef SecCertificatePathVCGetRevocationReason(SecCertificatePathVCRef certificatePath); // returns first revocation reason found + +bool SecCertificatePathVCCheckedIssuers(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetCheckedIssuers(SecCertificatePathVCRef certificatePath, bool checked); +CFIndex SecCertificatePathVCUnknownCAIndex(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetUnknownCAIndex(SecCertificatePathVCRef certificatePath, CFIndex index); + +/* Did we already validate this path (setting EV, CT, RVC, etc.) */ +bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath); + +/* EV */ +bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV); +bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath); + +/* CT */ +typedef CFIndex SecPathCTPolicy; +enum { + kSecPathCTNotRequired = 0, + kSecPathCTRequiredOverridable = 1, + kSecPathCTRequired = 2 +}; +bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT); +SecPathCTPolicy SecCertificatePathVCRequiresCT(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath, SecPathCTPolicy requiresCT); +CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIssuanceTime(SecCertificatePathVCRef certificatePath, CFAbsoluteTime issuanceTime); + +/* Allowlist */ +bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted); + +/* Policy Tree */ +bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted); + +#endif /* _SECURITY_SECCERTIFICATESERVER_H_ */ diff --git a/trust/trustd/SecCertificateSource.c b/trust/trustd/SecCertificateSource.c new file mode 100644 index 00000000..1c7932e7 --- /dev/null +++ b/trust/trustd/SecCertificateSource.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecCertificateSource.c - certificate sources for trust evaluation engine + * + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "trust/trustd/SecTrustServer.h" +#include "keychain/securityd/SecItemServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecCAIssuerRequest.h" + +#include "OTATrustUtilities.h" +#include "SecCertificateSource.h" + +/******************************************************** + ***************** OTA Trust support ******************** + ********************************************************/ + + +//#ifndef SECITEM_SHIM_OSX + +static CFArrayRef subject_to_anchors(CFDataRef nic); +static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets); + +static CFArrayRef subject_to_anchors(CFDataRef nic) +{ + CFArrayRef result = NULL; + + if (NULL == nic) + { + return result; + } + + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) + { + return result; + } + + CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref); + CFRelease(otapkiref); + + if (NULL == lookupTable) + { + return result; + } + + unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH]; + memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH); + + (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest); + CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull); + + + result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest); + CFReleaseSafe(lookupTable); + CFReleaseSafe(sha1Digest); + + return result; +} + +static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets) +{ + CFMutableArrayRef result = NULL; + + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiref) + { + return result; + } + + const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref); + if (NULL == anchorTable) + { + CFReleaseSafe(otapkiref); + return result; + } + + CFIndex num_offsets = CFArrayGetCount(offsets); + + result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + for (CFIndex idx = 0; idx < num_offsets; idx++) + { + CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx); + uint32_t offset_value = 0; + if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value)) + { + char* pDataPtr = (char *)(anchorTable + offset_value); + //int32_t record_length = *((int32_t * )pDataPtr); + //record_length = record_length; + pDataPtr += sizeof(uint32_t); + + int32_t cert_data_length = *((int32_t * )pDataPtr); + pDataPtr += sizeof(uint32_t); + + CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr, + cert_data_length, kCFAllocatorNull); + if (NULL != cert_data) + { + CFArrayAppendValue(result, cert_data); + CFReleaseSafe(cert_data); + } + } + } + CFReleaseSafe(otapkiref); + return result; +} + +static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets) +{ + CFMutableArrayRef result = NULL; + + CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets); + + if (NULL != cert_data_array) + { + result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFIndex num_cert_datas = CFArrayGetCount(cert_data_array); + for (CFIndex idx = 0; idx < num_cert_datas; idx++) + { + CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx); + if (NULL != cert_data) + { + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data); + if (NULL != cert) + { + CFArrayAppendValue(result, cert); + CFRelease(cert); + } + } + } + CFRelease(cert_data_array); + } + return result; + +} +//#endif // SECITEM_SHIM_OSX + +/******************************************************** + *************** END OTA Trust support ****************** + ********************************************************/ + +/******************************************************** + ************ SecCertificateSource object *************** + ********************************************************/ + +bool SecCertificateSourceCopyParents(SecCertificateSourceRef source, + SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + return source->copyParents(source, certificate, context, callback); +} + +CFArrayRef SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source, + SecCertificateRef certificate) { + if (source->copyUsageConstraints) { + return source->copyUsageConstraints(source, certificate); + } else { + return NULL; + } +} + +bool SecCertificateSourceContains(SecCertificateSourceRef source, + SecCertificateRef certificate) { + return source->contains(source, certificate); +} + +// MARK: - +// MARK: SecItemCertificateSource +/******************************************************** + *********** SecItemCertificateSource object ************ + ********************************************************/ +struct SecItemCertificateSource { + struct SecCertificateSource base; + CFArrayRef accessGroups; +}; +typedef struct SecItemCertificateSource *SecItemCertificateSourceRef; + +static CF_RETURNS_RETAINED CFArrayRef _Nullable SecItemCertificateSourceResultsPost(CFTypeRef raw_results) { + CFMutableArrayRef result = NULL; + if (isArray(raw_results)) { + result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); + CFArrayForEach(raw_results, ^(const void *value) { + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value); + if (cert) { + CFArrayAppendValue(result, cert); + CFRelease(cert); + } + }); + } else if (isData(raw_results)) { + result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results); + if (cert) { + CFArrayAppendValue(result, cert); + CFRelease(cert); + } + } + return result; +} + +static bool SecItemCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; + CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); + + CFErrorRef localError = NULL; + CFArrayRef results = SecItemCopyParentCertificates_ios(normalizedIssuer, msource->accessGroups, &localError); + if (!results) { + if (localError && (CFErrorGetCode(localError) != errSecItemNotFound)) { + secdebug("trust", "SecItemCopyParentCertificates_ios: %@", localError); + } + CFReleaseSafe(localError); + } + CFArrayRef certs = SecItemCertificateSourceResultsPost(results); + CFReleaseSafe(results); + callback(context, certs); + CFReleaseSafe(certs); + return true; +} + +static bool SecItemCertificateSourceContains(SecCertificateSourceRef source, + SecCertificateRef certificate) { + SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; + /* Look up a certificate by issuer and serial number. */ + CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); + CFRetainSafe(normalizedIssuer); + CFErrorRef localError = NULL; + CFDataRef serialNumber = SecCertificateCopySerialNumberData(certificate, &localError); + bool result = SecItemCertificateExists(normalizedIssuer, serialNumber, msource->accessGroups, &localError); + if (localError) { + if (CFErrorGetCode(localError) != errSecItemNotFound) { + secdebug("trust", "SecItemCertificateExists_ios: %@", localError); + } + CFReleaseSafe(localError); + } + CFReleaseSafe(serialNumber); + CFReleaseSafe(normalizedIssuer); + return result; +} + +SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) { + SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result)); + result->base.copyParents = SecItemCertificateSourceCopyParents; + result->base.copyUsageConstraints = NULL; + result->base.contains = SecItemCertificateSourceContains; + result->accessGroups = accessGroups; + CFRetainSafe(accessGroups); + return (SecCertificateSourceRef)result; +} + +void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) { + SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; + CFReleaseSafe(msource->accessGroups); + free(msource); +} + +// MARK: - +// MARK: SecSystemAnchorSource +/******************************************************** + *********** SecSystemAnchorSource object ************ + ********************************************************/ + +static bool SecSystemAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + CFArrayRef parents = NULL; + CFArrayRef anchors = NULL; + + CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); + /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor. + It does not matter since we would be returning the wrong anchors */ + assert((unsigned long)CFDataGetLength(nic)subjects, + normalizedIssuer) : NULL; + /* FIXME filter parents by subjectID if certificate has an + authorityKeyIdentifier. */ + secdebug("trust", "%@ parents -> %@", certificate, parents); + callback(context, parents); + return true; +} + +static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source, + SecCertificateRef certificate) { + SecMemoryCertificateSourceRef msource = + (SecMemoryCertificateSourceRef)source; + return CFSetContainsValue(msource->certificates, certificate); +} + +static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict, + const void *key, const void *value) { + if (!key) + return; + + CFMutableArrayRef values = + (CFMutableArrayRef)CFDictionaryGetValue(dict, key); + if (!values) { + values = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks); + CFDictionaryAddValue(dict, key, values); + CFRelease(values); + } + + if (values) + CFArrayAppendValue(values, value); +} + +static void SecMemoryCertificateSourceApplierFunction(const void *value, void *context) { + SecMemoryCertificateSourceRef msource = + (SecMemoryCertificateSourceRef)context; + SecCertificateRef certificate = (SecCertificateRef)value; + + /* CFSet's API has no way to combine these 2 operations into 1 sadly. */ + if (CFSetContainsValue(msource->certificates, certificate)) + return; + CFSetAddValue(msource->certificates, certificate); + + CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate); + dictAddValueToArrayForKey(msource->subjects, key, value); +} + +SecCertificateSourceRef SecMemoryCertificateSourceCreate(CFArrayRef certificates) { + SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef) + malloc(sizeof(*result)); + result->base.copyParents = SecMemoryCertificateSourceCopyParents; + result->base.copyUsageConstraints = NULL; + result->base.contains = SecMemoryCertificateSourceContains; + CFIndex count = CFArrayGetCount(certificates); + result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count, + &kCFTypeSetCallBacks); + result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault, + count, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRange range = { 0, count }; + CFArrayApplyFunction(certificates, range, + SecMemoryCertificateSourceApplierFunction, result); + + return (SecCertificateSourceRef)result; +} + +void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source) { + SecMemoryCertificateSourceRef msource = + (SecMemoryCertificateSourceRef)source; + CFRelease(msource->certificates); + CFRelease(msource->subjects); + free(msource); +} + +// MARK: - +// MARK: SecCAIssuerCertificateSource +/******************************************************** + ********* SecCAIssuerCertificateSource object ********** + ********************************************************/ +static bool SecCAIssuerCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + /* Some expired certs have dead domains. Let's not check them. */ + SecPathBuilderRef builder = (SecPathBuilderRef)context; + CFAbsoluteTime verifyDate = SecPathBuilderGetVerifyTime(builder); + if (SecPathBuilderHasTemporalParentChecks(builder) && !SecCertificateIsValid(certificate, verifyDate)) { + secinfo("async", "skipping CAIssuer fetch for expired %@", certificate); + callback(context, NULL); + return true; + } + return SecCAIssuerCopyParents(certificate, context, callback); +} + +static bool SecCAIssuerCertificateSourceContains(SecCertificateSourceRef source, SecCertificateRef certificate) { + return false; +} + +struct SecCertificateSource _kSecCAIssuerSource = { + SecCAIssuerCertificateSourceCopyParents, + NULL, + SecCAIssuerCertificateSourceContains +}; + +const SecCertificateSourceRef kSecCAIssuerSource = &_kSecCAIssuerSource; + +#if TARGET_OS_OSX +#include +// MARK: - +// MARK: SecLegacyCertificateSource +/******************************************************** + ********** SecLegacyCertificateSource object *********** + ********************************************************/ + +static bool SecLegacyCertificateSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); + callback(context, parents); + CFReleaseSafe(parents); + return true; +} + +static bool SecLegacyCertificateSourceContains(SecCertificateSourceRef source, SecCertificateRef certificate) { + SecCertificateRef cert = SecItemCopyStoredCertificate(certificate, NULL); + bool result = (cert) ? true : false; + CFReleaseSafe(cert); + return result; +} + +struct SecCertificateSource _kSecLegacyCertificateSource = { + SecLegacyCertificateSourceCopyParents, + NULL, + SecLegacyCertificateSourceContains +}; + +const SecCertificateSourceRef kSecLegacyCertificateSource = &_kSecLegacyCertificateSource; + +#endif /* SecLegacyCertificateSource */ + +#if TARGET_OS_OSX +// MARK: - +// MARK: SecLegacyAnchorSource +/******************************************************** + ************ SecLegacyAnchorSource object ************** + ********************************************************/ + +static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback) { + CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); + CFArrayRef trusted = NULL; + if (parents == NULL) { + goto finish; + } + /* Get the custom anchors which have been trusted in the user and admin domains. + * We don't need system domain roots here, since SecSystemAnchorSource provides those. + */ + OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted); + if (status == errSecSuccess && trusted) { + CFIndex index, count = CFArrayGetCount(parents); + for (index = 0; index < count; index++) { + SecCertificateRef parent = (SecCertificateRef)CFArrayGetValueAtIndex(parents, index); + if (parent && CFArrayContainsValue(trusted, CFRangeMake(0, CFArrayGetCount(trusted)), parent)) { + CFArrayAppendValue(anchors, parent); + } + } + } + +finish: + callback(context, anchors); + CFReleaseSafe(anchors); + CFReleaseSafe(parents); + CFReleaseSafe(trusted); + return true; +} + +static CFArrayRef SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source, + SecCertificateRef certificate) { + CFArrayRef result = NULL; + CFArrayRef userTrustSettings = NULL, adminTrustSettings = NULL; + + OSStatus status = SecTrustSettingsCopyTrustSettings(certificate, + kSecTrustSettingsDomainUser, + &userTrustSettings); + if ((status == errSecSuccess) && (userTrustSettings != NULL)) { + result = CFRetain(userTrustSettings); + } + + status = SecTrustSettingsCopyTrustSettings(certificate, + kSecTrustSettingsDomainAdmin, + &adminTrustSettings); + /* user trust settings overrule admin trust settings */ + if ((status == errSecSuccess) && (adminTrustSettings != NULL) && (result == NULL)) { + result = CFRetain(adminTrustSettings); + } + + CFReleaseNull(userTrustSettings); + CFReleaseNull(adminTrustSettings); + return result; +} + +static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source, + SecCertificateRef certificate) { + if (certificate == NULL) { + return false; + } + CFArrayRef trusted = NULL; + bool result = false; + OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted); + if ((status == errSecSuccess) && (trusted != NULL)) { + CFIndex index, count = CFArrayGetCount(trusted); + for (index = 0; index < count; index++) { + SecCertificateRef anchor = (SecCertificateRef)CFRetainSafe(CFArrayGetValueAtIndex(trusted, index)); + if (anchor && (CFGetTypeID(anchor) != CFGetTypeID(certificate))) { + /* This should only happen if trustd and the Security framework are using different SecCertificate TypeIDs. + * This occurs in TrustTests where we rebuild SecCertificate.c for code coverage purposes, so we end up with + * two registered SecCertificate types. So we'll make a SecCertificate of our type. */ + SecCertificateRef temp = SecCertificateCreateWithBytes(NULL, SecCertificateGetBytePtr(anchor), SecCertificateGetLength(anchor)); + CFAssignRetained(anchor, temp); + } + if (anchor && CFEqual(anchor, certificate)) { + result = true; + } + CFReleaseNull(anchor); + if (result) { + break; + } + } + } + CFReleaseSafe(trusted); + return result; +} + +struct SecCertificateSource _kSecLegacyAnchorSource = { + SecLegacyAnchorSourceCopyParents, + SecLegacyAnchorSourceCopyUsageConstraints, + SecLegacyAnchorSourceContains +}; + +const SecCertificateSourceRef kSecLegacyAnchorSource = &_kSecLegacyAnchorSource; + +#endif /* SecLegacyAnchorSource */ diff --git a/trust/trustd/SecCertificateSource.h b/trust/trustd/SecCertificateSource.h new file mode 100644 index 00000000..c2c99907 --- /dev/null +++ b/trust/trustd/SecCertificateSource.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecCertificateSource.h - certificate sources for trust evaluation engine + * + */ + +#ifndef _SECURITY_SECCERTIFICATESOURCE_H_ +#define _SECURITY_SECCERTIFICATESOURCE_H_ + +#include +#include + +/******************************************************** + ************ SecCertificateSource object *************** + ********************************************************/ +typedef struct SecCertificateSource *SecCertificateSourceRef; + +typedef void(*SecCertificateSourceParents)(void *, CFArrayRef); + +typedef bool(*CopyParents)(SecCertificateSourceRef source, + SecCertificateRef certificate, + void *context, SecCertificateSourceParents); + +typedef CFArrayRef(*CopyConstraints)(SecCertificateSourceRef source, + SecCertificateRef certificate); + +typedef bool(*Contains)(SecCertificateSourceRef source, + SecCertificateRef certificate); + +struct SecCertificateSource { + CopyParents copyParents; + CopyConstraints copyUsageConstraints; + Contains contains; +}; + +bool SecCertificateSourceCopyParents(SecCertificateSourceRef source, + SecCertificateRef certificate, + void *context, SecCertificateSourceParents callback); + +CFArrayRef SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source, + SecCertificateRef certificate); + +bool SecCertificateSourceContains(SecCertificateSourceRef source, + SecCertificateRef certificate); + +/******************************************************** + ********************** Sources ************************* + ********************************************************/ + +/* SecItemCertificateSource */ +SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups); +void SecItemCertificateSourceDestroy(SecCertificateSourceRef source); + +/* SecMemoryCertificateSource*/ +SecCertificateSourceRef SecMemoryCertificateSourceCreate(CFArrayRef certificates); +void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source); + +/* SecSystemAnchorSource */ +extern const SecCertificateSourceRef kSecSystemAnchorSource; + +#if TARGET_OS_IPHONE +/* SecUserAnchorSource */ +extern const SecCertificateSourceRef kSecUserAnchorSource; +#endif + +/* SecCAIssuerCertificateSource */ +extern const SecCertificateSourceRef kSecCAIssuerSource; + +#if TARGET_OS_OSX +/* SecLegacyCertificateSource */ +extern const SecCertificateSourceRef kSecLegacyCertificateSource; + +/* SecLegacyAnchorSource */ +extern const SecCertificateSourceRef kSecLegacyAnchorSource; +#endif + +#endif /* _SECURITY_SECCERTIFICATESOURCE_H_ */ diff --git a/trust/trustd/SecOCSPCache.c b/trust/trustd/SecOCSPCache.c new file mode 100644 index 00000000..c16d9e21 --- /dev/null +++ b/trust/trustd/SecOCSPCache.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecOCSPCache.c - securityd + */ + +#include +#include +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilities/SecCFWrappers.h" +#include "utilities/SecDb.h" +#include "utilities/SecFileLocations.h" +#include "utilities/iOSforOSX.h" + +/* Note that lastUsed is actually time of insert because we don't + refresh lastUsed on each SELECT. */ + +#define flushSQL CFSTR("DELETE FROM responses") +#define expireSQL CFSTR("DELETE FROM responses WHERE expires? AND responseId=(SELECT responseId FROM ocsp WHERE " \ + "issuerNameHash=? AND issuerPubKeyHash=? AND serialNum=? AND hashAlgorithm=?)" \ + " ORDER BY expires DESC") + +#define kSecOCSPCacheFileName CFSTR("ocspcache.sqlite3") + + +// MARK; - +// MARK: SecOCSPCacheDb + +static SecDbRef SecOCSPCacheDbCreate(CFStringRef path) { + return SecDbCreate(path, 0600, true, true, true, true, 1, + ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + __block bool ok = true; + + CFErrorRef localError = NULL; + if (!SecDbWithSQL(dbconn, selectHashAlgorithmSQL /* expireSQL */, &localError, NULL) && CFErrorGetCode(localError) == SQLITE_ERROR) { + /* SecDbWithSQL returns SQLITE_ERROR if the table we are preparing the above statement for doesn't exist. */ + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + ok &= SecDbExec(dbconn, + CFSTR("CREATE TABLE ocsp(" + "issuerNameHash BLOB NOT NULL," + "issuerPubKeyHash BLOB NOT NULL," + "serialNum BLOB NOT NULL," + "hashAlgorithm BLOB NOT NULL," + "responseId INTEGER NOT NULL" + ");" + "CREATE INDEX iResponseId ON ocsp(responseId);" + "CREATE INDEX iserialNum ON ocsp(serialNum);" + "CREATE INDEX iSNumDAlg ON ocsp(serialNum,hashAlgorithm);" + "CREATE TABLE responses(" + "responseId INTEGER PRIMARY KEY," + "ocspResponse BLOB NOT NULL," + "responderURI BLOB," + "expires DOUBLE NOT NULL," + "lastUsed DOUBLE NOT NULL" + ");" + "CREATE INDEX iexpires ON responses(expires);" + "CREATE TRIGGER tocspdel BEFORE DELETE ON responses FOR EACH ROW " + "BEGIN " + "DELETE FROM ocsp WHERE responseId=OLD.responseId;" + " END;"), error); + *commit = ok; + }); + } + CFReleaseSafe(localError); + if (!ok) { + secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); + CFIndex errCode = errSecInternalComponent; + if (error && *error) { + errCode = CFErrorGetCode(*error); + } + TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, + didCreate ? TAOperationCreate : TAOperationOpen, + TAFatalError, errCode); + } + return ok; + }); +} + +// MARK; - +// MARK: SecOCSPCache + +typedef struct __SecOCSPCache *SecOCSPCacheRef; +struct __SecOCSPCache { + SecDbRef db; +}; + +static dispatch_once_t kSecOCSPCacheOnce; +static SecOCSPCacheRef kSecOCSPCache = NULL; + +static SecOCSPCacheRef SecOCSPCacheCreate(CFStringRef db_name) { + SecOCSPCacheRef this; + + require(this = (SecOCSPCacheRef)malloc(sizeof(struct __SecOCSPCache)), errOut); + require(this->db = SecOCSPCacheDbCreate(db_name), errOut); + + return this; + +errOut: + if (this) { + CFReleaseSafe(this->db); + free(this); + } + + return NULL; +} + +static CFStringRef SecOCSPCacheCopyPath(void) { + CFStringRef ocspRelPath = kSecOCSPCacheFileName; +#if TARGET_OS_IPHONE + CFURLRef ocspURL = SecCopyURLForFileInKeychainDirectory(ocspRelPath); + if (!ocspURL) { + ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); + } +#else + /* macOS caches should be in user cache dir */ + CFURLRef ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); +#endif + CFStringRef ocspPath = NULL; + if (ocspURL) { + ocspPath = CFURLCopyFileSystemPath(ocspURL, kCFURLPOSIXPathStyle); + CFRelease(ocspURL); + } + return ocspPath; +} + +static void SecOCSPCacheWith(void(^cacheJob)(SecOCSPCacheRef cache)) { + dispatch_once(&kSecOCSPCacheOnce, ^{ + CFStringRef dbPath = SecOCSPCacheCopyPath(); + if (dbPath) { + kSecOCSPCache = SecOCSPCacheCreate(dbPath); + CFRelease(dbPath); + } + }); + // Do pre job run work here (cancel idle timers etc.) + cacheJob(kSecOCSPCache); + // Do post job run work here (gc timer, etc.) +} + +static bool _SecOCSPCacheExpireWithTransaction(SecDbConnectionRef dbconn, CFAbsoluteTime now, CFErrorRef *error) { + //if (now > nextExpireTime) + { + return SecDbWithSQL(dbconn, expireSQL, error, ^bool(sqlite3_stmt *expire) { + return SecDbBindDouble(expire, 1, now, error) && + SecDbStep(dbconn, expire, error, NULL); + }); + // TODO: Write now + expireDelay to nextExpireTime; + // currently we try to expire entries on each cache write + } +} + +/* Instance implementation. */ + +static void _SecOCSPCacheReplaceResponse(SecOCSPCacheRef this, + SecOCSPResponseRef oldResponse, SecOCSPResponseRef ocspResponse, + CFURLRef localResponderURI, CFAbsoluteTime verifyTime) { + secdebug("ocspcache", "adding response from %@", localResponderURI); + /* responses.ocspResponse */ + + // TODO: Update a latestProducedAt value using date in new entry, to ensure forward movement of time. + // Set "now" to the new producedAt we are receiving here if localTime is before this date. + // In addition whenever we run though here, check to see if "now" is more than past + // the nextCacheExpireDate and expire the cache if it is. + CFDataRef responseData = SecOCSPResponseGetData(ocspResponse); + __block CFErrorRef localError = NULL; + __block bool ok = true; + ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + __block sqlite3_int64 responseId; + if (oldResponse && (responseId = SecOCSPResponseGetID(oldResponse)) >= 0) { + ok &= SecDbWithSQL(dbconn, deleteResponseSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { + ok &= SecDbBindInt64(deleteResponse, 1, responseId, &localError); + /* Execute the delete statement. */ + ok &= SecDbStep(dbconn, deleteResponse, &localError, NULL); + return ok; + }); + } + + ok &= SecDbWithSQL(dbconn, insertResponseSQL, &localError, ^bool(sqlite3_stmt *insertResponse) { + ok &= SecDbBindBlob(insertResponse, 1, + CFDataGetBytePtr(responseData), + CFDataGetLength(responseData), + SQLITE_TRANSIENT, &localError); + + /* responses.responderURI */ + if (ok) { + CFDataRef uriData = NULL; + if (localResponderURI) { + uriData = CFURLCreateData(kCFAllocatorDefault, localResponderURI, + kCFStringEncodingUTF8, false); + } + if (uriData) { + ok = SecDbBindBlob(insertResponse, 2, + CFDataGetBytePtr(uriData), + CFDataGetLength(uriData), + SQLITE_TRANSIENT, &localError); + CFRelease(uriData); + } + } + /* responses.expires */ + ok &= SecDbBindDouble(insertResponse, 3, + SecOCSPResponseGetExpirationTime(ocspResponse), + &localError); + /* responses.lastUsed */ + ok &= SecDbBindDouble(insertResponse, 4, + verifyTime, + &localError); + + /* Execute the insert statement. */ + ok &= SecDbStep(dbconn, insertResponse, &localError, NULL); + + responseId = sqlite3_last_insert_rowid(SecDbHandle(dbconn)); + return ok; + }); + + /* Now add a link record for every singleResponse in the ocspResponse. */ + ok &= SecDbWithSQL(dbconn, insertLinkSQL, &localError, ^bool(sqlite3_stmt *insertLink) { + SecAsn1OCSPSingleResponse **responses; + for (responses = ocspResponse->responseData.responses; + *responses; ++responses) { + SecAsn1OCSPSingleResponse *resp = *responses; + SecAsn1OCSPCertID *certId = &resp->certID; + ok &= SecDbBindBlob(insertLink, 1, + certId->algId.algorithm.Data, + certId->algId.algorithm.Length, + SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(insertLink, 2, + certId->issuerNameHash.Data, + certId->issuerNameHash.Length, + SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(insertLink, 3, + certId->issuerPubKeyHash.Data, + certId->issuerPubKeyHash.Length, + SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(insertLink, 4, + certId->serialNumber.Data, + certId->serialNumber.Length, + SQLITE_TRANSIENT, &localError); + ok &= SecDbBindInt64(insertLink, 5, responseId, &localError); + + /* Execute the insert statement. */ + ok &= SecDbStep(dbconn, insertLink, &localError, NULL); + ok &= SecDbReset(insertLink, &localError); + } + return ok; + }); + + // Remove expired entries here. + // TODO: Consider only doing this once per 24 hours or something. + ok &= _SecOCSPCacheExpireWithTransaction(dbconn, verifyTime, &localError); + if (!ok) + *commit = false; + }); + }); + if (!ok) { + secerror("_SecOCSPCacheAddResponse failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + CFReleaseNull(localError); + } + CFReleaseSafe(localError); +} + +static SecOCSPResponseRef _SecOCSPCacheCopyMatching(SecOCSPCacheRef this, + SecOCSPRequestRef request, CFURLRef responderURI, CFAbsoluteTime minInsertTime) { + const DERItem *publicKey; + CFDataRef issuer = NULL; + CFDataRef serial = NULL; + __block SecOCSPResponseRef response = NULL; + __block CFErrorRef localError = NULL; + __block bool ok = true; + + require(publicKey = SecCertificateGetPublicKeyData(request->issuer), errOut); + require(issuer = SecCertificateCopyIssuerSequence(request->certificate), errOut); + require(serial = SecCertificateCopySerialNumberData(request->certificate, NULL), errOut); + + ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectHashAlgorithmSQL, &localError, ^bool(sqlite3_stmt *selectHash) { + ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); + ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stopHash) { + SecAsn1Oid algorithm; + algorithm.Data = (uint8_t *)sqlite3_column_blob(selectHash, 0); + algorithm.Length = sqlite3_column_bytes(selectHash, 0); + + /* Calculate the issuerKey and issuerName digests using the returned + hashAlgorithm. */ + CFDataRef issuerNameHash = SecDigestCreate(kCFAllocatorDefault, + &algorithm, NULL, CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); + CFDataRef issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, + &algorithm, NULL, publicKey->data, publicKey->length); + + if (issuerNameHash && issuerPubKeyHash && ok) ok &= SecDbWithSQL(dbconn, selectResponseSQL, &localError, ^bool(sqlite3_stmt *selectResponse) { + /* Now we have the serial, algorithm, issuerNameHash and + issuerPubKeyHash so let's lookup the db entry. */ + ok &= SecDbBindDouble(selectResponse, 1, minInsertTime, &localError); + ok &= SecDbBindBlob(selectResponse, 2, CFDataGetBytePtr(issuerNameHash), + CFDataGetLength(issuerNameHash), SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(selectResponse, 3, CFDataGetBytePtr(issuerPubKeyHash), + CFDataGetLength(issuerPubKeyHash), SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(selectResponse, 4, CFDataGetBytePtr(serial), + CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); + ok &= SecDbBindBlob(selectResponse, 5, algorithm.Data, + algorithm.Length, SQLITE_TRANSIENT, &localError); + ok &= SecDbStep(dbconn, selectResponse, &localError, ^(bool *stopResponse) { + /* Found an entry! */ + secdebug("ocspcache", "found cached response"); + CFDataRef resp = CFDataCreate(kCFAllocatorDefault, + sqlite3_column_blob(selectResponse, 0), + sqlite3_column_bytes(selectResponse, 0)); + sqlite3_int64 responseID = sqlite3_column_int64(selectResponse, 1); + if (resp) { + SecOCSPResponseRef new_response = SecOCSPResponseCreateWithID(resp, responseID); + if (response) { + if (SecOCSPResponseProducedAt(response) < SecOCSPResponseProducedAt(new_response)) { + SecOCSPResponseFinalize(response); + response = new_response; + } else { + SecOCSPResponseFinalize(new_response); + } + } else { + response = new_response; + } + CFRelease(resp); + } + }); + return ok; + }); + + CFReleaseSafe(issuerNameHash); + CFReleaseSafe(issuerPubKeyHash); + }); + return ok; + }); + }); + +errOut: + CFReleaseSafe(serial); + CFReleaseSafe(issuer); + + if (!ok || localError) { + secerror("ocsp cache lookup failed: %@", localError); + if (response) { + SecOCSPResponseFinalize(response); + response = NULL; + } + TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + CFReleaseSafe(localError); + + secdebug("ocspcache", "returning %s", (response ? "cached response" : "NULL")); + + return response; +} + +static bool _SecOCSPCacheFlush(SecOCSPCacheRef cache, CFErrorRef *error) { + __block CFErrorRef localError = NULL; + __block bool ok = true; + + ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbExec(dbconn, flushSQL, &localError); + }); + if (!ok || localError) { + TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + + return ok; +} + + +/* Public API */ + +void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, SecOCSPResponseRef response, + CFURLRef localResponderURI, CFAbsoluteTime verifyTime) { + SecOCSPCacheWith(^(SecOCSPCacheRef cache) { + _SecOCSPCacheReplaceResponse(cache, old_response, response, localResponderURI, verifyTime); + }); +} + +SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request, + CFURLRef localResponderURI /* may be NULL */) { + __block SecOCSPResponseRef response = NULL; + SecOCSPCacheWith(^(SecOCSPCacheRef cache) { + response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, 0.0); + }); + return response; +} + +SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request, + CFURLRef localResponderURI, CFAbsoluteTime minInsertTime) { + __block SecOCSPResponseRef response = NULL; + SecOCSPCacheWith(^(SecOCSPCacheRef cache) { + response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, minInsertTime); + }); + return response; +} + +bool SecOCSPCacheFlush(CFErrorRef *error) { + __block bool result = false; + SecOCSPCacheWith(^(SecOCSPCacheRef cache) { + result = _SecOCSPCacheFlush(cache, error); + }); + return result; +} diff --git a/trust/trustd/SecOCSPCache.h b/trust/trustd/SecOCSPCache.h new file mode 100644 index 00000000..6fef3f36 --- /dev/null +++ b/trust/trustd/SecOCSPCache.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/*! + @header SecOCSPCache + The functions provided in SecOCSPCache.h provide an interface to + an OCSP caching module. +*/ + +#ifndef _SECURITY_SECOCSPCACHE_H_ +#define _SECURITY_SECOCSPCACHE_H_ + +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" +#include + +__BEGIN_DECLS + + +void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, + SecOCSPResponseRef response, CFURLRef localResponderURI, CFAbsoluteTime verifyTime); + +SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request, + CFURLRef localResponderURI /* may be NULL */); + +SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request, + CFURLRef localResponderURI, CFAbsoluteTime minInsertTime); + +bool SecOCSPCacheFlush(CFErrorRef *error); + +__END_DECLS + +#endif /* _SECURITY_SECOCSPCACHE_H_ */ + +#if 0 +/* +Experation policy assumptions: +- We never check revocation status of anchors, whether they be system anchors, + passed in anchors or anchors hardcoded in a policy. +- Revocation information is cached for positive reponses for a limited time. +- Revocation information can be cached for negative reponses for an unlimited time. +- Revocation information need never be kept around after the certificate has expired (unless we still check after the cert has expired like we were talking about for EERI). +- Revocation information records that are used and still valid should be kept longer. +- We can set an upper limit in number of records (or certificates) in the cache. +- We can set an upper limit on total space consumed by the cache. +Questions: +- Remember bad server responses too? some ocsp responders required signed requests which we don't support, so we could consider caching the 6 (Not Authorized or something) response. + +Data needed per type of revocation record to implement this policy. + +Caching policy: +- Deleting cache should not be user option. +- Cache should surrvive backups. +- Negative caching as long as possible. + +CRL certificate stati: +unspecified, keyCompromise, cACompromise, +affiliationChanged, superseded, cessationOfOperation, +certificateHold, removeFromCRL, privilegeWithdrawn, +aACompromise, the special value UNREVOKED, or the special +value UNDETERMINED. This variable is initialized to the +special value UNREVOKED. + +CRL Timestamp values: +- thisUpdate +- nextUpdate (optional but not really 5280 says CAs must provide it even though ASN.1 is optional) +(no producedAt in CRLs, that's what thisUpdate is by definition it seems). + + +OCSP Timestamp values: + thisUpdate = May 1, 2005 01:00:00 GMT + nextUpdate = May 3, 2005 01:00:00 GMT (optional abscence means update available any time) + productedAt = May 1, 2005 01:00:00 GMT + +PER CERTIFICATE RETURN in INFO + +Revocation object used: OCSP Response, mapping from +reasons-> (CRL + most current delta CRL), Error Object (with status code). + -- good + -- revoked + -- unknown + +other exceptions (unsigned responses): + -- malformedRequest + -- internalError + -- tryLater + -- sigRequired + -- unauthorized (5019 The response "unauthorized" is returned in cases where the client + is not authorized to make this query to this server or the server + is not capable of responding authoritatively. (Expired certs might get this answer too)) + + +CRL signer chain rules: +1) Must use same anchor as cert itself. +This implies that we can only cache the validity of a leaf or intermediate certificate for CRL checking based on the mapping: +(certificate, path anchor, use_deltas) -> Revocation_status (unspecified, keyCompromise, cACompromise, +affiliationChanged, superseded, cessationOfOperation,certificateHold, removeFromCRL, privilegeWithdrawn,aACompromise, UNREVOKED, UNDETERMINED). + +OCSP signer chain rules: +(Wikipedia confirmed in rfc): The key that signs a response need not be the same key that signed the certificate. The certificate's issuer may delegate another authority to be the OCSP responder. In this case, the responder's certificate (the one that is used to sign the response) must be issued by the issuer of the certificate in question, and must include a certain extension that marks it as an OCSP signing authority (more precisely, an extended key usage extension with the OID {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) keyPurpose(3) ocspSigning(9)}) + +rfc text of the wikipedia: Therefore, a certificate's issuer MUST either sign the OCSP + responses itself or it MUST explicitly designate this authority to + another entity. OCSP signing delegation SHALL be designated by the + inclusion of id-kp-OCSPSigning in an extendedKeyUsage certificate + extension included in the OCSP response signer's certificate. This + certificate MUST be issued directly by the CA that issued the + certificate in question. + +rfc: If ocsp signing cert has id-pkix-ocsp-nocheck extension we don't check it's revocation status. + +(certificate, direct issuer certificate) -> Revocation_status good (UNREVOKED) revoked revocationTime, CRLReason (unspecified, keyCompromise, cACompromise,affiliationChanged, superseded, cessationOfOperation,certificateHold, removeFromCRL, privilegeWithdrawn,aACompromise) unknown (UNDETERMINED). + +ocsp CertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } +) + +In order to accomadate the responder using a different hashAlgorithm than we used in the request we need to recalc these from the cert itself. + +If all we have is a list of ocspresponses without knowing where they came from, we have to calculate the hashes of our issuerName and issuerKey for each hashAlgorithm we have cached ocsp responses for (optionally after limiting our candidates to those with matching serialNumbers first). + +SELECT from ocsp_cache hashAlgorithm WHERE serialNumber = + +for hix = 0 hix < hashAlgorithms.count + ALG(hix).id = hashAlgorithms(hix) + +SELECT from ocsp_cache response WHERE serialNumber = hashAlgorithm = ALG(hix).id issuerNameHash = ALG(hix).hash(issuer) issuerKeyHash = ALG(hix).hash(key) + + + + + + +Notes for Matt: +- ttl in amfi cache (to force recheck when ocsp response is invalid)? +- Periodic check before launch to remove in band waiting for ocsp response? + +Notes on Nonces in ocsp request and responses. Only ask for nonce if we think server supports it (no way to know today). Fall back on time based validity checking if reponse has no nonce, even if we asked for one + +Note on CRL checking and experation and retries of OCSP checking. +Clients MAY attempt to retrieve the CRL if no + OCSPResponse is received from the responder after a locally + configured timeout and number of retries.. + + + +CRL/OCSP cache design idea: + +revocation status table: + +rowid certhash issuer-rowid lastUsed thisUpdate producedAt nextUpdate revocationTime revocationStatus + +cacheAddOCSP(path, index_of_cert_resp_is_for, ocspResp) +cacheAddCRLStatus(path, index_of_cert_in_path, nextUpdate, revocationTime, revocationStatus) +(revocationTime, revocationStatus) = cacheLookupStatus(path, ix) + +Return a list of parent certificate hashes for the current leaf. If a result is returned, we have a candiate path leading up to an anchor, for which we already trust the signature in the chain and revocation information has been checked. + +CFArrayRef cacheSuggestParentsHashesFor(cert) + +for crl based status root must match root of path. For ocsp status issuer must match issuer of leaf in path + +presence in the cache means cert chain leading to an anchor is valid, and signed properly and trusted by the ocsp or crl policy, revocation status for cert is valid until the time indicated by nextUpdate. Cert chain itself may or may not be valid but that's checked by the policy engine. + +If a chain isn't properly signed or fails to satisfy the crl policy, it should not be in the cache. + +ocsp cache + +rowid ocspResponse (responder) lastUsed nextUpdate + +hashAlgorithm->(issuerNameHash,issuerKeyHash,serialNumber)->response + + +crl cache () + +crlDistributionPoint (reasons) crl thisUpdate nextUpdate isDelta + + +crlEntry cache table +(certHash anchorHash) crlIssuer revocationStatus revocationTime expires lastUsed +crlTable +(crlIssuer anchorHash distributionPointURL?) crl sigVerified expires +ocspEntry cache table +(certHash parentHash ocspReponderID) hashAlg revocationStatus revocationTime expires lastUsed +ocspTable +((hashAlg, pubKeyHash, issuerHash, serialNum) anchorHash) ocspResponse sigVerified expires + +or +cert cache table +(certHash parentHash anchorHash) crlEntryID ocspID + +crlEntry cache table +(crlEntryID anchorHash) crlIssuer revocationStatus revocationTime + +crlIssuerTable +(crlIssuer anchorHash) crl sigVerified + +ocsp table +(ocspID) ocspResponse + + +but so does caching the raw response as a link to a blob table containing crls +and ocsp-responses +But also cache the revocationStatus for a (cert,parent) or (cert,anchor) via +a link to a cached ocspResponse or revocationStatus and revocationTime entry from crl +*/ + +#endif diff --git a/trust/trustd/SecOCSPRequest.c b/trust/trustd/SecOCSPRequest.c new file mode 100644 index 00000000..2e9578b5 --- /dev/null +++ b/trust/trustd/SecOCSPRequest.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2008-2009,2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecOCSPRequest.c - Trust policies dealing with certificate revocation. + */ + +#include "trust/trustd/SecOCSPRequest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "SecInternal.h" + +/* + OCSPRequest ::= SEQUENCE { + tbsRequest TBSRequest, + optionalSignature [0] EXPLICIT Signature OPTIONAL } + + TBSRequest ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF Request, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + + Signature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate + OPTIONAL} + + Version ::= INTEGER { v1(0) } + + Request ::= SEQUENCE { + reqCert CertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + + CertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } + */ +static CFDataRef _SecOCSPRequestCopyDEREncoding(SecOCSPRequestRef this) { + /* fields obtained from issuer */ + SecAsn1OCSPSignedRequest signedReq = {}; + SecAsn1OCSPTbsRequest *tbs = &signedReq.tbsRequest; + SecAsn1OCSPRequest singleReq = {}; + SecAsn1OCSPCertID *certId = &singleReq.reqCert; + SecAsn1OCSPRequest *reqArray[2] = { &singleReq, NULL }; + uint8_t version = 0; + SecAsn1Item vers = {1, &version}; + CFDataRef der = NULL; + SecAsn1CoderRef coder = NULL; + CFDataRef issuerNameDigest; + CFDataRef serial; + CFDataRef issuerPubKeyDigest; + + + /* algId refers to the hash we'll perform in issuer name and key */ + certId->algId.algorithm = CSSMOID_SHA1; + /* preencoded DER NULL */ + static uint8_t nullParam[2] = {5, 0}; + certId->algId.parameters.Data = nullParam; + certId->algId.parameters.Length = sizeof(nullParam); + + /* @@@ Change this from using SecCertificateCopyIssuerSHA1Digest() / + SecCertificateCopyPublicKeySHA1Digest() to + SecCertificateCopyIssuerSequence() / SecCertificateGetPublicKeyData() + and call SecDigestCreate here instead. */ + issuerNameDigest = SecCertificateCopyIssuerSHA1Digest(this->certificate); + issuerPubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(this->issuer); + serial = SecCertificateCopySerialNumberData(this->certificate, NULL); + + /* build the CertID from those components */ + certId->issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH; + certId->issuerNameHash.Data = (uint8_t *)CFDataGetBytePtr(issuerNameDigest); + certId->issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH; + certId->issuerPubKeyHash.Data = (uint8_t *)CFDataGetBytePtr(issuerPubKeyDigest); + certId->serialNumber.Length = CFDataGetLength(serial); + certId->serialNumber.Data = (uint8_t *)CFDataGetBytePtr(serial); + + /* Build top level request with one entry in requestList, no signature, + and no optional extensions. */ + tbs->version = &vers; + tbs->requestList = reqArray; + + /* Encode the request. */ + require_noerr(SecAsn1CoderCreate(&coder), errOut); + SecAsn1Item encoded; + require_noerr(SecAsn1EncodeItem(coder, &signedReq, + kSecAsn1OCSPSignedRequestTemplate, &encoded), errOut); + der = CFDataCreate(kCFAllocatorDefault, encoded.Data, + encoded.Length); + +errOut: + if (coder) + SecAsn1CoderRelease(coder); + CFReleaseSafe(issuerNameDigest); + CFReleaseSafe(serial); + CFReleaseSafe(issuerPubKeyDigest); + + return der; +} + +SecOCSPRequestRef SecOCSPRequestCreate(SecCertificateRef certificate, + SecCertificateRef issuer) { + SecOCSPRequestRef this; + require(this = (SecOCSPRequestRef)calloc(1, sizeof(struct __SecOCSPRequest)), + errOut); + this->certificate = certificate; + this->issuer = issuer; + + return this; +errOut: + if (this) { + SecOCSPRequestFinalize(this); + } + return NULL; +} + +CFDataRef SecOCSPRequestGetDER(SecOCSPRequestRef this) { + if (!this) { return NULL; } + CFDataRef der = this->der; + if (!der) { + this->der = der = _SecOCSPRequestCopyDEREncoding(this); + } + return der; +} + +void SecOCSPRequestFinalize(SecOCSPRequestRef this) { + CFReleaseSafe(this->der); + free(this); +} + diff --git a/trust/trustd/SecOCSPRequest.h b/trust/trustd/SecOCSPRequest.h new file mode 100644 index 00000000..8ab1e6b1 --- /dev/null +++ b/trust/trustd/SecOCSPRequest.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecOCSPRequest + The functions and data types in SecOCSPRequest implement ocsp request + creation. +*/ + +#ifndef _SECURITY_SECOCSPREQUEST_H_ +#define _SECURITY_SECOCSPREQUEST_H_ + +#include +#include + +__BEGIN_DECLS + +/*! + @typedef SecOCSPRequestRef + @abstract Object used for ocsp response decoding. +*/ +typedef struct __SecOCSPRequest *SecOCSPRequestRef; + +struct __SecOCSPRequest { + SecCertificateRef certificate; // Nonretained + SecCertificateRef issuer; // Nonretained + CFDataRef der; +}; + +/*! + @function SecOCSPRequestCreate + @abstract Returns a SecOCSPRequestRef from a BER encoded ocsp response. + @param certificate The certificate for which we want a OCSP request created. + @param issuer The parent of certificate. + @result A SecOCSPRequestRef. +*/ +SecOCSPRequestRef SecOCSPRequestCreate(SecCertificateRef certificate, + SecCertificateRef issuer); + +/*! + @function SecOCSPRequestCopyDER + @abstract Returns a DER encoded ocsp request. + @param ocspRequest A SecOCSPRequestRef. + @result DER encoded ocsp request. +*/ +CFDataRef SecOCSPRequestGetDER(SecOCSPRequestRef ocspRequest); + +/*! + @function SecOCSPRequestFinalize + @abstract Frees a SecOCSPRequestRef. + @param ocspRequest A SecOCSPRequestRef. + @note The passed in SecOCSPRequestRef is deallocated +*/ +void SecOCSPRequestFinalize(SecOCSPRequestRef ocspRequest); + +__END_DECLS + +#endif /* !_SECURITY_SECOCSPREQUEST_H_ */ diff --git a/trust/trustd/SecOCSPResponse.c b/trust/trustd/SecOCSPResponse.c new file mode 100644 index 00000000..0d1995a6 --- /dev/null +++ b/trust/trustd/SecOCSPResponse.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) 2008-2009,2012-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecOCSPResponse.c - Wrapper to decode ocsp responses. + */ + +#include "trust/trustd/SecOCSPResponse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SecInternal.h" +#include +#include + + +#define ocspdErrorLog(args, ...) secerror(args, ## __VA_ARGS__) +#define ocspdHttpDebug(args...) secdebug("ocspdHttp", ## args) +#define ocspdDebug(args...) secdebug("ocsp", ## args) + + +/* + OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + + OCSPResponseStatus ::= ENUMERATED { + successful (0), --Response has valid confirmations + malformedRequest (1), --Illegal confirmation request + internalError (2), --Internal error in issuer + tryLater (3), --Try again later + --(4) is not used + sigRequired (5), --Must sign the request + unauthorized (6) --Request unauthorized + } + + ResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + + id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } + id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } + + The value for response SHALL be the DER encoding of + BasicOCSPResponse. + + BasicOCSPResponse ::= SEQUENCE { + tbsResponseData ResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + + The value for signature SHALL be computed on the hash of the DER + encoding ResponseData. + + ResponseData ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + responderID ResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF SingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + + ResponderID ::= CHOICE { + byName [1] Name, + byKey [2] KeyHash } + + KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key + (excluding the tag and length fields) + + SingleResponse ::= SEQUENCE { + certID CertID, + certStatus CertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + + CertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT RevokedInfo, + unknown [2] IMPLICIT UnknownInfo } + + RevokedInfo ::= SEQUENCE { + revocationTime GeneralizedTime, + revocationReason [0] EXPLICIT CRLReason OPTIONAL } + + UnknownInfo ::= NULL -- this can be replaced with an enumeration +*/ + +static CFAbsoluteTime genTimeToCFAbsTime(const SecAsn1Item *datetime) +{ + return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME, + datetime->Data, datetime->Length); +} + +void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this) { + CFReleaseSafe(this->scts); + free(this); +} + +static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate( + SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) { + assert(resp != NULL); + SecOCSPSingleResponseRef this; + require(this = (SecOCSPSingleResponseRef) + calloc(1, sizeof(struct __SecOCSPSingleResponse)), errOut); + this->certStatus = CS_NotParsed; + this->thisUpdate = NULL_TIME; + this->nextUpdate = NULL_TIME; + this->revokedTime = NULL_TIME; + this->crlReason = kSecRevocationReasonUndetermined; + this->scts = NULL; + + if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) { + ocspdErrorLog("OCSPSingleResponse: bad certStatus"); + goto errOut; + } + this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK); + if (this->certStatus == CS_Revoked) { + /* Decode further to get SecAsn1OCSPRevokedInfo */ + SecAsn1OCSPCertStatus certStatus; + memset(&certStatus, 0, sizeof(certStatus)); + if (SecAsn1DecodeData(coder, &resp->certStatus, + kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) { + ocspdErrorLog("OCSPSingleResponse: err decoding certStatus"); + goto errOut; + } + SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo; + if (revokedInfo != NULL) { + /* Treat this as optional even for CS_Revoked */ + this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime); + const SecAsn1Item *revReason = revokedInfo->revocationReason; + if((revReason != NULL) && + (revReason->Data != NULL) && + (revReason->Length != 0)) { + this->crlReason = revReason->Data[0]; + } + } + } + this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); + if (this->thisUpdate == NULL_TIME) { + ocspdErrorLog("OCSPResponse: bad thisUpdate DER"); + goto errOut; + } + + if (resp->nextUpdate != NULL) { + this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); + if (this->nextUpdate == NULL_TIME) { + ocspdErrorLog("OCSPResponse: bad nextUpdate DER"); + goto errOut; + } + } + + /* Lookup through extensions to find SCTs */ + if(resp->singleExtensions) { + ocspdErrorLog("OCSPResponse: single response has extension(s)."); + int i = 0; + NSS_CertExtension *extn; + while ((extn = resp->singleExtensions[i])) { + if(SecAsn1OidCompare(&extn->extnId, &OID_GOOGLE_OCSP_SCT )) { + ocspdErrorLog("OCSPResponse: single response has an SCT extension."); + SecAsn1Item sct_data = {0,}; + + // Note: if there are more that one valid SCT extension, we just use the first one that successfully decoded + if((this->scts == NULL) && (SecAsn1DecodeData(coder, &extn->value, kSecAsn1OctetStringTemplate, &sct_data) == 0)) { + this->scts = SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sct_data.Data, sct_data.Length); + ocspdErrorLog("OCSPResponse: single response has an SCT extension, parsed = %p.", this->scts); + } + } + i++; + } + } + + ocspdDebug("status %d reason %d", (int)this->certStatus, + (int)this->crlReason); + return this; +errOut: + if (this) + SecOCSPSingleResponseDestroy(this); + return NULL; +} + +#define LEEWAY (4500.0) + +/* Calculate temporal validity; set latestNextUpdate and expireTime. + Returns true if valid, else returns false. */ +bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, + CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) +{ + bool ok = false; + this->latestNextUpdate = NULL_TIME; + + if (this->producedAt > verifyTime + LEEWAY) { + secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now"); + goto exit; + } + + /* Make this->latestNextUpdate be the date farthest in the future + of any of the singleResponses nextUpdate fields. */ + SecAsn1OCSPSingleResponse **responses; + for (responses = this->responseData.responses; *responses; ++responses) { + SecAsn1OCSPSingleResponse *resp = *responses; + + /* thisUpdate later than 'now' invalidates the whole response. */ + CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); + if (thisUpdate > verifyTime + LEEWAY) { + secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now"); + goto exit; + } + + /* Keep track of latest nextUpdate. */ + if (resp->nextUpdate != NULL) { + CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); + if (nextUpdate > this->latestNextUpdate) { + this->latestNextUpdate = nextUpdate; + } + } + else { + /* RFC 5019 section 2.2.4 states on nextUpdate: + Responders MUST always include this value to aid in + response caching. See Section 6 for additional + information on caching. + */ + secnotice("ocsp", "OCSPResponse: nextUpdate not present"); +#ifdef STRICT_RFC5019 + goto exit; +#endif + } + } + + /* Now that we have this->latestNextUpdate, we figure out the latest + date at which we will expire this response from our cache. To comply + with rfc5019s: + +6.1. Caching at the Client + + To minimize bandwidth usage, clients MUST locally cache authoritative + OCSP responses (i.e., a response with a signature that has been + successfully validated and that indicate an OCSPResponseStatus of + 'successful'). + + Most OCSP clients will send OCSPRequests at or near the nextUpdate + time (when a cached response expires). To avoid large spikes in + responder load that might occur when many clients refresh cached + responses for a popular certificate, responders MAY indicate when the + client should fetch an updated OCSP response by using the cache- + control:max-age directive. Clients SHOULD fetch the updated OCSP + Response on or after the max-age time. To ensure that clients + receive an updated OCSP response, OCSP responders MUST refresh the + OCSP response before the max-age time. + +6.2 [...] + + we need to take the cache-control:max-age directive into account. + + The way the code below is written we ignore a max-age=0 in the + http header. Since a value of 0 (NULL_TIME) also means there + was no max-age in the header. This seems ok since that would imply + no-cache so we also ignore negative values for the same reason, + instead we'll expire whenever this->latestNextUpdate tells us to, + which is the signed value if max-age is too low, since we don't + want to refetch multilple times for a single page load in a browser. */ + if (this->latestNextUpdate == NULL_TIME) { + /* See comment above on RFC 5019 section 2.2.4. */ + /* Absolute expire time = current time plus defaultTTL */ + this->expireTime = verifyTime + defaultTTL; + } else if (this->latestNextUpdate < verifyTime - LEEWAY) { + secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago"); + goto exit; + } else if (maxAge > 0) { + /* Beware of double overflows such as: + + now + maxAge < this->latestNextUpdate + + in the math below since an attacker could create any positive + value for maxAge. */ + if (maxAge < this->latestNextUpdate - verifyTime) { + /* maxAge header wants us to expire the cache entry sooner than + nextUpdate would allow, to balance server load. */ + this->expireTime = verifyTime + maxAge; + } else { + /* maxAge http header attempting to make us cache the response + longer than it's valid for, bad http header! Ignoring you. */ +#ifdef DEBUG + CFStringRef hexResp = CFDataCopyHexString(this->data); + ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate," + " using latestNextUpdate %@", hexResp); + CFReleaseSafe(hexResp); +#endif + this->expireTime = this->latestNextUpdate; + } + } else { + /* No maxAge provided, just use latestNextUpdate. */ + this->expireTime = this->latestNextUpdate; + } + + ok = true; +exit: + return ok; +} + +SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID) { + SecAsn1OCSPResponse topResp = {}; + SecOCSPResponseRef this = NULL; + + require(ocspResponse, errOut); + require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)), + errOut); + require_noerr(SecAsn1CoderCreate(&this->coder), errOut); + + this->data = ocspResponse; + this->responseID = responseID; + CFRetain(ocspResponse); + + SecAsn1Item resp; + resp.Length = CFDataGetLength(ocspResponse); + resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse); + if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate, + &topResp)) { + ocspdErrorLog("OCSPResponse: decode failure at top level"); + } + /* remainder is valid only on RS_Success */ + if ((topResp.responseStatus.Data == NULL) || + (topResp.responseStatus.Length == 0)) { + ocspdErrorLog("OCSPResponse: no responseStatus"); + goto errOut; + } + this->responseStatus = topResp.responseStatus.Data[0]; + if (this->responseStatus != kSecOCSPSuccess) { +#ifdef DEBUG + CFStringRef hexResp = CFDataCopyHexString(this->data); + secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus, hexResp); + CFReleaseNull(hexResp); +#endif + /* not a failure of our constructor; this object is now useful, but + * only for this one byte of status info */ + goto fini; + } + if (topResp.responseBytes == NULL) { + /* I don't see how this can be legal on RS_Success */ + ocspdErrorLog("OCSPResponse: empty responseBytes"); + goto errOut; + } + if (!SecAsn1OidCompare(&topResp.responseBytes->responseType, + &OID_PKIX_OCSP_BASIC)) { + ocspdErrorLog("OCSPResponse: unknown responseType"); + goto errOut; + + } + + /* decode the SecAsn1OCSPBasicResponse */ + if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response, + kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) { + ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse"); + goto errOut; + } + + /* signature and cert evaluation done externally */ + + /* decode the SecAsn1OCSPResponseData */ + if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData, + kSecAsn1OCSPResponseDataTemplate, &this->responseData)) { + ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData"); + goto errOut; + } + this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt); + if (this->producedAt == NULL_TIME) { + ocspdErrorLog("OCSPResponse: bad producedAt"); + goto errOut; + } + + if (this->responseData.responderID.Data == NULL) { + ocspdErrorLog("OCSPResponse: bad responderID"); + goto errOut; + } + + /* Choice processing for ResponderID */ + this->responderIdTag = (SecAsn1OCSPResponderIDTag) + (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK); + const SecAsn1Template *templ; + switch(this->responderIdTag) { + case RIT_Name: + /* @@@ Since we don't use the decoded byName value we could skip + decoding it but we do it anyway for validation. */ + templ = kSecAsn1OCSPResponderIDAsNameTemplate; + break; + case RIT_Key: + templ = kSecAsn1OCSPResponderIDAsKeyTemplate; + break; + default: + ocspdErrorLog("OCSPResponse: bad responderID tag"); + goto errOut; + } + if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ, + &this->responderID)) { + ocspdErrorLog("OCSPResponse: decode failure at responderID"); + goto errOut; + } + +fini: + return this; +errOut: +#ifdef DEBUG + { + CFStringRef hexResp = (this) ? CFDataCopyHexString(this->data) : NULL; + secdebug("ocsp", "bad ocsp response: %@", hexResp); + CFReleaseSafe(hexResp); + } +#endif + if (this) { + SecOCSPResponseFinalize(this); + } + return NULL; +} + +SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) { + return SecOCSPResponseCreateWithID(this, -1); +} + +int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) { + return this->responseID; +} + +CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) { + return this->data; +} + +SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) { + return this->responseStatus; +} + +CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) { + return this->expireTime; +} + +CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) { + return this->nonce; +} + +CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) { + return this->producedAt; +} + +CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) { + CFMutableArrayRef result = NULL; + result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!result) { + return NULL; + } + SecAsn1Item **certs; + for (certs = this->basicResponse.certs; certs && *certs; ++certs) { + SecCertificateRef cert = NULL; + cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, (*certs)->Data, (*certs)->Length); + if (cert) { + CFArrayAppendValue(result, cert); + CFReleaseNull(cert); + } + } + + return result; +} + +void SecOCSPResponseFinalize(SecOCSPResponseRef this) { + CFReleaseSafe(this->data); + CFReleaseSafe(this->nonce); + SecAsn1CoderRelease(this->coder); + free(this); +} + +static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) { + /* rfc2560 section 2.4 states: "If nextUpdate is not set, the + responder is indicating that newer revocation information + is available all the time". + Let's ensure that thisUpdate isn't more than defaultTTL in + the past then. */ + return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate; +} + +bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) { + if (this->thisUpdate > verifyTime + LEEWAY) { + ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now"); + return false; + } + + CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL); + if (verifyTime - LEEWAY > cnu) { + ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400); + return false; + } + + return true; +} + +CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this) +{ + return CFRetainSafe(this->scts); +} + + +SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( + SecOCSPResponseRef this, SecOCSPRequestRef request) { + SecOCSPSingleResponseRef sr = NULL; + + if (!request) { return sr; } + CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate); + const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer); + CFDataRef serial = SecCertificateCopySerialNumberData(request->certificate, NULL); + CFDataRef issuerNameHash = NULL; + CFDataRef issuerPubKeyHash = NULL; + SecAsn1Oid *algorithm = NULL; + SecAsn1Item *parameters = NULL; + + SecAsn1OCSPSingleResponse **responses; + for (responses = this->responseData.responses; *responses; ++responses) { + SecAsn1OCSPSingleResponse *resp = *responses; + SecAsn1OCSPCertID *certId = &resp->certID; + /* First check the easy part, serial number should match. */ + if (!serial || certId->serialNumber.Length != (size_t)CFDataGetLength(serial) || + memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data, + certId->serialNumber.Length)) { + /* Serial # mismatch, skip this singleResponse. */ + continue; + } + + /* Calcluate the issuerKey and issuerName digests using the + hashAlgorithm and parameters specified in the certId, if + they differ from the ones we already computed. */ + if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) || + !SecAsn1OidCompare(parameters, &certId->algId.parameters)) { + algorithm = &certId->algId.algorithm; + parameters = &certId->algId.parameters; + CFReleaseSafe(issuerNameHash); + CFReleaseSafe(issuerPubKeyHash); + issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm, + parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); + issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm, + parameters, publicKey->data, publicKey->length); + } + + if (!issuerNameHash || !issuerPubKeyHash) { + /* This can happen when the hash algorithm is not supported, should be really rare */ + /* See also: CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */ + ocspdErrorLog("Unknown hash algorithm in singleResponse"); + algorithm = NULL; + parameters = NULL; + continue; + } + + if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash) + && !memcmp(CFDataGetBytePtr(issuerNameHash), + certId->issuerNameHash.Data, certId->issuerNameHash.Length) + && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash) + && !memcmp(CFDataGetBytePtr(issuerPubKeyHash), + certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) { + + /* resp matches the certificate in request, so let's use it. */ + sr = SecOCSPSingleResponseCreate(resp, this->coder); + if (sr) { + ocspdDebug("found matching singleResponse"); + break; + } + } + + } + + CFReleaseSafe(issuerPubKeyHash); + CFReleaseSafe(issuerNameHash); + CFReleaseSafe(serial); + CFReleaseSafe(issuer); + + if (!sr) { + ocspdDebug("certID not found"); + } + + return sr; +} + +static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this, + SecKeyRef key) { + /* Beware this->basicResponse.sig: on decode, length is in BITS */ + return SecKeyDigestAndVerify(key, &this->basicResponse.algId, + this->basicResponse.tbsResponseData.Data, + this->basicResponse.tbsResponseData.Length, + this->basicResponse.sig.Data, + this->basicResponse.sig.Length / 8) == errSecSuccess; +} + +static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this, + SecCertificateRef issuer) { + bool shouldBeSigner = false; + if (this->responderIdTag == RIT_Name) { + /* Name inside response must == signer's SubjectName. */ + CFDataRef subject = SecCertificateCopySubjectSequence(issuer); + if (!subject) { + ocspdDebug("error on SecCertificateCopySubjectSequence"); + return false; + } + if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length && + !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject), + this->responderID.byName.Length)) { + ocspdDebug("good ResponderID.byName"); + shouldBeSigner = true; + } else { + ocspdDebug("BAD ResponderID.byName"); + } + CFRelease(subject); + } else /* if (this->responderIdTag == RIT_Key) */ { + /* ResponderID.byKey must == SHA1(signer's public key) */ + CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(issuer); + if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length && + !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest), + this->responderID.byKey.Length)) { + ocspdDebug("good ResponderID.byKey"); + shouldBeSigner = true; + } else { + ocspdDebug("BAD ResponderID.byKey"); + } + CFRelease(pubKeyDigest); + } + + if (shouldBeSigner) { + SecKeyRef key = SecCertificateCopyKey(issuer); + if (key) { + shouldBeSigner = SecOCSPResponseVerifySignature(this, key); + ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not "); + CFRelease(key); + } else { + ocspdDebug("Failed to extract key from leaf certificate"); + shouldBeSigner = false; + } + } + + return shouldBeSigner; +} + +/* Returns the SecCertificateRef of the cert that signed this ocspResponse if + we can find one and NULL if we can't find a valid signer. */ +SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertificateRef issuer) { + /* Look though any certs that came with the response to find + * which one signed the response. */ + SecAsn1Item **certs; + for (certs = this->basicResponse.certs; certs && *certs; ++certs) { + SecCertificateRef cert = SecCertificateCreateWithBytes( + kCFAllocatorDefault, (*certs)->Data, (*certs)->Length); + if (cert) { + if (SecOCSPResponseIsIssuer(this, cert)) { + return cert; + } else { + CFRelease(cert); + } + } else { + ocspdErrorLog("ocsp response cert failed to parse"); + } + } + ocspdDebug("ocsp response did not contain a signer cert."); + + /* If none of the returned certs work, try the issuer of the certificate + being checked directly. */ + if (issuer && SecOCSPResponseIsIssuer(this, issuer)) { + CFRetain(issuer); + return issuer; + } + + /* We couldn't find who signed this ocspResponse, give up. */ + return NULL; +} diff --git a/trust/trustd/SecOCSPResponse.h b/trust/trustd/SecOCSPResponse.h new file mode 100644 index 00000000..91eec797 --- /dev/null +++ b/trust/trustd/SecOCSPResponse.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2009,2012-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecOCSPResponse + The functions and data types in SecOCSPResponse implement ocsp response + decoding and verification. +*/ + +#ifndef _SECURITY_SECOCSPRESPONSE_H_ +#define _SECURITY_SECOCSPRESPONSE_H_ + +#include +#include +#include +#include +#include "trust/trustd/SecOCSPRequest.h" +#include + +__BEGIN_DECLS + +typedef enum { + kSecOCSPBad = -2, + kSecOCSPUnknown = -1, + kSecOCSPSuccess = 0, + kSecOCSPMalformedRequest = 1, + kSecOCSPInternalError = 2, + kSecOCSPTryLater = 3, + kSecOCSPUnused = 4, + kSecOCSPSigRequired = 5, + kSecOCSPUnauthorized = 6 +} SecOCSPResponseStatus; + +enum { + kSecRevocationReasonUnrevoked = -2, + kSecRevocationReasonUndetermined = -1, + kSecRevocationReasonUnspecified = 0, + kSecRevocationReasonKeyCompromise = 1, + kSecRevocationReasonCACompromise = 2, + kSecRevocationReasonAffiliationChanged = 3, + kSecRevocationReasonSuperseded = 4, + kSecRevocationReasonCessationOfOperation = 5, + kSecRevocationReasonCertificateHold = 6, + /* -- value 7 is not used */ + kSecRevocationReasonRemoveFromCRL = 8, + kSecRevocationReasonPrivilegeWithdrawn = 9, + kSecRevocationReasonAACompromise = 10 +}; +typedef int32_t SecRevocationReason; + + +/*! + @typedef SecOCSPResponseRef + @abstract Object used for ocsp response decoding. +*/ +typedef struct __SecOCSPResponse *SecOCSPResponseRef; + +struct __SecOCSPResponse { + CFDataRef data; + SecAsn1CoderRef coder; + SecOCSPResponseStatus responseStatus; + CFDataRef nonce; + CFAbsoluteTime producedAt; + CFAbsoluteTime latestNextUpdate; + CFAbsoluteTime expireTime; + SecAsn1OCSPBasicResponse basicResponse; + SecAsn1OCSPResponseData responseData; + SecAsn1OCSPResponderIDTag responderIdTag; + SecAsn1OCSPResponderID responderID; + int64_t responseID; +}; + +typedef struct __SecOCSPSingleResponse *SecOCSPSingleResponseRef; + +struct __SecOCSPSingleResponse { + SecAsn1OCSPCertStatusTag certStatus; + CFAbsoluteTime thisUpdate; + CFAbsoluteTime nextUpdate; /* may be NULL_TIME */ + CFAbsoluteTime revokedTime; /* != NULL_TIME for certStatus == CS_Revoked */ + SecRevocationReason crlReason; + CFArrayRef scts; /* This is parsed from an extension */ +}; + +/*! + @function SecOCSPResponseCreate + @abstract Returns a SecOCSPResponseRef from a BER encoded ocsp response. + @param ocspResponse The BER encoded ocsp response. + @result A SecOCSPResponseRef. +*/ +SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef ocspResponse); + +SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID); + +int64_t SecOCSPResponseGetID(SecOCSPResponseRef ocspResponse); + +/* Return true if response is still valid for the given age. */ +bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, + CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime); + +CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this); + +SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef ocspResponse); + +CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef ocspResponse); + +CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef ocspResponse); + +CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef ocspResponse); + +/*! + @function SecOCSPResponseCopySigners + @abstract Returns an array of signers. + @param ocspResponse A SecOCSPResponseRef. + @result The passed in SecOCSPResponseRef is deallocated +*/ +CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef ocspResponse); + +/*! + @function SecOCSPResponseFinalize + @abstract Frees a SecOCSPResponseRef. + @param ocspResponse The BER encoded ocsp response. +*/ +void SecOCSPResponseFinalize(SecOCSPResponseRef ocspResponse); + +SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( + SecOCSPResponseRef ocspResponse, SecOCSPRequestRef request); + +/* DefaultTTL is how long past the thisUpdate time we trust a response without a nextUpdate field. */ +bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFAbsoluteTime defaultTTL, CFAbsoluteTime verifyTime); + +/* Find the eventual SCTs from the single response extensions */ +CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this); + +void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this); + +/* Returns the SecCertificateRef whose leaf signed this ocspResponse if + we can find one and NULL if we can't find a valid signer. The issuerPath + contains the cert chain from the anchor to the certificate that issued the + leaf certificate for which this ocspResponse is supposed to be valid. */ +SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, + SecCertificateRef issuerPath); + +__END_DECLS + +#endif /* !_SECURITY_SECOCSPRESPONSE_H_ */ diff --git a/trust/trustd/SecPinningDb.h b/trust/trustd/SecPinningDb.h new file mode 100644 index 00000000..fc5a21d6 --- /dev/null +++ b/trust/trustd/SecPinningDb.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/*! + @header SecPinningDb + The functions in SecPinningDb.h provide an interface to look up + pinning rules based on hostname. + */ + +#ifndef _SECURITY_SECPINNINGDB_H_ +#define _SECURITY_SECPINNINGDB_H_ + +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED + +extern const CFStringRef kSecPinningDbKeyHostname; +extern const CFStringRef kSecPinningDbKeyPolicyName; +extern const CFStringRef kSecPinningDbKeyRules; + +CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef _Nonnull query); +void SecPinningDbInitialize(void); + +#if !TARGET_OS_BRIDGE && __OBJC__ +/* Updating the pinning DB isn't supported on BridgeOS because we treat the disk as read-only. */ +bool SecPinningDbUpdateFromURL(NSURL *url, NSError **error); +#endif + +CFNumberRef SecPinningDbCopyContentVersion(void); + +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END + +__END_DECLS + + +#endif /* _SECURITY_SECPINNINGDB_H_ */ diff --git a/trust/trustd/SecPinningDb.m b/trust/trustd/SecPinningDb.m new file mode 100644 index 00000000..a62b9256 --- /dev/null +++ b/trust/trustd/SecPinningDb.m @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/* + * SecPinningDb.m + */ + +#include +#import +#import +#import +#import + +#if !TARGET_OS_BRIDGE +#import +#import +#endif + +#if TARGET_OS_OSX +#import +#include +#endif + +#import + +#import "trust/trustd/OTATrustUtilities.h" +#import "trust/trustd/SecPinningDb.h" +#import "trust/trustd/SecTrustLoggingServer.h" + +#include "utilities/debugging.h" +#include "utilities/sqlutils.h" +#include "utilities/iOSforOSX.h" +#include +#include +#include +#include +#include +#include "utilities/sec_action.h" + +#define kSecPinningDbFileName "pinningrules.sqlite3" + +const uint64_t PinningDbSchemaVersion = 2; +const NSString *PinningDbPolicyNameKey = @"policyName"; /* key for a string value */ +const NSString *PinningDbDomainsKey = @"domains"; /* key for an array of dictionaries */ +const NSString *PinningDbPoliciesKey = @"rules"; /* key for an array of dictionaries */ +const NSString *PinningDbDomainSuffixKey = @"suffix"; /* key for a string */ +const NSString *PinningDbLabelRegexKey = @"labelRegex"; /* key for a regex string */ + +const CFStringRef kSecPinningDbKeyHostname = CFSTR("PinningHostname"); +const CFStringRef kSecPinningDbKeyPolicyName = CFSTR("PinningPolicyName"); +const CFStringRef kSecPinningDbKeyRules = CFSTR("PinningRules"); + +@interface SecPinningDb : NSObject +@property (assign) SecDbRef db; +@property dispatch_queue_t queue; +@property NSURL *dbPath; +@property (assign) os_unfair_lock regexCacheLock; +@property NSMutableDictionary *regexCache; +- (instancetype) init; +- ( NSDictionary * _Nullable ) queryForDomain:(NSString *)domain; +- ( NSDictionary * _Nullable ) queryForPolicyName:(NSString *)policyName; +@end + +static inline bool isNSNumber(id nsType) { + return nsType && [nsType isKindOfClass:[NSNumber class]]; +} + +static inline bool isNSArray(id nsType) { + return nsType && [nsType isKindOfClass:[NSArray class]]; +} + +static inline bool isNSDictionary(id nsType) { + return nsType && [nsType isKindOfClass:[NSDictionary class]]; +} + +@implementation SecPinningDb +#define getSchemaVersionSQL CFSTR("PRAGMA user_version") +#define selectVersionSQL CFSTR("SELECT ival FROM admin WHERE key='version'") +#define insertAdminSQL CFSTR("INSERT OR REPLACE INTO admin (key,ival,value) VALUES (?,?,?)") +#define selectDomainSQL CFSTR("SELECT DISTINCT labelRegex,policyName,policies FROM rules WHERE domainSuffix=?") +#define selectPolicyNameSQL CFSTR("SELECT DISTINCT policies FROM rules WHERE policyName=?") +#define insertRuleSQL CFSTR("INSERT OR REPLACE INTO rules (policyName,domainSuffix,labelRegex,policies) VALUES (?,?,?,?) ") +#define removeAllRulesSQL CFSTR("DELETE FROM rules;") + +- (NSNumber *)getSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block bool ok = true; + __block NSNumber *version = nil; + ok &= SecDbWithSQL(dbconn, getSchemaVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { + ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { + int ival = sqlite3_column_int(selectVersion, 0); + version = [NSNumber numberWithInt:ival]; + }); + return ok; + }); + return version; +} + +- (BOOL)setSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + NSString *setVersion = [NSString stringWithFormat:@"PRAGMA user_version = %llu", PinningDbSchemaVersion]; + ok &= SecDbExec(dbconn, + (__bridge CFStringRef)setVersion, + error); + if (!ok) { + secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); + } + return ok; +} + +- (NSNumber *)getContentVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block bool ok = true; + __block NSNumber *version = nil; + ok &= SecDbWithSQL(dbconn, selectVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { + ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { + uint64_t ival = sqlite3_column_int64(selectVersion, 0); + version = [NSNumber numberWithUnsignedLongLong:ival]; + }); + return ok; + }); + return version; +} + +- (BOOL)setContentVersion:(NSNumber *)version dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + ok &= SecDbWithSQL(dbconn, insertAdminSQL, error, ^bool(sqlite3_stmt *insertAdmin) { + const char *versionKey = "version"; + ok &= SecDbBindText(insertAdmin, 1, versionKey, strlen(versionKey), SQLITE_TRANSIENT, error); + ok &= SecDbBindInt64(insertAdmin, 2, [version unsignedLongLongValue], error); + ok &= SecDbStep(dbconn, insertAdmin, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to set version %@ from pinning list: %@", version, error ? *error : nil); + } + return ok; +} + +- (BOOL) shouldUpdateContent:(NSNumber *)new_version error:(NSError **)nserror { + __block CFErrorRef error = NULL; + __block BOOL ok = YES; + __block BOOL newer = NO; + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + NSNumber *db_version = [self getContentVersion:dbconn error:&error]; + if (!db_version || [new_version compare:db_version] == NSOrderedDescending) { + newer = YES; + secnotice("pinningDb", "Pinning database should update from version %@ to version %@", db_version, new_version); + } + }); + + if (!ok || error) { + secerror("SecPinningDb: error reading content version from database %@", error); + } + if (nserror && error) { *nserror = CFBridgingRelease(error); } + return newer; +} + +- (BOOL) insertRuleWithName:(NSString *)policyName + domainSuffix:(NSString *)domainSuffix + labelRegex:(NSString *)labelRegex + policies:(NSArray *)policies + dbConnection:(SecDbConnectionRef)dbconn + error:(CFErrorRef *)error{ + /* @@@ This insertion mechanism assumes that the input is trusted -- namely, that the new rules + * are allowed to replace existing rules. For third-party inputs, this assumption isn't true. */ + + secdebug("pinningDb", "inserting new rule: %@ for %@.%@", policyName, labelRegex, domainSuffix); + + __block bool ok = true; + ok &= SecDbWithSQL(dbconn, insertRuleSQL, error, ^bool(sqlite3_stmt *insertRule) { + ok &= SecDbBindText(insertRule, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, error); + ok &= SecDbBindText(insertRule, 2, [domainSuffix UTF8String], [domainSuffix length], SQLITE_TRANSIENT, error); + ok &= SecDbBindText(insertRule, 3, [labelRegex UTF8String], [labelRegex length], SQLITE_TRANSIENT, error); + NSData *xmlPolicies = [NSPropertyListSerialization dataWithPropertyList:policies + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:nil]; + if (!xmlPolicies) { + secerror("SecPinningDb: failed to serialize policies"); + ok = false; + } + ok &= SecDbBindBlob(insertRule, 4, [xmlPolicies bytes], [xmlPolicies length], SQLITE_TRANSIENT, error); + ok &= SecDbStep(dbconn, insertRule, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to insert rule %@ for %@.%@ with error %@", policyName, labelRegex, domainSuffix, error ? *error : nil); + } + return ok; +} + +- (BOOL) populateDbFromBundle:(NSArray *)pinningList dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + [pinningList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (idx ==0) { return; } // Skip the first value which is the version + if (!isNSDictionary(obj)) { + secerror("SecPinningDb: rule entry in pinning plist is wrong class"); + ok = false; + return; + } + NSDictionary *rule = obj; + __block NSString *policyName = [rule objectForKey:PinningDbPolicyNameKey]; + NSArray *domains = [rule objectForKey:PinningDbDomainsKey]; + __block NSArray *policies = [rule objectForKey:PinningDbPoliciesKey]; + + if (!policyName || !domains || !policies) { + secerror("SecPinningDb: failed to get required fields from rule entry %lu", (unsigned long)idx); + ok = false; + return; + } + + [domains enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (!isNSDictionary(obj)) { + secerror("SecPinningDb: domain entry %lu for %@ in pinning rule is wrong class", (unsigned long)idx, policyName); + ok = false; + return; + } + NSDictionary *domain = obj; + NSString *suffix = [domain objectForKey:PinningDbDomainSuffixKey]; + NSString *labelRegex = [domain objectForKey:PinningDbLabelRegexKey]; + + if (!suffix || !labelRegex) { + secerror("SecPinningDb: failed to get required fields for entry %lu for %@", (unsigned long)idx, policyName); + ok = false; + return; + } + ok &= [self insertRuleWithName:policyName domainSuffix:suffix labelRegex:labelRegex policies:policies + dbConnection:dbconn error:error]; + }]; + }]; + if (!ok) { + secerror("SecPinningDb: failed to populate DB from pinning list: %@", error ? *error : nil); + } + return ok; +} + +- (BOOL) removeAllRulesFromDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + ok &= SecDbWithSQL(dbconn, removeAllRulesSQL, error, ^bool(sqlite3_stmt *deleteRules) { + ok &= SecDbStep(dbconn, deleteRules, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to delete old values: %@", error ? *error :nil); + } + return ok; +} + + +- (BOOL) createOrAlterAdminTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + ok &= SecDbExec(dbconn, + CFSTR("CREATE TABLE IF NOT EXISTS admin(" + "key TEXT PRIMARY KEY NOT NULL," + "ival INTEGER NOT NULL," + "value BLOB" + ");"), + error); + if (!ok) { + secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); + } + return ok; +} + +- (BOOL) createOrAlterRulesTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + ok &= SecDbExec(dbconn, + CFSTR("CREATE TABLE IF NOT EXISTS rules(" + "policyName TEXT NOT NULL," + "domainSuffix TEXT NOT NULL," + "labelRegex TEXT NOT NULL," + "policies BLOB NOT NULL," + "UNIQUE(policyName, domainSuffix, labelRegex)" + ");"), + error); + ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS idomain ON rules(domainSuffix);"), error); + ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS ipolicy ON rules(policyName);"), error); + if (!ok) { + secerror("SecPinningDb: failed to create rules table: %@", error ? *error : nil); + } + return ok; +} + +#if !TARGET_OS_BRIDGE +- (BOOL) installDbFromURL:(NSURL *)localURL error:(NSError **)nserror { + if (!localURL) { + secerror("SecPinningDb: missing url for downloaded asset"); + return NO; + } + NSURL *fileLoc = [NSURL URLWithString:@"CertificatePinning.plist" + relativeToURL:localURL]; + __block NSArray *pinningList = [NSArray arrayWithContentsOfURL:fileLoc error:nserror]; + if (!pinningList) { + secerror("SecPinningDb: unable to create pinning list from asset file: %@", fileLoc); + return NO; + } + + NSNumber *plist_version = [pinningList objectAtIndex:0]; + if (![self shouldUpdateContent:plist_version error:nserror]) { + /* Something went wrong reading the DB in order to determine whether this version is new. */ + if (nserror && *nserror) { + return NO; + } + /* We got a new plist but we already have that version installed. */ + return YES; + } + + /* Update Content */ + __block CFErrorRef error = NULL; + __block BOOL ok = YES; + dispatch_sync(self->_queue, ^{ + ok &= SecDbPerformWrite(self->_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= [self updateDb:dbconn error:&error pinningList:pinningList updateSchema:NO updateContent:YES]; + }); +#if !TARGET_OS_WATCH + /* We changed the database, so clear the database cache */ + [self clearCache]; +#endif + }); + + if (!ok || error) { + secerror("SecPinningDb: error installing updated pinning list version %@: %@", [pinningList objectAtIndex:0], error); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error + withEventName:TrustdHealthAnalyticsEventDatabaseEvent + withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), + TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationWrite) }]; +#endif // ENABLE_TRUSTD_ANALYTICS + if (nserror && error) { *nserror = CFBridgingRelease(error); } + } + + return ok; +} +#endif /* !TARGET_OS_BRIDGE */ + +- (NSArray *) copySystemPinningList { + NSArray *pinningList = nil; + NSURL *pinningListURL = nil; + /* Get the pinning list shipped with the OS */ + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (otapkiref) { + pinningListURL = CFBridgingRelease(SecOTAPKICopyPinningList(otapkiref)); + CFReleaseNull(otapkiref); + if (!pinningListURL) { + secerror("SecPinningDb: failed to get pinning plist URL"); + } + NSError *error = nil; + pinningList = [NSArray arrayWithContentsOfURL:pinningListURL error:&error]; + if (!pinningList) { + secerror("SecPinningDb: failed to read pinning plist from bundle: %@", error); + } + } + + return pinningList; +} + +- (BOOL) updateDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error pinningList:(NSArray *)pinningList + updateSchema:(BOOL)updateSchema updateContent:(BOOL)updateContent +{ + if (!SecOTAPKIIsSystemTrustd()) { return false; } + secdebug("pinningDb", "updating or creating database"); + + __block bool ok = true; + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + if (updateSchema) { + /* update the tables */ + ok &= [self createOrAlterAdminTable:dbconn error:error]; + ok &= [self createOrAlterRulesTable:dbconn error:error]; + ok &= [self setSchemaVersion:dbconn error:error]; + } + + if (updateContent) { + /* remove the old data */ + /* @@@ This behavior assumes that we have all the rules we want to populate + * elsewhere on disk and that the DB doesn't contain the sole copy of that data. */ + ok &= [self removeAllRulesFromDb:dbconn error:error]; + + /* read the new data */ + NSNumber *version = [pinningList objectAtIndex:0]; + + /* populate the tables */ + ok &= [self populateDbFromBundle:pinningList dbConnection:dbconn error:error]; + ok &= [self setContentVersion:version dbConnection:dbconn error:error]; + } + + *commit = ok; + }); + + return ok; +} + +- (SecDbRef) createAtPath { + bool readWrite = SecOTAPKIIsSystemTrustd(); +#if TARGET_OS_OSX + mode_t mode = 0644; // Root trustd can rw. All other trustds need to read. +#else + mode_t mode = 0600; // Only one trustd. +#endif + + CFStringRef path = CFStringCreateWithCString(NULL, [_dbPath fileSystemRepresentation], kCFStringEncodingUTF8); + SecDbRef result = SecDbCreate(path, mode, readWrite, readWrite, false, false, 1, + ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + if (!SecOTAPKIIsSystemTrustd()) { + /* Non-owner process can't update the db, but it should get a db connection. + * @@@ Revisit if new schema version is needed by reader processes. */ + return true; + } + + dispatch_assert_queue_not(self->_queue); + + __block BOOL ok = true; + dispatch_sync(self->_queue, ^{ + bool updateSchema = false; + bool updateContent = false; + + /* Get the pinning plist */ + NSArray *pinningList = [self copySystemPinningList]; + if (!pinningList) { + secerror("SecPinningDb: failed to find pinning plist in bundle"); + ok = false; + return; + } + + /* Check latest data and schema versions against existing table. */ + if (!isNSNumber([pinningList objectAtIndex:0])) { + secerror("SecPinningDb: pinning plist in wrong format"); + return; // Don't change status. We can continue to use old DB. + } + NSNumber *plist_version = [pinningList objectAtIndex:0]; + NSNumber *db_version = [self getContentVersion:dbconn error:error]; + secnotice("pinningDb", "Opening db with version %@", db_version); + if (!db_version || [plist_version compare:db_version] == NSOrderedDescending) { + secnotice("pinningDb", "Updating pinning database content from version %@ to version %@", + db_version ? db_version : 0, plist_version); + updateContent = true; + } + NSNumber *schema_version = [self getSchemaVersion:dbconn error:error]; + NSNumber *current_version = [NSNumber numberWithUnsignedLongLong:PinningDbSchemaVersion]; + if (!schema_version || ![schema_version isEqualToNumber:current_version]) { + secnotice("pinningDb", "Updating pinning database schema from version %@ to version %@", + schema_version, current_version); + updateSchema = true; + } + + if (updateContent || updateSchema) { + ok &= [self updateDb:dbconn error:error pinningList:pinningList updateSchema:updateSchema updateContent:updateContent]; + /* Since we updated the DB to match the list that shipped with the system, + * reset the OTAPKI Asset version to the system asset version */ + (void)SecOTAPKIResetCurrentAssetVersion(NULL); + } + if (!ok) { + secerror("SecPinningDb: %s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logHardError:(error ? (__bridge NSError *)*error : nil) + withEventName:TrustdHealthAnalyticsEventDatabaseEvent + withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), + TrustdHealthAnalyticsAttributeDatabaseOperation : didCreate ? @(TAOperationCreate) : @(TAOperationOpen)}]; +#endif // ENABLE_TRUSTD_ANALYTICS + } + }); + return ok; + }); + + CFReleaseNull(path); + return result; +} + +static void verify_create_path(const char *path) +{ + int ret = mkpath_np(path, 0755); + if (!(ret == 0 || ret == EEXIST)) { + secerror("could not create path: %s (%s)", path, strerror(ret)); + } +} + +- (NSURL *)pinningDbPath { + /* Make sure the /Library/Keychains directory is there */ + NSURL *directory = CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(nil)); + verify_create_path([directory fileSystemRepresentation]); + + /* Get the full path of the pinning DB */ + return [directory URLByAppendingPathComponent:@kSecPinningDbFileName]; +} + +- (void) initializedDb { + dispatch_sync(_queue, ^{ + if (!self->_db) { + self->_dbPath = [self pinningDbPath]; + self->_db = [self createAtPath]; + } + }); +} + +- (instancetype) init { + if (self = [super init]) { + _queue = dispatch_queue_create("Pinning DB Queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); +#if !TARGET_OS_WATCH + _regexCache = [NSMutableDictionary dictionary]; + _regexCacheLock = OS_UNFAIR_LOCK_INIT; +#endif + [self initializedDb]; + } + return self; +} + +- (void) dealloc { + CFReleaseNull(_db); +} + +/* MARK: DB Cache + * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } } + * The cache is not used on watchOS to reduce memory overhead. */ +#if !TARGET_OS_WATCH +- (void) clearCache { + os_unfair_lock_lock(&_regexCacheLock); + self.regexCache = [NSMutableDictionary dictionary]; + os_unfair_lock_unlock(&_regexCacheLock); +} +#endif // !TARGET_OS_WATCH + +#if !TARGET_OS_WATCH +- (void) addSuffixToCache:(NSString *)suffix entry:(NSDictionary *)entry { + os_unfair_lock_lock(&_regexCacheLock); + secinfo("SecPinningDb", "adding %llu entries for %@ to cache", (unsigned long long)[entry count], suffix); + self.regexCache[suffix] = entry; + os_unfair_lock_unlock(&_regexCacheLock); +} +#endif // !TARGET_OS_WATCH + +#if !TARGET_OS_WATCH +/* Because we iterate over all DB entries for a suffix, even if we find a match, we guarantee + * that the cache, if the cache has an entry for a suffix, it has all the entries for that suffix */ +- (BOOL) queryCacheForSuffix:(NSString *)suffix firstLabel:(NSString *)firstLabel results:(NSDictionary * __autoreleasing *)results{ + __block BOOL foundSuffix = NO; + os_unfair_lock_lock(&_regexCacheLock); + NSDictionary *cacheEntry; + if (NULL != (cacheEntry = self.regexCache[suffix])) { + foundSuffix = YES; + for (NSRegularExpression *regex in cacheEntry) { + NSUInteger numMatches = [regex numberOfMatchesInString:firstLabel + options:0 + range:NSMakeRange(0, [firstLabel length])]; + if (numMatches == 0) { + continue; + } + secinfo("SecPinningDb", "found matching rule in cache for %@.%@", firstLabel, suffix); + NSDictionary *resultDictionary = [cacheEntry objectForKey:regex]; + + /* Check the policyName for no-pinning settings */ + /* Return the pinning rules */ + if (results) { + /* Check the no-pinning settings to determine whether to use the rules */ + NSString *policyName = resultDictionary[(__bridge NSString *)kSecPinningDbKeyPolicyName]; + if ([self isPinningDisabled:policyName]) { + *results = @{ (__bridge NSString*)kSecPinningDbKeyRules:@[@{}], + (__bridge NSString*)kSecPinningDbKeyPolicyName:policyName}; + } else { + *results = resultDictionary; + } + } + } + } + os_unfair_lock_unlock(&_regexCacheLock); + + return foundSuffix; +} +#endif // !TARGET_OS_WATCH + +- (BOOL) isPinningDisabled:(NSString * _Nullable)policy { + static dispatch_once_t once; + static sec_action_t action; + + BOOL pinningDisabled = NO; + if (SecIsInternalRelease()) { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + pinningDisabled = [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]; + if (!pinningDisabled && policy) { + NSMutableString *policySpecificKey = [NSMutableString stringWithString:@"AppleServerAuthenticationNoPinning"]; + [policySpecificKey appendString:policy]; + pinningDisabled = [defaults boolForKey:policySpecificKey]; + secinfo("pinningQA", "%@ disable pinning = %d", policy, pinningDisabled); + } + } + + + dispatch_once(&once, ^{ + /* Only log system-wide pinning status once every five minutes */ + action = sec_action_create("pinning logging charles", 5*60.0); + sec_action_set_handler(action, ^{ + if (!SecIsInternalRelease()) { + secnotice("pinningQA", "could not disable pinning: not an internal release"); + } else { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + secnotice("pinningQA", "generic pinning disable = %d", [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]); + } + }); + }); + sec_action_perform(action); + + return pinningDisabled; +} + +- (NSDictionary * _Nullable) queryForDomain:(NSString *)domain { + if (!_queue) { (void)[self init]; } + if (!_db) { [self initializedDb]; } + + /* parse the domain into suffix and 1st label */ + NSRange firstDot = [domain rangeOfString:@"."]; + if (firstDot.location == NSNotFound) { return nil; } // Probably not a legitimate domain name + __block NSString *firstLabel = [domain substringToIndex:firstDot.location]; + __block NSString *suffix = [domain substringFromIndex:(firstDot.location + 1)]; + +#if !TARGET_OS_WATCH + /* Search cache */ + NSDictionary *cacheResult = nil; + if ([self queryCacheForSuffix:suffix firstLabel:firstLabel results:&cacheResult]) { + return cacheResult; + } +#endif + + /* Cache miss. Perform SELECT */ + __block bool ok = true; + __block CFErrorRef error = NULL; + __block NSMutableArray *resultRules = [NSMutableArray array]; + __block NSString *resultName = nil; +#if !TARGET_OS_WATCH + __block NSMutableDictionary *newCacheEntry = [NSMutableDictionary dictionary]; +#endif + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectDomainSQL, &error, ^bool(sqlite3_stmt *selectDomain) { + ok &= SecDbBindText(selectDomain, 1, [suffix UTF8String], [suffix length], SQLITE_TRANSIENT, &error); + ok &= SecDbStep(dbconn, selectDomain, &error, ^(bool *stop) { + @autoreleasepool { + /* Get the data from the entry */ + // First Label Regex + const uint8_t *regex = sqlite3_column_text(selectDomain, 0); + verify_action(regex, return); + NSString *regexStr = [NSString stringWithUTF8String:(const char *)regex]; + verify_action(regexStr, return); + NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regexStr + options:NSRegularExpressionCaseInsensitive + error:nil]; + verify_action(regularExpression, return); + // Policy name + const uint8_t *policyName = sqlite3_column_text(selectDomain, 1); + NSString *policyNameStr = [NSString stringWithUTF8String:(const char *)policyName]; + // Policies + NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectDomain, 2) length:sqlite3_column_bytes(selectDomain, 2)]; + verify_action(xmlPolicies, return); + id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; + verify_action(isNSArray(policies), return); + +#if !TARGET_OS_WATCH + /* Add to cache entry */ + [newCacheEntry setObject:@{(__bridge NSString*)kSecPinningDbKeyPolicyName:policyNameStr, + (__bridge NSString*)kSecPinningDbKeyRules:policies} + forKey:regularExpression]; +#endif + + /* Match the labelRegex */ + NSUInteger numMatches = [regularExpression numberOfMatchesInString:firstLabel + options:0 + range:NSMakeRange(0, [firstLabel length])]; + if (numMatches == 0) { + return; + } + secinfo("SecPinningDb", "found matching rule in DB for %@.%@", firstLabel, suffix); + + /* Add return data + * @@@ Assumes there is only one rule with matching suffix/label pairs. */ + [resultRules addObjectsFromArray:(NSArray *)policies]; + resultName = policyNameStr; + } + }); + return ok; + }); + }); + + if (!ok || error) { + secerror("SecPinningDb: error querying DB for hostname: %@", error); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error + withEventName:TrustdHealthAnalyticsEventDatabaseEvent + withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), + TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; +#endif // ENABLE_TRUSTD_ANALYTICS + CFReleaseNull(error); + } + +#if !TARGET_OS_WATCH + /* Add new cache entry to cache. */ + if ([newCacheEntry count] > 0) { + [self addSuffixToCache:suffix entry:newCacheEntry]; + } +#endif + + /* Return results if found */ + if ([resultRules count] > 0) { + /* Check for general no-pinning setting and return empty rules. We want to still return a + * a policy name so that requirements that don't apply to pinned domains continue to not + * apply. */ + if ([self isPinningDisabled:resultName]) { + return @{ (__bridge NSString*)kSecPinningDbKeyRules:@[@{}], + (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; + } + + return @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, + (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; + } + return nil; +} + +- (NSDictionary * _Nullable) queryForPolicyName:(NSString *)policyName { + if (!_queue) { (void)[self init]; } + if (!_db) { [self initializedDb]; } + + /* Skip the "sslServer" policyName, which is not a pinning policy */ + if ([policyName isEqualToString:@"sslServer"]) { + return nil; + } + + /* Check for general no-pinning setting */ + if ([self isPinningDisabled:nil] || [self isPinningDisabled:policyName]) { + return nil; + } + + secinfo("SecPinningDb", "Fetching rules for policy named %@", policyName); + + /* Perform SELECT */ + __block bool ok = true; + __block CFErrorRef error = NULL; + __block NSMutableArray *resultRules = [NSMutableArray array]; + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectPolicyNameSQL, &error, ^bool(sqlite3_stmt *selectPolicyName) { + ok &= SecDbBindText(selectPolicyName, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, &error); + ok &= SecDbStep(dbconn, selectPolicyName, &error, ^(bool *stop) { + @autoreleasepool { + secinfo("SecPinningDb", "found matching rule for %@ policy", policyName); + + /* Deserialize the policies and return */ + NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectPolicyName, 0) length:sqlite3_column_bytes(selectPolicyName, 0)]; + if (!xmlPolicies) { return; } + id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; + if (!isNSArray(policies)) { + return; + } + [resultRules addObjectsFromArray:(NSArray *)policies]; + } + }); + return ok; + }); + }); + + if (!ok || error) { + secerror("SecPinningDb: error querying DB for policyName: %@", error); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error + withEventName:TrustdHealthAnalyticsEventDatabaseEvent + withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), + TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; +#endif // ENABLE_TRUSTD_ANALYTICS + CFReleaseNull(error); + } + + if ([resultRules count] > 0) { + NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, + (__bridge NSString*)kSecPinningDbKeyPolicyName:policyName}; + return results; + } + return nil; +} + +@end + +/* C interfaces */ +static SecPinningDb *pinningDb = nil; +void SecPinningDbInitialize(void) { + /* Create the pinning object once per launch */ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + @autoreleasepool { + pinningDb = [[SecPinningDb alloc] init]; + __block CFErrorRef error = NULL; + BOOL ok = SecDbPerformRead([pinningDb db], &error, ^(SecDbConnectionRef dbconn) { + NSNumber *contentVersion = [pinningDb getContentVersion:dbconn error:&error]; + NSNumber *schemaVersion = [pinningDb getSchemaVersion:dbconn error:&error]; + secinfo("pinningDb", "Database Schema: %@ Content: %@", schemaVersion, contentVersion); + }); + if (!ok || error) { + secerror("SecPinningDb: unable to initialize db: %@", error); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error + withEventName:TrustdHealthAnalyticsEventDatabaseEvent + withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb), + TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}]; +#endif // ENABLE_TRUSTD_ANALYTICS + } + CFReleaseNull(error); + } + }); +} + +CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef query) { + @autoreleasepool { + SecPinningDbInitialize(); + + NSDictionary *nsQuery = (__bridge NSDictionary*)query; + NSString *hostname = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyHostname]; + + NSDictionary *results = [pinningDb queryForDomain:hostname]; + if (results) { return CFBridgingRetain(results); } + NSString *policyName = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyPolicyName]; + results = [pinningDb queryForPolicyName:policyName]; + if (!results) { return nil; } + return CFBridgingRetain(results); + } +} + +#if !TARGET_OS_BRIDGE +bool SecPinningDbUpdateFromURL(NSURL *url, NSError **error) { + SecPinningDbInitialize(); + + return [pinningDb installDbFromURL:url error:error]; +} +#endif + +CFNumberRef SecPinningDbCopyContentVersion(void) { + @autoreleasepool { + __block CFErrorRef error = NULL; + __block NSNumber *contentVersion = nil; + BOOL ok = SecDbPerformRead([pinningDb db], &error, ^(SecDbConnectionRef dbconn) { + contentVersion = [pinningDb getContentVersion:dbconn error:&error]; + }); + if (!ok || error) { + secerror("SecPinningDb: unable to get content version: %@", error); + } + CFReleaseNull(error); + if (!contentVersion) { + contentVersion = [NSNumber numberWithInteger:0]; + } + return CFBridgingRetain(contentVersion); + } +} diff --git a/trust/trustd/SecPolicyServer.c b/trust/trustd/SecPolicyServer.c new file mode 100644 index 00000000..d17d3bbd --- /dev/null +++ b/trust/trustd/SecPolicyServer.c @@ -0,0 +1,3788 @@ +/* + * Copyright (c) 2008-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies. + */ + +#include "trust/trustd/SecPolicyServer.h" +#include +#include +#include +#include "trust/trustd/policytree.h" +#include "trust/trustd/nameconstraints.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecRevocationServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include "trust/trustd/SecOCSPResponse.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include +#include +#include +#include "OTATrustUtilities.h" +#include "personalization.h" +#include + +#if !TARGET_OS_IPHONE +#include +#endif + +/* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */ +#ifndef DUMP_OCSPRESPONSES +#define DUMP_OCSPRESPONSES 0 +#endif + +#if DUMP_OCSPRESPONSES + +#include +#include + +static void secdumpdata(CFDataRef data, const char *name) { + int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666); + write(fd, CFDataGetBytePtr(data), CFDataGetLength(data)); + close(fd); +} + +#endif + + +/******************************************************** + ****************** SecPolicy object ******************** + ********************************************************/ + +static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix); +static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc); +static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc); +static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints); + +static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL; +static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL; + +static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID) +{ + CFArrayRef result = NULL; + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL == otapkiRef) + { + return result; + } + + CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef); + CFRelease(otapkiRef); + + if (NULL == evToPolicyAnchorDigest) + { + return result; + } + + CFArrayRef roots = NULL; + CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID); + if (oid && evToPolicyAnchorDigest) + { + result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid); + if (roots && CFGetTypeID(result) != CFArrayGetTypeID()) + { + secerror("EVRoot.plist has non array value"); + result = NULL; + } + CFRelease(oid); + } + CFReleaseSafe(evToPolicyAnchorDigest); + return result; +} + + +bool SecPolicyIsEVPolicy(const DERItem *policyOID) { + return SecPolicyAnchorDigestsForEVPolicy(policyOID); +} + +static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate, + policy_set_t valid_policies) { + CFDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + bool isEV = false; + /* Ensure that this certificate is a valid anchor for one of the + certificate policy oids specified in the leaf. */ + CFDataRef digest = SecCertificateGetSHA1Digest(certificate); + policy_set_t ix; + bool good_ev_anchor = false; + for (ix = valid_policies; ix; ix = ix->oid_next) { + CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid); + if (digests && CFArrayContainsValue(digests, + CFRangeMake(0, CFArrayGetCount(digests)), digest)) { + secdebug("ev", "found anchor for policy oid"); + good_ev_anchor = true; + break; + } + } + require_action_quiet(good_ev_anchor, notEV, secnotice("ev", "anchor not in plist")); + + CFAbsoluteTime october2006 = 178761600; + if (SecCertificateNotValidBefore(certificate) >= october2006) { + require_action_quiet(SecCertificateVersion(certificate) >= 3, notEV, + secnotice("ev", "Anchor issued after October 2006 and is not v3")); + } + if (SecCertificateVersion(certificate) >= 3 + && SecCertificateNotValidBefore(certificate) >= october2006) { + const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); + require_action_quiet(bc && bc->isCA == true, notEV, + secnotice("ev", "Anchor has invalid basic constraints")); + SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); + require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) + == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV, + secnotice("ev", "Anchor has invalid key usage %u", ku)); + } + + /* At least RSA 2048 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); + require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); + const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; + const void *values[] = { rsaSize, ecSize }; + require_quiet(keySizes = CFDictionaryCreate(NULL, keys, values, 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), notEV); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "Anchor's public key is too weak for EV")); + + isEV = true; + +notEV: + CFReleaseNull(rsaSize); + CFReleaseNull(ecSize); + CFReleaseNull(keySizes); + return isEV; +} + +static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) { + CFMutableDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + bool isEV = false; + + const SecCECertificatePolicies *cp; + cp = SecCertificateGetCertificatePolicies(certificate); + require_action_quiet(cp && cp->numPolicies > 0, notEV, + secnotice("ev", "SubCA missing certificate policies")); + CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate); + require_action_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV, + secnotice("ev", "SubCA missing CRLDP")); + const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); + require_action_quiet(bc && bc->isCA == true, notEV, + secnotice("ev", "SubCA has invalid basic constraints")); + SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); + require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) + == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV, + secnotice("ev", "SubCA has invalid key usage %u", ku)); + + /* 6.1.5 Key Sizes */ + CFAbsoluteTime jan2011 = 315532800; + CFAbsoluteTime jan2014 = 410227200; + require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); + require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); + if (SecCertificateNotValidBefore(certificate) < jan2011 || + SecCertificateNotValidAfter(certificate) < jan2014) { + /* At least RSA 1024 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "SubCA's public key is too small for issuance before 2011 or expiration before 2014")); + } else { + /* At least RSA 2028 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "SubCA's public key is too small for issuance after 2010 or expiration after 2013")); + } + + /* 7.1.3 Algorithm Object Identifiers */ + CFAbsoluteTime jan2016 = 473299200; + if (SecCertificateNotValidBefore(certificate) > jan2016) { + /* SHA-2 only */ + require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, + notEV, secnotice("ev", "SubCA was issued with SHA-1 after 2015")); + } + + isEV = true; + +notEV: + CFReleaseNull(rsaSize); + CFReleaseNull(ecSize); + CFReleaseNull(keySizes); + return isEV; +} + +/******************************************************** + **************** SecPolicy Callbacks ******************* + ********************************************************/ +static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc, + CFStringRef key) { +} + +static void SecPolicyCheckIdLinkage(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + CFDataRef parentSubjectKeyID = NULL; + for (ix = count - 1; ix >= 0; --ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + /* If the previous certificate in the chain had a SubjectKeyID, + make sure it matches the current certificates AuthorityKeyID. */ + if (parentSubjectKeyID) { + /* @@@ According to RFC 2459 neither AuthorityKeyID nor + SubjectKeyID can be critical. Currenty we don't check + for this. */ + CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert); + if (authorityKeyID) { + if (!CFEqual(parentSubjectKeyID, authorityKeyID)) { + /* AuthorityKeyID doesn't match issuers SubjectKeyID. */ + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } + } + + parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert); + } +} + +static void SecPolicyCheckKeyUsage(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef xku = CFDictionaryGetValue(policy->_options, key); + if (!SecPolicyCheckCertKeyUsage(leaf, xku)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) { + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key); + if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +static void SecPolicyCheckBasicConstraints(SecPVCRef pvc, + CFStringRef key) { + //SecPolicyCheckBasicContraintsCommon(pvc, key, false); +} + +static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key); + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertNonEmptySubject(cert, pvcValue)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckSSLHostname(SecPVCRef pvc, + CFStringRef key) { + /* @@@ Consider what to do if the caller passes in no hostname. Should + we then still fail if the leaf has no dnsNames or IPAddresses at all? */ + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef hostName = (CFStringRef) + CFDictionaryGetValue(policy->_options, key); + if (!isString(hostName)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + bool dnsMatch = SecPolicyCheckCertSSLHostname(leaf, hostName); + + if (!dnsMatch) { + /* Hostname mismatch or no hostnames found in certificate. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key); + if (!isString(email)) { + /* We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + + if (!SecPolicyCheckCertEmail(leaf, email)) { + /* Hostname mismatch or no hostnames found in certificate. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +static void SecPolicyCheckTemporalValidity(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecCertificateIsValid(cert, verifyTime)) { + /* Intermediate certificate has expired. */ + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc, + CFStringRef key) { + CFIndex count = SecPVCGetCertificateCount(pvc); + if (count < 2) { + /* Can't check intermediates common name if there is no intermediate. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + return; + } + + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef commonName = + (CFStringRef)CFDictionaryGetValue(policy->_options, key); + if (!isString(commonName)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectCommonName(cert, commonName)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, + key); + if (!isString(common_name)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectCommonName(cert, common_name)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options, + key); + if (!isString(prefix)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectCommonNamePrefix(cert, prefix)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, + key); + if (!isString(common_name)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectCommonNameTEST(cert, common_name)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckNotValidBefore(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key); + if (!isDate(date)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertNotValidBefore(cert, date)) { + if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) + return; + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckChainLength(SecPVCRef pvc, + CFStringRef key) { + CFIndex count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFNumberRef chainLength = + (CFNumberRef)CFDictionaryGetValue(policy->_options, key); + CFIndex value; + if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() || + !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (value != count) { + /* Chain length doesn't match policy requirement. */ + if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) + return; + } +} + +static bool isDigestInPolicy(SecPVCRef pvc, CFStringRef key, CFDataRef digest) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + + bool foundMatch = false; + if (isData(value)) + foundMatch = CFEqual(digest, value); + else if (isArray(value)) + foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), digest); + else { + /* @@@ We only support Data and Array but we can't return an error here so. + we let the evaluation fail (not much help) and assert in debug. */ + assert(false); + } + + return foundMatch; +} + +static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) { + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); + CFDataRef anchorSHA256 = NULL; + anchorSHA256 = SecCertificateCopySHA256Digest(cert); + + if (!isDigestInPolicy(pvc, key, anchorSHA256)) { + SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA256, count-1, kCFBooleanFalse); + } + + CFReleaseNull(anchorSHA256); + return; +} + + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc, + CFStringRef key) { + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); + CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert); + + if (!isDigestInPolicy(pvc, key, anchorSHA1)) + if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, count-1, kCFBooleanFalse)) + return; + + return; +} + +/* + Check the SHA256 of SPKI of the first intermediate CA certificate in the path + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = NULL; + CFDataRef digest = NULL; + + if (SecPVCGetCertificateCount(pvc) < 2) { + SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 0, kCFBooleanFalse); + return; + } + + cert = SecPVCGetCertificateAtIndex(pvc, 1); + digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert); + + if (!isDigestInPolicy(pvc, key, digest)) { + SecPVCSetResult(pvc, kSecPolicyCheckIntermediateSPKISHA256, 1, kCFBooleanFalse); + } + CFReleaseNull(digest); +} + +/* + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckAnchorApple(SecPVCRef pvc, + CFStringRef key) { + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); + SecAppleTrustAnchorFlags flags = 0; + + + bool foundMatch = SecIsAppleTrustAnchor(cert, flags); + + if (!foundMatch) + if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorApple, 0, kCFBooleanFalse)) + return; + + return; +} + + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options, + key); + if (!isString(org)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectOrganization(cert, org)) { + /* Leaf Subject Organization mismatch. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options, + key); + if (!isString(orgUnit)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + if (!SecPolicyCheckCertSubjectOrganizationalUnit(cert, orgUnit)) { + /* Leaf Subject Organization mismatch. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc, + CFStringRef key) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFArrayRef trustedServerNames = (CFArrayRef) + CFDictionaryGetValue(policy->_options, key); + /* No names specified means we accept any name. */ + if (!trustedServerNames) + return; + if (!isArray(trustedServerNames)) { + /* @@@ We can't return an error here and making the evaluation fail + won't help much either. */ + return; + } + + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + if (!SecPolicyCheckCertEAPTrustedServerNames(leaf, trustedServerNames)) { + /* Hostname mismatch or no hostnames found in certificate. */ + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = { +{ 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 }, +{ 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 }, +{ 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 }, +{ 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 }, +{ 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 }, +{ 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 }, +{ 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 }, +{ 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e }, +{ 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } }; + +static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = { + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, + 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, + 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43, + 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, + 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31, + 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54, + 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45, + 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e, + 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48, + 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45 +}; +static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151; + + +static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc, + CFStringRef key) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL; + + if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) && + (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer), + UTN_USERFirst_Hardware_Normalized_Issuer_len))) + { + CFDataRef serial = SecCertificateCopySerialNumberData(cert, NULL); + if (serial) { + CFIndex serial_length = CFDataGetLength(serial); + const uint8_t *serial_ptr = CFDataGetBytePtr(serial); + + while ((serial_length > 0) && (*serial_ptr == 0)) { + serial_ptr++; + serial_length--; + } + + if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) { + unsigned int i; + for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++) + { + if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i], + serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial))) + { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + CFReleaseSafe(serial); + return; + } + } + } + CFRelease(serial); + } + } + + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL != otapkiRef) + { + CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); + CFRelease(otapkiRef); + if (NULL != blackListedKeys) + { + /* Check for blacklisted intermediates keys. */ + CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); + if (dgst) + { + /* Check dgst against blacklist. */ + if (CFSetContainsValue(blackListedKeys, dgst)) + { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + CFRelease(dgst); + } + CFRelease(blackListedKeys); + } + } +} + +static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key) +{ + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL != otapkiRef) + { + CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef); + CFRelease(otapkiRef); + if (NULL != grayListedKeys) + { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + + CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); + if (dgst) + { + /* Check dgst against gray. */ + if (CFSetContainsValue(grayListedKeys, dgst)) + { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + CFRelease(dgst); + } + CFRelease(grayListedKeys); + } + } +} + +static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key) +{ + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + + if (!SecPolicyCheckCertLeafMarkerOid(cert, value)) { + // Don't use 'key' because that may be the legacy key (see ) + // Force because we may have gotten the legacy key instead of the new key in the policy + SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkerOid, 0, kCFBooleanFalse, true); + } +} + +static void SecPolicyCheckLeafMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key) +{ + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + + if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + + +/* + * The value is a dictionary. The dictionary contains keys indicating + * whether the value is for Prod or QA. The values are the same as + * in the options dictionary for SecPolicyCheckLeafMarkerOid. + */ +static void SecPolicyCheckLeafMarkersProdAndQA(SecPVCRef pvc, CFStringRef key) +{ + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFDictionaryRef value = CFDictionaryGetValue(policy->_options, key); + CFTypeRef prodValue = CFDictionaryGetValue(value, kSecPolicyLeafMarkerProd); + + if (!SecPolicyCheckCertLeafMarkerOid(cert, prodValue)) { + bool result = false; + if (!result) { + // Don't use 'key' because that may be the legacy key (see ) + // Force because we may have gotten the legacy key instead of the new key in the policy + SecPVCSetResultForced(pvc, kSecPolicyCheckLeafMarkersProdAndQA, 0, kCFBooleanFalse, true); + } + } +} + +static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key) +{ + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + + for (ix = 1; ix < count - 1; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (SecCertificateHasMarkerExtension(cert, value)) + return; + } + // Don't use 'key' because that may be the legacy key (see ) + // Force because we may have gotten the legacy key instead of the new key in the policy + SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateMarkerOid, 0, kCFBooleanFalse, true); +} + +static void SecPolicyCheckIntermediateMarkerOidWithoutValueCheck(SecPVCRef pvc, CFStringRef key) +{ + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + + for (ix = 1; ix < count - 1; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertLeafMarkerOidWithoutValueCheck(cert, value)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + } +} + +static void SecPolicyCheckIntermediateEKU(SecPVCRef pvc, CFStringRef key) +{ + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef peku = CFDictionaryGetValue(policy->_options, key); + + for (ix = 1; ix < count - 1; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertExtendedKeyUsage(cert, peku)) { + SecPVCSetResult(pvc, key, ix, kCFBooleanFalse); + } + } +} + +static void SecPolicyCheckIntermediateOrganization(SecPVCRef pvc, CFStringRef key) +{ + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef organization = CFDictionaryGetValue(policy->_options, key); + + for (ix = 1; ix < count - 1; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertSubjectOrganization(cert, organization)) { + // Don't use 'key' because that may be the legacy key (see ) + // Force because we may have gotten the legacy key instead of the new key in the policy + SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateOrganization, ix, kCFBooleanFalse, true); + } + } +} + +static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key) +{ + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef country = CFDictionaryGetValue(policy->_options, key); + + for (ix = 1; ix < count - 1; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertSubjectCountry(cert, country)) { + // Don't use 'key' because that may be the legacy key (see ) + // Force because we may have gotten the legacy key instead of the new key in the policy + SecPVCSetResultForced(pvc, kSecPolicyCheckIntermediateCountry, ix, kCFBooleanFalse, true); + } + } +} + +/**************************************************************************** + *********************** New rfc5280 Chain Validation *********************** + ****************************************************************************/ + +#define POLICY_MAPPING 1 +#define POLICY_SUBTREES 1 + +/* rfc5280 basic cert processing. */ +static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, + CFStringRef key) { + /* Inputs */ + //cert_path_t path; + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */ + assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ + uint32_t n = (uint32_t)count; + + bool is_anchored = SecPathBuilderIsAnchored(pvc->builder); + bool is_anchor_trusted = false; + if (is_anchored) { + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, n - 1); + if (CFArrayGetCount(constraints) == 0) { + /* Given that the path builder has already indicated the last cert in this chain has + * trust set on it, empty constraints means trusted. */ + is_anchor_trusted = true; + } else { + /* Determine whether constraints say to trust this cert for this PVC. */ + SecTrustSettingsResult tsResult = SecPVCGetTrustSettingsResult(pvc, SecCertificatePathVCGetCertificateAtIndex(path, n - 1), + constraints); + if (tsResult == kSecTrustSettingsResultTrustRoot || tsResult == kSecTrustSettingsResultTrustAsRoot) { + is_anchor_trusted = true; + } + } + } + + if (is_anchor_trusted) { + /* If the anchor is trusted we don't process the last cert in the + chain (root). */ + n--; + } else { + Boolean isSelfSigned = false; + (void) SecCertificateIsSelfSigned(SecCertificatePathVCGetCertificateAtIndex(path, n - 1), &isSelfSigned); + if (isSelfSigned) { + /* Add a detail for the root not being trusted. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted, + n - 1, kCFBooleanFalse, true)) { + return; + } + } else { + /* Add a detail for the missing intermediate. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckMissingIntermediate, + n - 1, kCFBooleanFalse, true)) { + return; + } + } + } + + CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc); + //policy_set_t user_initial_policy_set = NULL; + //trust_anchor_t anchor; + + /* Initialization */ +#if POLICY_SUBTREES + CFMutableArrayRef permitted_subtrees = NULL; + CFMutableArrayRef excluded_subtrees = NULL; + /* set the initial subtrees to the trusted anchor's subtrees, if it has them */ + SecCertificateRef anchor = SecCertificatePathVCGetRoot(path); + CFArrayRef anchor_permitted_subtrees = SecCertificateGetPermittedSubtrees(anchor); + if (is_anchor_trusted && anchor_permitted_subtrees) { + permitted_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_permitted_subtrees); + } else { + permitted_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + CFArrayRef anchor_excluded_subtrees = SecCertificateGetExcludedSubtrees(anchor); + if (is_anchor_trusted && anchor_excluded_subtrees) { + excluded_subtrees = CFArrayCreateMutableCopy(NULL, 0, anchor_excluded_subtrees); + } else { + excluded_subtrees = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + require_action_quiet(permitted_subtrees != NULL, errOut, + SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true)); + require_action_quiet(excluded_subtrees != NULL, errOut, + SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, 0, kCFBooleanFalse, true)); +#endif + + if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) { + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckPolicyConstraints, 0, kCFBooleanFalse, true)) { + goto errOut; + } + } + +#if 0 + /* Path builder ensures we only get cert chains with proper issuer + chaining with valid signatures along the way. */ + algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm; + SecKeyRef working_public_key = anchor->public_key; + x500_name_t working_issuer_name = anchor->issuer_name; +#endif + uint32_t i, max_path_length = n; + SecCertificateRef cert = NULL; + for (i = 1; i <= n; ++i) { + /* Process Cert */ + cert = SecPVCGetCertificateAtIndex(pvc, n - i); + bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i); + + /* (a) Verify the basic certificate information. */ + /* @@@ Ensure that cert was signed with working_public_key_algorithm + using the working_public_key and the working_public_key_parameters. */ + + /* Already done by chain builder. */ + if (!SecCertificateIsValid(cert, verify_time)) { + if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, n - i, kCFBooleanFalse)) { + goto errOut; + } + } + if (SecCertificateIsWeakKey(cert)) { + if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, n - i, kCFBooleanFalse)) { + goto errOut; + } + } + if (!SecPolicyCheckCertWeakSignature(cert, NULL)) { + if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, n - i, kCFBooleanFalse)) { + goto errOut; + } + } + + /* @@@ cert.issuer == working_issuer_name. */ + +#if POLICY_SUBTREES + /* (b) (c) */ + if (!is_self_issued || i == n) { + bool found = false; + /* Verify certificate Subject Name and SubjectAltNames are not within any of the excluded_subtrees */ + if(excluded_subtrees && CFArrayGetCount(excluded_subtrees)) { + if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, excluded_subtrees, &found, false)) || found) { + secnotice("policy", "name in excluded subtrees"); + if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; } + } + } + /* Verify certificate Subject Name and SubjectAltNames are within the permitted_subtrees */ + if(permitted_subtrees && CFArrayGetCount(permitted_subtrees)) { + if ((errSecSuccess != SecNameContraintsMatchSubtrees(cert, permitted_subtrees, &found, true)) || !found) { + secnotice("policy", "name not in permitted subtrees"); + if(!SecPVCSetResultForced(pvc, kSecPolicyCheckNameConstraints, n - i, kCFBooleanFalse, true)) { goto errOut; } + } + } + } +#endif + /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */ + + /* If Last Cert in Path */ + if (i == n) + break; + + /* Prepare for Next Cert */ + /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */ + /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */ +#if POLICY_SUBTREES + /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables. + */ + CFArrayRef permitted_subtrees_in_cert = SecCertificateGetPermittedSubtrees(cert); + if (permitted_subtrees_in_cert) { + SecNameConstraintsIntersectSubtrees(permitted_subtrees, permitted_subtrees_in_cert); + } + + // could do something smart here to avoid inserting the exact same constraint + CFArrayRef excluded_subtrees_in_cert = SecCertificateGetExcludedSubtrees(cert); + if (excluded_subtrees_in_cert) { + CFIndex num_trees = CFArrayGetCount(excluded_subtrees_in_cert); + CFRange range = { 0, num_trees }; + CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range); + } +#endif + /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */ + + /* (k) Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ + + /* (l) */ + if (!is_self_issued) { + if (max_path_length > 0) { + max_path_length--; + } else { + /* max_path_len exceeded, illegal. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsPathLen, + n - i, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + /* (m) */ + const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(cert); + if (bc && bc->pathLenConstraintPresent + && bc->pathLenConstraint < max_path_length) { + max_path_length = bc->pathLenConstraint; + } + + /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ + /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ + + /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */ + if (SecCertificateHasUnknownCriticalExtension(cert)) { + /* Certificate contains one or more unknown critical extensions. */ + if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, n - i, kCFBooleanFalse)) { + goto errOut; + } + } + + if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) { + /* Certificate contains one or more known exensions where parsing failed. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, n-i, kCFBooleanFalse, true)) { + goto errOut; + } + } + + } /* end loop over certs in path */ + /* Wrap up */ + /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */ + /* (c) */ + /* (d) */ + /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the +working_public_key_algorithm are different, set the working_public_key_parameters to null. */ + /* (e) */ + /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */ + if (SecCertificateHasUnknownCriticalExtension(cert)) { + /* Certificate contains one or more unknown critical extensions. */ + if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, 0, kCFBooleanFalse)) { + goto errOut; + } + } + + if (SecCertificateGetUnparseableKnownExtension(cert) != kCFNotFound) { + /* Certificate contains one or more known exensions where parsing failed. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckUnparseableExtension, 0, kCFBooleanFalse, true)) { + goto errOut; + } + } + /* (g) done by SecCertificatePathVCVerifyPolicyTree */ + +errOut: + CFReleaseNull(permitted_subtrees); + CFReleaseNull(excluded_subtrees); +} + +static policy_set_t policies_for_cert(SecCertificateRef cert) { + policy_set_t policies = NULL; + const SecCECertificatePolicies *cp = + SecCertificateGetCertificatePolicies(cert); + size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; + for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { + policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier); + } + return policies; +} + +static void SecPolicyCheckEV(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + policy_set_t valid_policies = NULL; + + /* 6.1.7. Key Usage Purposes */ + if (count) { + CFAbsoluteTime jul2016 = 489024000; + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + if (SecCertificateNotValidBefore(leaf) > jul2016 && count < 3) { + /* Root CAs may not sign subscriber certificates after 30 June 2016. */ + if (SecPVCSetResultForced(pvc, key, + 0, kCFBooleanFalse, true)) { + return; + } + } + } + + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + policy_set_t policies = policies_for_cert(cert); + if (ix == 0) { + /* Subscriber */ + /* anyPolicy in the leaf isn't allowed for EV, so only init + valid_policies if we have real policies. */ + if (!policy_set_contains(policies, &oidAnyPolicy)) { + valid_policies = policies; + policies = NULL; + } + } else if (ix < count - 1) { + /* Subordinate CA */ + if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) { + secnotice("ev", "subordinate certificate is not ev"); + if (SecPVCSetResultForced(pvc, key, + ix, kCFBooleanFalse, true)) { + policy_set_free(valid_policies); + policy_set_free(policies); + return; + } + } + policy_set_intersect(&valid_policies, policies); + } else { + /* Root CA */ + if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) { + secnotice("ev", "anchor certificate is not ev"); + if (SecPVCSetResultForced(pvc, key, + ix, kCFBooleanFalse, true)) { + policy_set_free(valid_policies); + policy_set_free(policies); + return; + } + } + } + policy_set_free(policies); + if (!valid_policies) { + secnotice("ev", "valid_policies set is empty: chain not ev"); + /* If we ever get into a state where no policies are valid anymore + this can't be an ev chain. */ + if (SecPVCSetResultForced(pvc, key, + ix, kCFBooleanFalse, true)) { + return; + } + } + } + + policy_set_free(valid_policies); + + /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a +Subscriber MUST contain an OID defined by the CA in the certificate’s +certificatePolicies extension that: (i) indicates which CA policy statement relates +to that certificate, (ii) asserts the CA’s adherence to and compliance with these +Guidelines, and (iii), by pre-agreement with the Application Software Vendor, +marks the certificate as being an EV Certificate. +(b) EV Subordinate CA Certificates +(1) Certificates issued to Subordinate CAs that are not controlled by the issuing +CA MUST contain one or more OIDs defined by the issuing CA that +explicitly identify the EV Policies that are implemented by the Subordinate +CA; +(2) Certificates issued to Subordinate CAs that are controlled by the Root CA +MAY contain the special anyPolicy OID (2.5.29.32.0). +(c) Root CA Certificates Root CA Certificates SHOULD NOT contain the +certificatePolicies or extendedKeyUsage extensions. +*/ +} + + +/* + * MARK: Certificate Transparency support + */ +const CFStringRef kSecCTRetirementDateKey = CFSTR("expiry"); // For backwards compatibility, retirement date is represented with the "expiry" key +const CFStringRef kSecCTReadOnlyDateKey = CFSTR("frozen"); // For backwards compatibility, read-only date is represented with the "frozen" key +const CFStringRef kSecCTShardStartDateKey = CFSTR("start_inclusive"); +const CFStringRef kSecCTShardEndDateKey = CFSTR("end_exclusive"); +const CFStringRef kSecCTPublicKeyKey = CFSTR("key"); + +enum { + kSecCTEntryTypeCert = 0, + kSecCTEntryTypePreCert = 1, +}; + +/*** + +struct { + Version sct_version; // 1 byte + LogID id; // 32 bytes + uint64 timestamp; // 8 bytes + CtExtensions extensions; // 2 bytes len field, + n bytes data + digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature + Version sct_version; + SignatureType signature_type = certificate_timestamp; + uint64 timestamp; + LogEntryType entry_type; + select(entry_type) { + case x509_entry: ASN.1Cert; + case precert_entry: PreCert; + } signed_entry; + CtExtensions extensions; + }; +} SignedCertificateTimestamp; + +***/ + +#include + +static const +SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg) +{ + switch(alg) { + case SSL_SignatureAlgorithmRSA: + switch (hash) { + case SSL_HashAlgorithmSHA1: + return &CSSMOID_SHA1WithRSA; + case SSL_HashAlgorithmSHA256: + return &CSSMOID_SHA256WithRSA; + case SSL_HashAlgorithmSHA384: + return &CSSMOID_SHA384WithRSA; + default: + break; + } + case SSL_SignatureAlgorithmECDSA: + switch (hash) { + case SSL_HashAlgorithmSHA1: + return &CSSMOID_ECDSA_WithSHA1; + case SSL_HashAlgorithmSHA256: + return &CSSMOID_ECDSA_WithSHA256; + case SSL_HashAlgorithmSHA384: + return &CSSMOID_ECDSA_WithSHA384; + default: + break; + } + default: + break; + } + + return NULL; +} + + +static size_t SSLDecodeUint16(const uint8_t *p) +{ + return (p[0]<<8 | p[1]); +} + +static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len) +{ + p[0] = (len >> 8)&0xff; + p[1] = (len & 0xff); + return p+2; +} + +static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len) +{ + p[0] = (len >> 16)&0xff; + p[1] = (len >> 8)&0xff; + p[2] = (len & 0xff); + return p+3; +} + + +static +uint64_t SSLDecodeUint64(const uint8_t *p) +{ + uint64_t u = 0; + for(int i=0; i<8; i++) { + u=(u<<8)|p[0]; + p++; + } + return u; +} + +#include +#include +#include + + +static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc) +{ + SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); + + CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert)); + + CFDataSetLength(data, 3+SecCertificateGetLength(leafCert)); + + uint8_t *q = CFDataGetMutableBytePtr(data); + q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert)); + memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert)); + + return data; +} + + +static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc) +{ + SecCertificateRef leafCert = NULL; + SecCertificateRef issuer = NULL; + CFDataRef issuerKeyHash = NULL; + CFDataRef tbs_precert = NULL; + CFMutableDataRef data= NULL; + + require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. + leafCert = SecPVCGetCertificateAtIndex(pvc, 0); + issuer = SecPVCGetCertificateAtIndex(pvc, 1); + + require(leafCert, out); + require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above. + issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer); + tbs_precert = SecCertificateCopyPrecertTBS(leafCert); + + require(issuerKeyHash, out); + require(tbs_precert, out); + data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); + CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); + + uint8_t *q = CFDataGetMutableBytePtr(data); + memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash + q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert)); + memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert)); + +out: + CFReleaseSafe(issuerKeyHash); + CFReleaseSafe(tbs_precert); + return data; +} + +static +CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts) +{ + return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970; +} + +static +uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at) +{ + return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000; +} + +static bool isSCTValidForLogData(CFDictionaryRef logData, int entry_type, CFAbsoluteTime sct_time, CFAbsoluteTime cert_expiry_date) { + /* only embedded SCTs can be used from retired logs. */ + if(entry_type==kSecCTEntryTypeCert && CFDictionaryContainsKey(logData, kSecCTRetirementDateKey)) { + return false; + } + + /* SCTs from after the transition to read-only are not valid (and indicate a operator failure) */ + CFDateRef frozen_date = CFDictionaryGetValue(logData, kSecCTReadOnlyDateKey); + if (frozen_date && (sct_time > CFDateGetAbsoluteTime(frozen_date))) { + secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData); + return false; + } + + /* If the log is temporally sharded, the certificate expiry date must be within the temporal shard window */ + CFDateRef start_inclusive = CFDictionaryGetValue(logData, kSecCTShardStartDateKey); + CFDateRef end_exclusive = CFDictionaryGetValue(logData, kSecCTShardEndDateKey); + if (start_inclusive && (cert_expiry_date < CFDateGetAbsoluteTime(start_inclusive))) { + return false; + } + if (end_exclusive && (cert_expiry_date >= CFDateGetAbsoluteTime(end_exclusive))) { + return false; + } + + return true; +} + + +/* + If the 'sct' is valid, add it to the validatingLogs dictionary. + + Inputs: + - validatingLogs: mutable dictionary to which to add the log that validate this SCT. + - sct: the SCT date + - entry_type: 0 for x509 cert, 1 for precert. + - entry: the cert or precert data. + - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch) + - trustedLog: Dictionary contain the Trusted Logs. + + The SCT is valid if: + - It decodes properly. + - Its timestamp is less than 'verifyTime'. + - It is signed by a log in 'trustedLogs'. + - If entry_type = 0, the log must be currently qualified. + - If entry_type = 1, the log may be expired. + + If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value. + If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier. + + */ +static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFAbsoluteTime cert_expiry_date, CFDictionaryRef trustedLogs, CFAbsoluteTime *sct_at) +{ + uint8_t version; + const uint8_t *logID; + const uint8_t *timestampData; + uint64_t timestamp; + size_t extensionsLen; + const uint8_t *extensionsData; + uint8_t hashAlg; + uint8_t sigAlg; + size_t signatureLen; + const uint8_t *signatureData; + SecKeyRef pubKey = NULL; + uint8_t *signed_data = NULL; + const SecAsn1Oid *oid = NULL; + SecAsn1AlgId algId; + CFDataRef logIDData = NULL; + CFDictionaryRef result = 0; + + const uint8_t *p = CFDataGetBytePtr(sct); + size_t len = CFDataGetLength(sct); + + require(len>=43, out); + + version = p[0]; p++; len--; + logID = p; p+=32; len-=32; + timestampData = p; p+=8; len-=8; + extensionsLen = SSLDecodeUint16(p); p+=2; len-=2; + + require(len>=extensionsLen, out); + extensionsData = p; p+=extensionsLen; len-=extensionsLen; + + require(len>=4, out); + hashAlg=p[0]; p++; len--; + sigAlg=p[0]; p++; len--; + signatureLen = SSLDecodeUint16(p); p+=2; len-=2; + require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */ + signatureData = p; + + /* verify version: only v1(0) is supported */ + if(version!=0) { + secerror("SCT version unsupported: %d\n", version); + goto out; + } + + /* verify timestamp not in the future */ + timestamp = SSLDecodeUint64(timestampData); + if(timestamp > vt) { + secerror("SCT is in the future: %llu > %llu\n", timestamp, vt); + goto out; + } + + uint8_t *q; + + /* signed entry */ + size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ; + signed_data = malloc(signed_data_len); + require(signed_data, out); + q = signed_data; + *q++ = version; + *q++ = 0; // certificate_timestamp + memcpy(q, timestampData, 8); q+=8; + q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert + memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry); + q = SSLEncodeUint16(q, extensionsLen); + memcpy(q, extensionsData, extensionsLen); + + logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull); + + CFDictionaryRef logData = CFDictionaryGetValue(trustedLogs, logIDData); + CFAbsoluteTime sct_time = TimestampToCFAbsoluteTime(timestamp); + require(logData && isSCTValidForLogData(logData, entry_type, sct_time, cert_expiry_date), out); + + CFDataRef logKeyData = CFDictionaryGetValue(logData, kSecCTPublicKeyKey); + require(logKeyData, out); // This failing would be an internal logic error + pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData); + require(pubKey, out); + + oid = oidForSigAlg(hashAlg, sigAlg); + require(oid, out); + + algId.algorithm = *oid; + algId.parameters.Data = NULL; + algId.parameters.Length = 0; + + if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) { + *sct_at = sct_time; + result = logData; + } else { + secerror("SCT signature failed (log=%@)\n", logData); + } + +out: + CFReleaseSafe(logIDData); + CFReleaseSafe(pubKey); + free(signed_data); + return result; +} + + +static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at) +{ + CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log); + + if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) { + CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at); + CFDictionarySetValue(validatingLogs, log, sct_time); + CFReleaseSafe(sct_time); + } +} + +static CFArrayRef copy_ocsp_scts(SecPVCRef pvc) +{ + CFMutableArrayRef SCTs = NULL; + SecCertificateRef leafCert = NULL; + SecCertificateRef issuer = NULL; + CFArrayRef ocspResponsesData = NULL; + SecOCSPRequestRef ocspRequest = NULL; + + ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder); + require_quiet(ocspResponsesData, out); + + require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. + leafCert = SecPVCGetCertificateAtIndex(pvc, 0); + issuer = SecPVCGetCertificateAtIndex(pvc, 1); + + require(leafCert, out); + require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above. + ocspRequest = SecOCSPRequestCreate(leafCert, issuer); + + SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + require(SCTs, out); + + CFArrayForEach(ocspResponsesData, ^(const void *value) { + /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */ + SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); + if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) { + SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest); + if(ocspSingleResponse) { + CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse); + if(singleResponseSCTs) { + CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs))); + CFRelease(singleResponseSCTs); + } + SecOCSPSingleResponseDestroy(ocspSingleResponse); + } + } + if(ocspResponse) SecOCSPResponseFinalize(ocspResponse); + }); + + if(CFArrayGetCount(SCTs)==0) { + CFReleaseNull(SCTs); + } + +out: + CFReleaseSafe(ocspResponsesData); + if(ocspRequest) + SecOCSPRequestFinalize(ocspRequest); + + return SCTs; +} + +static void SecPolicyCheckCT(SecPVCRef pvc) +{ + SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); + CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert); + CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder); + CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); + CFArrayRef ocspScts = copy_ocsp_scts(pvc); + CFDataRef precertEntry = copy_precert_entry_from_chain(pvc); + CFDataRef x509Entry = copy_x509_entry_from_chain(pvc); + __block uint32_t trustedSCTCount = 0; + __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc); + __block CFAbsoluteTime certExpiry = SecCertificateNotValidAfter(leafCert); + TA_CTFailureReason failureReason = TA_CTNoFailure; + + if (!trustedLogs) { + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref); + CFReleaseSafe(otapkiref); + } + + // This eventually contain list of logs who validated the SCT. + CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc)); + + __block bool at_least_one_currently_valid_external = 0; + __block bool at_least_one_currently_valid_embedded = 0; + __block bool unknown_log = 0; + __block bool disqualified_log = 0; + + require(logsValidatingEmbeddedScts, out); + require(currentLogsValidatingScts, out); + + /* Skip if there are no SCTs. */ + bool no_scts = (embeddedScts && CFArrayGetCount(embeddedScts) > 0) || + (builderScts && CFArrayGetCount(builderScts) > 0) || + (ocspScts && CFArrayGetCount(ocspScts) > 0); + require_action_quiet(no_scts, out, + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); + if (analytics) { + analytics->ct_failure_reason = TA_CTNoSCTs; + } + ); + + if(trustedLogs && CFDictionaryGetCount(trustedLogs) > 0) { // Don't bother trying to validate SCTs if we don't have any trusted logs. + if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert. + CFArrayForEach(embeddedScts, ^(const void *value){ + CFAbsoluteTime sct_at; + CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, certExpiry, trustedLogs, &sct_at); + if(log) { + addValidatingLog(logsValidatingEmbeddedScts, log, sct_at); + if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { + addValidatingLog(currentLogsValidatingScts, log, sct_at); + at_least_one_currently_valid_embedded = true; + trustedSCTCount++; + } else { + disqualified_log = true; + } + } else { + unknown_log = true; + } + }); + } + + if(builderScts && x509Entry) { // Don't bother if we could not get the cert. + CFArrayForEach(builderScts, ^(const void *value){ + CFAbsoluteTime sct_at; + CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); + if(log) { + addValidatingLog(currentLogsValidatingScts, log, sct_at); + at_least_one_currently_valid_external = true; + trustedSCTCount++; + } else { + unknown_log = true; + } + }); + } + + if(ocspScts && x509Entry) { + CFArrayForEach(ocspScts, ^(const void *value){ + CFAbsoluteTime sct_at; + CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); + if(log) { + addValidatingLog(currentLogsValidatingScts, log, sct_at); + at_least_one_currently_valid_external = true; + trustedSCTCount++; + } else { + unknown_log = true; + } + }); + } + } else { + failureReason = TA_CTMissingLogs; + } + + + /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision. + + Current Policy: + is_ct = (A1 AND A2) OR (B1 AND B2). + + A1: embedded SCTs from 2+ to 5+ logs valid at issuance time + A2: At least one embedded SCT from a currently valid log. + + B1: SCTs from 2 currently valid logs (from any source) + B2: At least 1 external SCT from a currently valid log. + + */ + + bool hasValidExternalSCT = (at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2); + bool hasValidEmbeddedSCT = (at_least_one_currently_valid_embedded); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + SecCertificatePathVCSetIsCT(path, false); + + if (hasValidEmbeddedSCT) { + /* Calculate issuance time based on timestamp of SCTs from current logs */ + CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) { + CFDictionaryRef log = key; + if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { + // Log is still qualified + CFDateRef ts = (CFDateRef) value; + CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts); + if(timestamp < issuanceTime) { + issuanceTime = timestamp; + } + } + }); + SecCertificatePathVCSetIssuanceTime(path, issuanceTime); + } + if (hasValidExternalSCT) { + /* Note: since external SCT validates this cert, we do not need to + override issuance time here. If the cert also has a valid embedded + SCT, issuanceTime will be calculated and set in the block above. */ + SecCertificatePathVCSetIsCT(path, true); + } else if (hasValidEmbeddedSCT) { + __block int lifetime; // in Months + __block unsigned once_or_current_qualified_embedded = 0; + + /* Count Logs */ + __block bool failed_once_check = false; + CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) { + CFDictionaryRef log = key; + CFDateRef ts = value; + CFDateRef expiry = CFDictionaryGetValue(log, kSecCTRetirementDateKey); + if (expiry == NULL) { // Currently qualified OR + once_or_current_qualified_embedded++; + } else if (CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan && // Once qualified. That is, qualified at the time of SCT AND + issuanceTime < CFDateGetAbsoluteTime(expiry)) { // at the time of issuance.) + once_or_current_qualified_embedded++; + trustedSCTCount++; + } else { + failed_once_check = true; + } + }); + + SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { + int _lifetime; + CFCalendarGetComponentDifference(zuluCalendar, + SecCertificateNotValidBefore(leafCert), + SecCertificateNotValidAfter(leafCert), + 0, "M", &_lifetime); + lifetime = _lifetime; + }); + + unsigned requiredEmbeddedSctsCount; + + if (lifetime < 15) { + requiredEmbeddedSctsCount = 2; + } else if (lifetime <= 27) { + requiredEmbeddedSctsCount = 3; + } else if (lifetime <= 39) { + requiredEmbeddedSctsCount = 4; + } else { + requiredEmbeddedSctsCount = 5; + } + + if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){ + SecCertificatePathVCSetIsCT(path, true); + } else { + /* Not enough "once or currently qualified" SCTs */ + if (failed_once_check) { + failureReason = TA_CTEmbeddedNotEnoughDisqualified; + } else if (unknown_log) { + failureReason = TA_CTEmbeddedNotEnoughUnknown; + } else { + failureReason = TA_CTEmbeddedNotEnough; + } + } + } else if (!at_least_one_currently_valid_embedded && !at_least_one_currently_valid_external) { + /* No currently valid SCTs */ + if (disqualified_log) { + failureReason = TA_CTNoCurrentSCTsDisqualifiedLog; + } else if (unknown_log) { + failureReason = TA_CTNoCurrentSCTsUnknownLog; + } + } else if (at_least_one_currently_valid_external) { + /* One presented current SCT but failed total current check */ + if (disqualified_log) { + failureReason = TA_CTPresentedNotEnoughDisqualified; + } else if (unknown_log) { + failureReason = TA_CTPresentedNotEnoughUnknown; + } else { + failureReason = TA_CTPresentedNotEnough; + } + } + + /* Record analytics data for CT */ + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); + require_quiet(analytics, out); + uint32_t sctCount = 0; + /* Count the total number of SCTs we found and report where we got them */ + if (embeddedScts && CFArrayGetCount(embeddedScts) > 0) { + analytics->sct_sources |= TA_SCTEmbedded; + sctCount += CFArrayGetCount(embeddedScts); + } + if (builderScts && CFArrayGetCount(builderScts) > 0) { + analytics->sct_sources |= TA_SCT_TLS; + sctCount += CFArrayGetCount(builderScts); + } + if (ocspScts && CFArrayGetCount(ocspScts) > 0) { + analytics->sct_sources |= TA_SCT_OCSP; + sctCount += CFArrayGetCount(ocspScts); + } + /* Report how many of those SCTs were once or currently qualified */ + analytics->number_trusted_scts = trustedSCTCount; + /* Report how many SCTs we got */ + analytics->number_scts = sctCount; + /* Why we failed */ + analytics->ct_failure_reason = failureReason; + /* Only one current SCT -- close to failure */ + if (CFDictionaryGetCount(currentLogsValidatingScts) == 1) { + analytics->ct_one_current = true; + } +out: + CFReleaseSafe(logsValidatingEmbeddedScts); + CFReleaseSafe(currentLogsValidatingScts); + CFReleaseSafe(builderScts); + CFReleaseSafe(embeddedScts); + CFReleaseSafe(ocspScts); + CFReleaseSafe(precertEntry); + CFReleaseSafe(trustedLogs); + CFReleaseSafe(x509Entry); +} + +static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + DERItem key_value; + key_value.data = (DERByte *)CFDataGetBytePtr(oid); + key_value.length = (DERSize)CFDataGetLength(oid); + + for (ix = 0; ix < count; ix++) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + policy_set_t policies = policies_for_cert(cert); + + if (policy_set_contains(policies, &key_value)) { + policy_set_free(policies); + return true; + } + policy_set_free(policies); + } + return false; +} + +static void SecPolicyCheckCertificatePolicy(SecPVCRef pvc, CFStringRef key) +{ + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + bool result = false; + + if (CFGetTypeID(value) == CFDataGetTypeID()) + { + result = checkPolicyOidData(pvc, value); + } else if (CFGetTypeID(value) == CFStringGetTypeID()) { + CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, value); + if (dataOid) { + result = checkPolicyOidData(pvc, dataOid); + CFRelease(dataOid); + } + } + if(!result) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + + +static void SecPolicyCheckRevocation(SecPVCRef pvc, + CFStringRef key) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + if (isString(value)) { + SecPathBuilderSetRevocationMethod(pvc->builder, value); + } +} + +static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc, + CFStringRef key) { + pvc->require_revocation_response = true; + secdebug("policy", "revocation response required"); +} + +static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) { + SecPathBuilderSetCheckRevocationOnline(pvc->builder); +} + +static void SecPolicyCheckRevocationIfTrusted(SecPVCRef pvc, CFStringRef key) { + SecPathBuilderSetCheckRevocationIfTrusted(pvc->builder); +} + +static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc, + CFStringRef key) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef value = CFDictionaryGetValue(policy->_options, key); + if (value == kCFBooleanTrue) { + SecPathBuilderSetCanAccessNetwork(pvc->builder, false); + } else { + SecPathBuilderSetCanAccessNetwork(pvc->builder, true); + } +} + +static void SecPolicyCheckWeakKeySize(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (cert && SecCertificateIsWeakKey(cert)) { + /* Intermediate certificate has a weak key. */ + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } +} + +static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFDictionaryRef keySizes = CFDictionaryGetValue(policy->_options, key); + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + + /* Don't check key size for user-anchored leafs */ +#if TARGET_OS_IPHONE + SecCertificateSourceRef userSource = kSecUserAnchorSource; +#else + SecCertificateSourceRef userSource = kSecLegacyAnchorSource; +#endif + if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) { + return; + } + + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecCertificateIsAtLeastMinKeySize(cert, keySizes)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } +} + +static void SecPolicyCheckWeakSignature(SecPVCRef pvc, CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key); + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecPolicyCheckCertWeakSignature(cert, pvcValue)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + } +} + +static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc); + + /* Ignore (a non-self-signed) anchor if it's trusted by the user */ +#if TARGET_OS_IPHONE + bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1)); +#else + bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1)); +#endif + if (SecPathBuilderIsAnchored(pvc->builder) && userAnchored) { + count--; + } + + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFSetRef disallowedHashAlgorithms = CFDictionaryGetValue(policy->_options, key); + while (ix < count) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + /* note that these checks skip self-signed certs */ + if (!SecPolicyCheckCertSignatureHashAlgorithms(cert, disallowedHashAlgorithms)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } + ix++; + } +} + +static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) { + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + require_quiet(leaf, out); + + /* And now a special snowflake from our tests */ + + /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */ + /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */ + /* Not After : May 26 09:37:50 2017 GMT */ + static const uint8_t vodafone[] = { + 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a, + 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18 + }; + + CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf); + require_quiet(leafFingerprint, out); + const unsigned int len = 20; + const uint8_t *dp = CFDataGetBytePtr(leafFingerprint); + if (dp && (!memcmp(vodafone, dp, len))) { + return true; + } + +out: + return false; +} + +static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key); + +static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + + Boolean keyInPolicy = false; + CFArrayRef policies = pvc->policies; + CFIndex policyIX, policyCount = CFArrayGetCount(policies); + for (policyIX = 0; policyIX < policyCount; ++policyIX) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + if (policy && CFDictionaryContainsKey(policy->_options, key)) { + keyInPolicy = true; + } + } + + /* We only enforce this check when *both* of the following are true: + * 1. One of the certs in the path has this usage constraint, and + * 2. One of the policies in the PVC has this key + * (As compared to normal policy options which require only one to be true..) */ + require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) && + keyInPolicy, out); + + /* Ignore the anchor if it's trusted */ + if (SecPathBuilderIsAnchored(pvc->builder)) { + count--; + } + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (SecCertificateIsWeakHash(cert)) { + if (!leaf_is_on_weak_hash_whitelist(pvc)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { + return; + } + } + } + } +out: + return; +} + +static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); + + Boolean keyInPolicy = false; + CFArrayRef policies = pvc->policies; + CFIndex policyIX, policyCount = CFArrayGetCount(policies); + for (policyIX = 0; policyIX < policyCount; ++policyIX) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + if (policy && CFDictionaryContainsKey(policy->_options, key)) { + keyInPolicy = true; + } + } + + /* We only enforce this check when *both* of the following are true: + * 1. One of the certs in the path has this usage constraint, and + * 2. One of the policies in the PVC has this key + * (As compared to normal policy options which require only one to be true..) */ + require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) && + keyInPolicy, out); + + /* Ignore the anchor if it's trusted */ + if (SecPathBuilderIsAnchored(pvc->builder)) { + count--; + } + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecCertificateIsStrongKey(cert)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { + return; + } + } + + } /* Cert loop */ +out: + return; +} + +static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) { + /* Pinning is disabled on the system, skip. */ + if (SecIsInternalRelease()) { + if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"), + CFSTR("com.apple.security"), NULL)) { + return; + } + } + + CFArrayRef policies = pvc->policies; + CFIndex policyIX, policyCount = CFArrayGetCount(policies); + for (policyIX = 0; policyIX < policyCount; ++policyIX) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + CFStringRef policyName = SecPolicyGetName(policy); + if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) { + /* policy required pinning, but we didn't use a pinning policy */ + if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) { + return; + } + } + } +} + +static bool is_configured_test_system_root(SecCertificateRef root, CFStringRef preference) { + if (!SecIsInternalRelease()) { + return false; + } + bool result = false; + CFDataRef rootHash = SecCertificateCopySHA256Digest(root); + CFTypeRef value = CFPreferencesCopyAppValue(preference, CFSTR("com.apple.security")); + require_quiet(isData(value), out); + require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out); + result = true; + +out: + CFReleaseNull(value); + CFReleaseNull(rootHash); + return result; +} + +static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) { + if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) { + /* exact match */ + return true; + } else if (CFStringHasPrefix(exception, CFSTR("."))) { + /* subdomains */ + CFIndex elength = CFStringGetLength(exception); + CFIndex hlength = CFStringGetLength(hostname); + if (hlength > elength) { + CFRange compareRange = { hlength - elength, elength }; + if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) { + return true; + } + } else if (hlength + 1 == elength) { + CFRange compareRange = { 1, hlength }; + if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) { + return true; + } + } + } + return false; +} + +static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { + if (gnType != GNT_DirectoryName) { + return errSecInternal; + } + + DERDecodedInfo subtreeName_content; + if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) { + return errSecDecode; + } + + CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content); + if (subtree_orgs) { + CFReleaseNull(subtree_orgs); + return errSecSuccess; + } + return errSecInternal; +} + +static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) { + __block bool result = false; + CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey); + + /* exception for a leaf is always allowed */ + SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0); + CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf); + if (CFEqualSafe(exceptionHash, spkiHash)) { + result = true; + } + CFReleaseNull(spkiHash); + + if (result) { return result; } + + /* exceptions for CAs */ + for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) { + SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX); + + spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca); + if (!CFEqualSafe(exceptionHash, spkiHash)) { + CFReleaseNull(spkiHash); + continue; + } + CFReleaseNull(spkiHash); + + /* this CA matches but exceptions for CAs have constraints */ + if (SecCertificateGetPermittedSubtrees(ca)) { + /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */ + CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) { + CFDataRef subtree = (CFDataRef)value; + const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) }; + DERDecodedInfo general_name_content; + if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) { + OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, + &general_name_content.content, + NULL, + is_subtree_dn_with_org); + if (status == errSecSuccess) { + result = true; + } + } + }); + } + + if (!result) { + /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */ + CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf); + CFArrayRef caOrgs = SecCertificateCopyOrganization(ca); + if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) { + result = true; + } + CFReleaseNull(leafOrgs); + CFReleaseNull(caOrgs); + } + + if (result) { + break; + } + } + + return result; +} + +static bool is_ct_excepted(SecPVCRef pvc) { + CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL); + if (!ct_exceptions) { + return false; + } + + __block bool result = false; + CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey); + if (domainExceptions) { + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); + if (hostname) { + CFArrayForEach(domainExceptions, ^(const void *value) { + result = result || is_ct_excepted_domain(hostname, value); + }); + } + } + if (result) { + secinfo("policy", "domain-based CT exception applied"); + CFReleaseNull(ct_exceptions); + return result; + } + + CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey); + if (keyExceptions) { + __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayForEach(keyExceptions, ^(const void *value) { + result = result || has_ct_excepted_key(path, value); + }); + } + + if (result) { + secinfo("policy" , "key-based CT exceptions applied"); + } + + CFReleaseNull(ct_exceptions); + return result; +} + +/* some Apple servers not getting certs with embedded SCTs */ +static bool is_ct_allowlisted_cert(SecCertificateRef leaf) { + if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlist"), CFSTR("com.apple.security"), NULL) || + CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistApple"), CFSTR("com.apple.security"), NULL)) { + return false; + } + + /* subject:/CN=basejumper.apple.com/OU=management:idms.group.110621/O=Apple Inc./ST=California/C=US */ + /* issuer :/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */ + static const uint8_t basejumper_hash[] = { + 0x23, 0x32, 0x0b, 0x5a, 0x24, 0xd8, 0x4d, 0x27, 0x8c, 0x43, 0xc9, 0xed, 0x22, 0xed, 0x87, 0xb7, + 0xc5, 0x51, 0x43, 0x55, 0xa9, 0x84, 0x79, 0x5a, 0x77, 0xb9, 0xad, 0x0f, 0x88, 0x14, 0x61, 0xac, + }; + + bool result = false; + CFDataRef leaf_fingerprint = SecCertificateCopySHA256Digest(leaf); + const uint8_t *dp = CFDataGetBytePtr(leaf_fingerprint); + if (dp && !memcmp(basejumper_hash, dp, CC_SHA256_DIGEST_LENGTH)) { + result = true; + } + CFReleaseNull(leaf_fingerprint); + return result; +} + +static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) { + SecCertificateSourceRef appleAnchorSource = NULL; + SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); + + /* Skip this check if we haven't done the CT checks yet */ + require_quiet(SecCertificatePathVCIsPathValidated(path), out); + + /* We only enforce this check when all of the following are true: + * 0. Kill Switch not enabled */ + require_quiet(!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT), out); + + /* 1. Not a pinning policy */ + SecPolicyRef policy = SecPVCGetPolicy(pvc); + require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out); + + /* 2. Device has checked in to MobileAsset for a current log list within the last 60 days. + * Or the caller passed in the trusted log list. */ + require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out); + + /* 3. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC and not expired. */ + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0 && + SecCertificateIsValid(leaf, SecPVCGetVerifyTime(pvc)), out); + + /* 4. Chain is anchored with root in the system anchor source but not the Apple anchor source + * with certain excepted CAs and configurable included CAs. */ + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); + appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false)); + require_quiet(SecPathBuilderIsAnchored(pvc->builder), out); + require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) && + appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) && + !is_ct_allowlisted_cert(leaf)) || + is_configured_test_system_root(root, CFSTR("TestCTRequiredSystemRoot")), out); + + if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) { + /* Set failure. By not using the Forced variant, we implicitly check that this + * policy had this options set. */ + SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse); + } + +out: + CFReleaseNull(trustedLogs); + CFReleaseNull(otaref); + if (appleAnchorSource) { + SecMemoryCertificateSourceDestroy(appleAnchorSource); + } +} + +static bool SecPolicyCheckSystemTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) { + CFAbsoluteTime jul2016 = 489024000.0; // 1 July 2016 00:00:00 UTC + CFAbsoluteTime mar2018 = 541555200.0; // 1 March 2018 00:00:00 UTC + if (notBefore < jul2016) { + /* Validity Period no greater than 60 months. + 60 months is no more than 5 years and 2 leap days (and 1 hour slip). */ + CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2) + 3600; + if (notAfter - notBefore > maxPeriod) { + secnotice("policy", "System-trusted leaf validity period is more than 60 months"); + return false; + } + } else if (notBefore < mar2018) { + /* Validity Period no greater than 39 months. + 39 months is no more than 3 years, 2 31-day months, + 1 30-day month, and 1 leap day (and 1 hour slip) */ + CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1) + 3600; + if (notAfter - notBefore > maxPeriod) { + secnotice("policy", "System-trusted leaf validity period longer than 39 months and issued after 30 June 2016"); + return false; + } + } else { + /* Validity Period no greater than 825 days (and 1 hour slip). */ + CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600; + if (notAfter - notBefore > maxPeriod) { + secnotice("policy", "System-trusted leaf validity period longer than 825 days and issued on or after 1 March 2018"); + return false; + } + } + return true; +} + +static bool SecPolicyCheckOtherTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) { + /* Check whether we will enforce the validity period maximum for a non-system trusted leaf. */ + if (SecIsInternalRelease()) { + if (CFPreferencesGetAppBooleanValue(CFSTR("IgnoreMaximumValidityPeriod"), + CFSTR("com.apple.security"), NULL)) { + return true; + } + } + CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC + if (notBefore > jul2019) { + /* Validity Period no greater than 825 days (and 1 hour slip). */ + CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600; + if (notAfter - notBefore > maxPeriod) { + secnotice("policy", "Non-system-trusted leaf validity period longer than 825 days and issued on or after 1 July 2019"); + return false; + } + } + return true; +} + +static void SecPolicyCheckValidityPeriodMaximums(SecPVCRef pvc, CFStringRef key) { + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + CFAbsoluteTime notAfter = SecCertificateNotValidAfter(leaf); + CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf); + + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); + if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) { + if (!SecPolicyCheckSystemTrustValidityPeriodMaximums(notBefore, notAfter)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + return; + } + + /* Don't check validity periods against maximums for user-anchored leafs */ +#if TARGET_OS_IPHONE + SecCertificateSourceRef userSource = kSecUserAnchorSource; +#else + SecCertificateSourceRef userSource = kSecLegacyAnchorSource; +#endif + if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) { + return; + } + + /* all other trust */ + if (!SecPolicyCheckOtherTrustValidityPeriodMaximums(notBefore, notAfter)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } +} + +static void SecPolicyCheckServerAuthEKU(SecPVCRef pvc, CFStringRef key) { + /* The ExtendedKeyUsage check will verify a looser version of this check for all TLS server certs. + * Here we want to be stricter (enforcing that there is an EKU extension and that it contains the + * one true Server Auth EKU OID) for system and app anchors */ + SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); + CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1); + if (SecCertificateSourceContains(kSecSystemAnchorSource, root) || is_configured_test_system_root(root, CFSTR("TestSystemRoot"))) { + /* all system-anchored chains must be compliant */ + if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + return; + } + + /* skip user/admin-anchored chains */ +#if TARGET_OS_IPHONE + SecCertificateSourceRef userSource = kSecUserAnchorSource; +#else + SecCertificateSourceRef userSource = kSecLegacyAnchorSource; +#endif + if (SecPVCIsAnchorPerConstraints(pvc, userSource, root)) { + return; + } + + /* All other anchor types must be compliant if issued on or after 1 July 2019 */ + CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf); + CFAbsoluteTime jul2019 = 583628400.0; // 1 July 2019 00:00:00 UTC + if (notBefore > jul2019) { + if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + } +} + +void SecPolicyServerInitialize(void) { + gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, NULL); + gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, NULL); + +#undef POLICYCHECKMACRO +#define __PC_ADD_CHECK_(NAME) +#define __PC_ADD_CHECK_L(NAME) CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME); +#define __PC_ADD_CHECK_A(NAME) CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheck##NAME, SecPolicyCheck##NAME); + +#define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ +__PC_ADD_CHECK_##LEAFCHECK(NAME) \ +__PC_ADD_CHECK_##PATHCHECK(NAME) +#include "OSX/sec/Security/SecPolicyChecks.list" + + /* Some of these don't follow the naming conventions but are in the Pinning DB. + * fix policy check constant values */ + CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkerOid"), SecPolicyCheckLeafMarkerOid); + CFDictionaryAddValue(gSecPolicyLeafCallbacks, CFSTR("CheckLeafMarkersProdAndQA"), SecPolicyCheckLeafMarkersProdAndQA); + CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateMarkerOid"), SecPolicyCheckIntermediateMarkerOid); + CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateCountry"), SecPolicyCheckIntermediateCountry); + CFDictionaryAddValue(gSecPolicyPathCallbacks, CFSTR("CheckIntermediateOrganization"), SecPolicyCheckIntermediateOrganization); +} + +// MARK: - +// MARK: SecPVCRef +/******************************************************** + ****************** SecPVCRef Functions ***************** + ********************************************************/ + +void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) { + secdebug("alloc", "pvc %p", pvc); + // Weird logging policies crashes. + //secdebug("policy", "%@", policies); + + // Zero the pvc struct so only non-zero fields need to be explicitly set + memset(pvc, 0, sizeof(struct OpaqueSecPVC)); + pvc->builder = builder; + pvc->policies = policies; + if (policies) + CFRetain(policies); + pvc->result = kSecTrustResultUnspecified; + + CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail, + 1, &kCFTypeArrayCallBacks); + CFRelease(certDetail); +} + +void SecPVCDelete(SecPVCRef pvc) { + secdebug("alloc", "delete pvc %p", pvc); + CFReleaseNull(pvc->policies); + CFReleaseNull(pvc->details); + CFReleaseNull(pvc->leafDetails); +} + +void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) { + secdebug("policy", "%@", path); + pvc->policyIX = 0; + pvc->result = kSecTrustResultUnspecified; + CFReleaseNull(pvc->details); +} + +void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) { + pvc->policyIX = 0; + + /* Since we don't run the LeafChecks again, we need to preserve the + * result the leaf had. */ + CFIndex ix, pathLength = SecCertificatePathVCGetCount(path); + CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault, + pathLength, pvc->leafDetails); + for (ix = 1; ix < pathLength; ++ix) { + CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFArrayAppendValue(details, certDetail); + CFRelease(certDetail); + } + CFRetainAssign(pvc->details, details); + pvc->result = pvc->leafResult; + CFReleaseSafe(details); +} + +SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) { + return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX); +} + +static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { + return SecPathBuilderGetCertificateCount(pvc->builder); +} + +static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { + return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); +} + +static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { + return SecPathBuilderGetVerifyTime(pvc->builder); +} + +static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) { + CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder); + if (!exceptions) { return false; } + CFIndex exceptionsCount = CFArrayGetCount(exceptions); + + /* There are two types of exceptions: + * 1. Those that are built from SecTrustCopyExceptions, which are particular to the + * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary. + * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors. + */ +#if TARGET_OS_OSX + CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0); + /* Type 2 */ + if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) { + /* SHA1Digest not allowed */ + if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; } + /* Key excepted */ + if (CFDictionaryContainsKey(options, key)) { + /* Special case -- AnchorTrusted only for self-signed certs */ + if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) { + Boolean isSelfSigned = false; + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); + if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) { + return false; + } + } + return true; + } else if (CFEqual(key, kSecPolicyCheckTemporalValidity) && CFDictionaryContainsKey(options, kSecPolicyCheckValidRoot)) { + /* Another special case - ValidRoot excepts Valid only for self-signed certs */ + Boolean isSelfSigned = false; + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); + if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) { + return false; + } + return true; + } + } +#endif + + /* Type 1 */ + if (ix >= exceptionsCount) { return false; } + CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix); + + /* Compare the cert hash */ + if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; } + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); + if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) { + return false; + } + + /* Key Excepted */ + CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key); + if (exceptionValue && CFEqual(value, exceptionValue)) { + /* Only change result if PVC is already ok */ + if (SecPVCIsOkResult(pvc)) { + // Chains that pass due to exceptions get Proceed result. + pvc->result = kSecTrustResultProceed; + } + return true; + } + + return false; +} + +static int32_t detailKeyToCssmErr(CFStringRef key) { + int32_t result = 0; + + if (CFEqual(key, kSecPolicyCheckSSLHostname)) { + result = -2147408896; // CSSMERR_APPLETP_HOSTNAME_MISMATCH + } + else if (CFEqual(key, kSecPolicyCheckEmail)) { + result = -2147408872; // CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND + } + else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) { + result = -2147409654; // CSSMERR_TP_CERT_EXPIRED + } + + return result; +} + +static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint); + +static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) { + bool result = false; + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); + + for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { + CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); + CFNumberRef allowedErrorNumber = NULL; + if (!isDictionary(constraint)) { + continue; + } + allowedErrorNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsAllowedError); + int32_t allowedErrorValue = 0; + if (!isNumber(allowedErrorNumber) || !CFNumberGetValue(allowedErrorNumber, kCFNumberSInt32Type, &allowedErrorValue)) { + continue; + } + + if (SecPVCMeetsConstraint(pvc, cert, constraint)) { + if (allowedErrorValue == detailKeyToCssmErr(key)) { + result = true; + break; + } + } + } + return result; +} + +static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) { + CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); + for (certIX = 0; certIX < certCount; certIX++) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); + CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); + for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { + CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); + if (!isDictionary(constraint)) { + continue; + } + + CFDictionaryRef policyOptions = NULL; + policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions); + if (policyOptions && isDictionary(policyOptions) && + CFDictionaryContainsKey(policyOptions, key)) { + return true; + } + } + } + return false; +} + +static SecTrustResultType trust_result_for_key(CFStringRef key) { + SecTrustResultType result = kSecTrustResultRecoverableTrustFailure; +#undef POLICYCHECKMACRO +#define __PC_TYPE_MEMBER_ false +#define __PC_TYPE_MEMBER_R false +#define __PC_TYPE_MEMBER_F true +#define __PC_TYPE_MEMBER_D true + +#define __TRUSTRESULT_ kSecTrustResultRecoverableTrustFailure +#define __TRUSTRESULT_F kSecTrustResultFatalTrustFailure +#define __TRUSTRESULT_D kSecTrustResultDeny +#define __TRUSTRESULT_R kSecTrustResultRecoverableTrustFailure + +#define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ +if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \ + result = __TRUSTRESULT_##TRUSTRESULT; \ +} +#include "OSX/sec/Security/SecPolicyChecks.list" + return result; +} + + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +bool SecPVCSetResultForced(SecPVCRef pvc, + CFStringRef key, CFIndex ix, CFTypeRef result, bool force) { + + /* If this is not something the current policy cares about ignore + this error and return true so our caller continues evaluation. */ + if (!force) { + /* Either the policy or the usage constraints have to have this key */ + SecPolicyRef policy = SecPVCGetPolicy(pvc); + if (!(SecPVCKeyIsConstraintPolicyOption(pvc, key) || + (policy && CFDictionaryContainsKey(policy->_options, key)))) { + return true; + } + } + + /* Check to see if the SecTrustSettings for the certificate in question + tell us to ignore this error. */ + if (SecPVCIsAllowedError(pvc, ix, key)) { + secinfo("policy", "cert[%d]: skipped allowed error %@", (int) ix, key); + return true; + } + + /* Check to see if exceptions tells us to ignore this error. */ + if (SecPVCIsExceptedError(pvc, ix, key, result)) { + secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key); + return true; + } + + secnotice("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key, + (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf" + : (pvc->callbacks == gSecPolicyPathCallbacks ? "path" + : "custom")), + (force ? "force" : ""), result); + + /* Avoid resetting deny or fatal to recoverable */ + SecTrustResultType trustResult = trust_result_for_key(key); + if (SecPVCIsOkResult(pvc) || trustResult == kSecTrustResultFatalTrustFailure) { + pvc->result = trustResult; + } else if (trustResult == kSecTrustResultDeny && + pvc->result == kSecTrustResultRecoverableTrustFailure) { + pvc->result = trustResult; + } + + if (!pvc->details) + return false; + + CFMutableDictionaryRef detail = + (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix); + if (!detail) { + secerror("SecPVCSetResultForced: failed to get detail at index %ld (array length %ld)", + ix, CFArrayGetCount(pvc->details)); + return false; + } + + /* Perhaps detail should have an array of results per key? As it stands + in the case of multiple policy failures the last failure stands. */ + CFDictionarySetValue(detail, key, result); + + return true; +} + +bool SecPVCSetResult(SecPVCRef pvc, + CFStringRef key, CFIndex ix, CFTypeRef result) { + return SecPVCSetResultForced(pvc, key, ix, result, false); +} + +/* AUDIT[securityd](done): + key(ok) is a caller provided. + value(ok, unused) is a caller provided. + */ +static void SecPVCValidateKey(const void *key, const void *value, + void *context) { + SecPVCRef pvc = (SecPVCRef)context; + + /* If our caller doesn't want full details and we failed earlier there is + no point in doing additional checks. */ + if (!SecPVCIsOkResult(pvc) && !pvc->details) + return; + + SecPolicyCheckFunction fcn = (SecPolicyCheckFunction) + CFDictionaryGetValue(pvc->callbacks, key); + + if (!fcn) { + /* "Optional" policy checks. This may be a new key from the + * pinning DB which is not implemented in this OS version. Log a + * warning, and on debug builds fail evaluation, to encourage us + * to ensure that checks are synchronized across the same build. */ + if (pvc->callbacks == gSecPolicyLeafCallbacks) { + if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) { + secwarning("policy: unknown policy key %@, skipping", key); +#if DEBUG + pvc->result = kSecTrustResultOtherError; +#endif + } + } else if (pvc->callbacks == gSecPolicyPathCallbacks) { + if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) { + secwarning("policy: unknown policy key %@, skipping", key); +#if DEBUG + pvc->result = kSecTrustResultOtherError; +#endif + } + } else { + /* Non standard validation phase, nothing is optional. */ + pvc->result = kSecTrustResultOtherError; + } + return; + } + + fcn(pvc, (CFStringRef)key); +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) { + /* We need to compute details for the leaf. */ + CFRetainAssign(pvc->details, pvc->leafDetails); + + CFArrayRef policies = pvc->policies; + CFIndex ix, count = CFArrayGetCount(policies); + for (ix = 0; ix < count; ++ix) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix); + pvc->policyIX = ix; + /* Validate all keys for all policies. */ + pvc->callbacks = gSecPolicyLeafCallbacks; + CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); + } + + pvc->leafResult = pvc->result; + CFRetainAssign(pvc->leafDetails, pvc->details); + + return pvc->result; +} + +bool SecPVCIsOkResult(SecPVCRef pvc) { + if (pvc->result == kSecTrustResultRecoverableTrustFailure || + pvc->result == kSecTrustResultDeny || + pvc->result == kSecTrustResultFatalTrustFailure || + pvc->result == kSecTrustResultOtherError) { + return false; + } + return true; +} + +bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) { + /* Check stuff common to intermediate and anchors. */ + CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1; + bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder)); + + if (!SecCertificateIsValid(cert, verifyTime)) { + /* Certificate has expired. */ + if (!SecPVCSetResult(pvc, kSecPolicyCheckTemporalValidity, ix, kCFBooleanFalse)) { + goto errOut; + } + } + + if (SecCertificateIsWeakKey(cert)) { + /* Certificate uses weak key. */ + if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakKeySize, ix, kCFBooleanFalse)) { + goto errOut; + } + } + + if (!SecPolicyCheckCertWeakSignature(cert, NULL)) { + /* Certificate uses weak hash. */ + if (!SecPVCSetResult(pvc, kSecPolicyCheckWeakSignature, ix, kCFBooleanFalse)) { + goto errOut; + } + } + + if (is_anchor) { + /* Perform anchor specific checks. */ + /* Don't think we have any of these. */ + } else { + /* Perform intermediate specific checks. */ + + /* (k) Basic constraints only relevant for v3 and later. */ + if (SecCertificateVersion(cert) >= 3) { + const SecCEBasicConstraints *bc = + SecCertificateGetBasicConstraints(cert); + if (!bc) { + /* Basic constraints not present, illegal. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } else if (!bc->isCA) { + /* Basic constraints not marked as isCA, illegal. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraintsCA, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + /* For a v1 or v2 certificate in an intermediate slot (not a leaf and + not an anchor), we additionally require that the certificate chain + does not end in a v3 or later anchor. [rdar://32204517] */ + else if (ix > 0 && ix < anchor_ix) { + SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix); + if (SecCertificateVersion(anchor) >= 3) { + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + /* (l) max_path_length is checked elsewhere. */ + + /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ + SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); + if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + +errOut: + return SecPVCIsOkResult(pvc); +} + +static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { + /* Check stuff common to intermediate and anchors. */ + + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL != otapkiRef) + { + CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); + CFRelease(otapkiRef); + if (NULL != blackListedKeys) + { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + CFIndex count = SecPVCGetCertificateCount(pvc); + bool is_last = (ix == count - 1); + bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); + if (!is_anchor) { + /* Check for blacklisted intermediate issuer keys. */ + CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); + if (dgst) { + /* Check dgst against blacklist. */ + if (CFSetContainsValue(blackListedKeys, dgst)) { + /* Check allow list for this blacklisted issuer key, + which is the authority key of the issued cert at ix-1. + */ + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + bool allowed = path && SecCertificatePathVCIsAllowlisted(path); + if (!allowed) { + SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, + ix, kCFBooleanFalse, true); + } + } + CFRelease(dgst); + } + } + CFRelease(blackListedKeys); + return SecPVCIsOkResult(pvc); + } + } + // Assume OK + return true; +} + +static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) +{ + /* Check stuff common to intermediate and anchors. */ + SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (NULL != otapkiRef) + { + CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef); + CFRelease(otapkiRef); + if (NULL != grayListKeys) + { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + CFIndex count = SecPVCGetCertificateCount(pvc); + bool is_last = (ix == count - 1); + bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); + if (!is_anchor) { + /* Check for gray listed intermediate issuer keys. */ + CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); + if (dgst) { + /* Check dgst against gray list. */ + if (CFSetContainsValue(grayListKeys, dgst)) { + /* Check allow list for this graylisted issuer key, + which is the authority key of the issued cert at ix-1. + */ + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + bool allowed = path && SecCertificatePathVCIsAllowlisted(path); + if (!allowed) { + SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey, + ix, kCFBooleanFalse, true); + } + } + CFRelease(dgst); + } + } + CFRelease(grayListKeys); + return SecPVCIsOkResult(pvc); + } + } + // Assume ok + return true; +} + +static bool SecPVCContainsPolicy(SecPVCRef pvc, CFStringRef searchOid, CFStringRef searchName, CFIndex *policyIX) { + if (!isString(searchName) && !isString(searchOid)) { + return false; + } + CFArrayRef policies = pvc->policies; + CFIndex ix, count = CFArrayGetCount(policies); + for (ix = 0; ix < count; ++ix) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix); + CFStringRef policyName = SecPolicyGetName(policy); + CFStringRef policyOid = SecPolicyGetOidString(policy); + /* Prefer a match of both name and OID */ + if (searchOid && searchName && policyOid && policyName) { + if (CFEqual(searchOid, policyOid) && + CFEqual(searchName, policyName)) { + if (policyIX) { *policyIX = ix; } + return true; + } + /* sslServer trust settings need to apply to evals using policyName pinning + * but make sure we don't use this for SSL Client trust settings or policies. */ + if (CFEqual(searchOid, policyOid) && + CFEqual(searchName, kSecPolicyNameSSLServer) && !CFEqual(policyName, kSecPolicyNameSSLClient)) { + if (policyIX) { *policyIX = ix; } + return true; + } + } + /* Next best is just OID. */ + if (!searchName && searchOid && policyOid) { + if (CFEqual(searchOid, policyOid)) { + if (policyIX) { *policyIX = ix; } + return true; + } + } + if (!searchOid && searchName && policyName) { + if (CFEqual(searchName, policyName)) { + if (policyIX) { *policyIX = ix; } + return true; + } + } + } + return false; +} + +static bool SecPVCContainsString(SecPVCRef pvc, CFIndex policyIX, CFStringRef stringValue) { + if (!isString(stringValue)) { + return false; + } + bool result = false; + + /* Previous versions of macOS null-terminated the string, so we need to strip it. */ + CFStringRef tmpStringValue = NULL; + if (CFStringGetCharacterAtIndex(stringValue, CFStringGetLength(stringValue) -1) == (UniChar)0x0000) { + tmpStringValue = CFStringCreateTruncatedCopy(stringValue, CFStringGetLength(stringValue) - 1); + } else { + tmpStringValue = CFStringCreateCopy(NULL, stringValue); + } + /* Some users have strings that only contain the null-termination, so we need to check that we + * still have a string. */ + require(tmpStringValue, out); + + if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX); + /* Have to look for all the possible locations of name string */ + CFStringRef policyString = NULL; + policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); + if (!policyString) { + policyString = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEmail); + } + if (policyString && (CFStringCompare(tmpStringValue, policyString, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) { + result = true; + goto out; + } + + CFArrayRef policyStrings = NULL; + policyStrings = CFDictionaryGetValue(policy->_options, kSecPolicyCheckEAPTrustedServerNames); + if (policyStrings && CFArrayContainsValue(policyStrings, + CFRangeMake(0, CFArrayGetCount(policyStrings)), + tmpStringValue)) { + result = true; + goto out; + } + } + +out: + CFReleaseNull(tmpStringValue); + return result; +} + + +static uint32_t ts_key_usage_for_kuNumber(CFNumberRef keyUsageNumber) { + uint32_t ourTSKeyUsage = 0; + uint32_t keyUsage = 0; + if (keyUsageNumber && + CFNumberGetValue(keyUsageNumber, kCFNumberSInt32Type, &keyUsage)) { + if (keyUsage & kSecKeyUsageDigitalSignature) { + ourTSKeyUsage |= kSecTrustSettingsKeyUseSignature; + } + if (keyUsage & kSecKeyUsageDataEncipherment) { + ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptData; + } + if (keyUsage & kSecKeyUsageKeyEncipherment) { + ourTSKeyUsage |= kSecTrustSettingsKeyUseEnDecryptKey; + } + if (keyUsage & kSecKeyUsageKeyAgreement) { + ourTSKeyUsage |= kSecTrustSettingsKeyUseKeyExchange; + } + if (keyUsage == kSecKeyUsageAll) { + ourTSKeyUsage = kSecTrustSettingsKeyUseAny; + } + } + return ourTSKeyUsage; +} + +static uint32_t ts_key_usage_for_policy(SecPolicyRef policy) { + uint32_t ourTSKeyUsage = 0; + CFTypeRef policyKeyUsageType = NULL; + + policyKeyUsageType = (CFTypeRef)CFDictionaryGetValue(policy->_options, kSecPolicyCheckKeyUsage); + if (isArray(policyKeyUsageType)) { + CFIndex ix, count = CFArrayGetCount(policyKeyUsageType); + for (ix = 0; ix < count; ix++) { + CFNumberRef policyKeyUsageNumber = NULL; + policyKeyUsageNumber = (CFNumberRef)CFArrayGetValueAtIndex(policyKeyUsageType, ix); + ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageNumber); + } + } else if (isNumber(policyKeyUsageType)) { + ourTSKeyUsage |= ts_key_usage_for_kuNumber(policyKeyUsageType); + } + + return ourTSKeyUsage; +} + +static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc, + SecCertificateRef certificate, CFIndex policyIX, CFNumberRef keyUsageNumber) { + int64_t keyUsageValue = 0; + uint32_t ourKeyUsage = 0; + + if (!isNumber(keyUsageNumber) || !CFNumberGetValue(keyUsageNumber, kCFNumberSInt64Type, &keyUsageValue)) { + return false; + } + + if (keyUsageValue == kSecTrustSettingsKeyUseAny) { + return true; + } + + /* We're using the key for revocation if we have the OCSPSigner policy. + * @@@ If we support CRLs, we'd need to check for that policy here too. + */ + if (SecPVCContainsPolicy(pvc, kSecPolicyAppleOCSPSigner, NULL, NULL)) { + ourKeyUsage |= kSecTrustSettingsKeyUseSignRevocation; + } + + /* We're using the key for verifying a cert if it's a root/intermediate + * in the chain. If the cert isn't in the path yet, we're about to add it, + * so it's a root/intermediate. If there is no path, this is the leaf. + */ + CFIndex pathIndex = -1; + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + if (path) { + pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate); + } else { + pathIndex = 0; + } + if (pathIndex != 0) { + ourKeyUsage |= kSecTrustSettingsKeyUseSignCert; + } + + /* The rest of the key usages may be specified by the policy(ies). */ + if (policyIX >= 0 && policyIX < CFArrayGetCount(pvc->policies)) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, policyIX); + ourKeyUsage |= ts_key_usage_for_policy(policy); + } else { + /* Get key usage from ALL policies */ + CFIndex ix, count = CFArrayGetCount(pvc->policies); + for (ix = 0; ix < count; ix++) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, ix); + ourKeyUsage |= ts_key_usage_for_policy(policy); + } + } + + if (ourKeyUsage == (uint32_t)(keyUsageValue & 0x00ffffffff)) { + return true; + } + + return false; +} + +#if TARGET_OS_OSX +#include +#include +#include +#include +#include + +extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); + +static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) { + bool result = false; + audit_token_t auditToken = {}; + SecTaskRef task = NULL; + SecRequirementRef requirement = NULL; + CFStringRef stringRequirement = NULL; + + require(appRef && clientAuditToken, out); + require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out); + require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out); + require(requirement, out); + require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out); + require(stringRequirement, out); + + require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); + CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); + require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); + + if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) { + result = true; + } + +out: + CFReleaseNull(task); + CFReleaseNull(requirement); + CFReleaseNull(stringRequirement); + return result; +} +#endif + +static bool SecPVCContainsTrustSettingsPolicyOption(SecPVCRef pvc, CFDictionaryRef options) { + if (!isDictionary(options)) { + return false; + } + + /* Push */ + CFDictionaryRef currentCallbacks = pvc->callbacks; + + /* We need to run the leaf and path checks using these options. */ + pvc->callbacks = gSecPolicyLeafCallbacks; + CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc); + + pvc->callbacks = gSecPolicyPathCallbacks; + CFDictionaryApplyFunction(options, SecPVCValidateKey, pvc); + + /* Pop */ + pvc->callbacks = currentCallbacks; + + /* Our work here is done; no need to claim a match */ + return false; +} + +static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, CFDictionaryRef constraint) { + CFStringRef policyOid = NULL, policyString = NULL, policyName = NULL; + CFNumberRef keyUsageNumber = NULL; + CFTypeRef trustedApplicationData = NULL; + CFDictionaryRef policyOptions = NULL; + + bool policyMatch = false, policyStringMatch = false, applicationMatch = false , + keyUsageMatch = false, policyOptionMatch = false; + bool result = false; + +#if TARGET_OS_OSX + /* OS X returns a SecPolicyRef in the constraints. Convert to the oid string. */ + SecPolicyRef policy = NULL; + policy = (SecPolicyRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy); + policyOid = (policy) ? policy->_oid : NULL; +#else + policyOid = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicy); +#endif + policyName = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyName); + policyString = (CFStringRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyString); + keyUsageNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsKeyUsage); + policyOptions = (CFDictionaryRef)CFDictionaryGetValue(constraint, kSecTrustSettingsPolicyOptions); + + CFIndex policyIX = -1; + policyMatch = SecPVCContainsPolicy(pvc, policyOid, policyName, &policyIX); + policyStringMatch = SecPVCContainsString(pvc, policyIX, policyString); + keyUsageMatch = SecPVCContainsTrustSettingsKeyUsage(pvc, certificate, policyIX, keyUsageNumber); + policyOptionMatch = SecPVCContainsTrustSettingsPolicyOption(pvc, policyOptions); + +#if TARGET_OS_OSX + trustedApplicationData = CFDictionaryGetValue(constraint, kSecTrustSettingsApplication); + CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder); + applicationMatch = SecPVCCallerIsApplication(clientAuditToken, trustedApplicationData); + CFReleaseNull(clientAuditToken); +#else + if(CFDictionaryContainsKey(constraint, kSecTrustSettingsApplication)) { + secerror("kSecTrustSettingsApplication is not yet supported on this platform"); + } +#endif + + /* If we either didn't find the parameter in the dictionary or we got a match + * against that parameter, for all possible parameters in the dictionary, then + * this trust setting result applies to the output. */ + if (((!policyOid && !policyName) || policyMatch) && + (!policyString || policyStringMatch) && + (!trustedApplicationData || applicationMatch) && + (!keyUsageNumber || keyUsageMatch) && + (!policyOptions || policyOptionMatch)) { + result = true; + } + + return result; +} + +static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints) { + SecTrustSettingsResult result = kSecTrustSettingsResultInvalid; + CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); + for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { + CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); + if (!isDictionary(constraint)) { + continue; + } + + CFNumberRef resultNumber = NULL; + resultNumber = (CFNumberRef)CFDictionaryGetValue(constraint, kSecTrustSettingsResult); + uint32_t resultValue = kSecTrustSettingsResultInvalid; + if (!isNumber(resultNumber) || !CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) { + /* no SecTrustSettingsResult entry defaults to TrustRoot*/ + resultValue = kSecTrustSettingsResultTrustRoot; + } + + if (SecPVCMeetsConstraint(pvc, certificate, constraint)) { + result = resultValue; + break; + } + } + return result; +} + +/* This function assumes that the input source is an anchor source */ +bool SecPVCIsAnchorPerConstraints(SecPVCRef pvc, SecCertificateSourceRef source, SecCertificateRef certificate) { + __block bool result = false; + CFArrayRef constraints = NULL; + constraints = SecCertificateSourceCopyUsageConstraints(source, certificate); + + /* Unrestricted certificates: + * -those that come from anchor sources with no constraints + * -self-signed certificates with empty contraints arrays + */ + Boolean selfSigned = false; + require(errSecSuccess == SecCertificateIsSelfSigned(certificate, &selfSigned), out); + if ((NULL == source->copyUsageConstraints) || + (constraints && (CFArrayGetCount(constraints) == 0) && selfSigned)) { + secinfo("trust", "unrestricted anchor%s", + (NULL == source->copyUsageConstraints) ? " source" : ""); + result = true; + goto out; + } + + /* Get the trust settings result for the PVC. Only one PVC need match to + * trigger the anchor behavior -- policy validation will handle whether the + * path is truly anchored for that PVC. */ + require_quiet(constraints, out); + SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid; + settingsResult = SecPVCGetTrustSettingsResult(pvc, + certificate, + constraints); + if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) || + (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) { + // For our purposes, this is an anchor. + secinfo("trust", "complex trust settings anchor"); + result = true; + } + + if (settingsResult == kSecTrustSettingsResultDeny) { + /* We consider denied certs "anchors" because the trust decision + is set regardless of building the chain further. The policy + validation will handle rejecting this chain. */ + secinfo("trust", "complex trust settings denied anchor"); + result = true; + } + +out: + CFReleaseNull(constraints); + return result; +} + +static void SecPVCCheckUsageConstraints(SecPVCRef pvc) { + CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); + for (certIX = 0; certIX < certCount; certIX++) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); + SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints); + + /* Set the pvc trust result based on the usage constraints and anchor source. */ + if (result == kSecTrustSettingsResultDeny) { + SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true); + } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot || + result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(pvc)) { + /* If we already think the PVC is ok and this cert is from one of the user/ + * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints), + * all mean we should use the special "Proceed" trust result. */ +#if TARGET_OS_IPHONE + if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) && + SecCertificateSourceContains(kSecUserAnchorSource, cert)) +#else + if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) && + SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) +#endif + { + pvc->result = kSecTrustResultProceed; + } + } + } +} + +static const UInt8 kTestDateConstraintsRoot[kSecPolicySHA256Size] = { + 0x51,0xA0,0xF3,0x1F,0xC0,0x1D,0xEC,0x87,0x32,0xB6,0xFD,0x13,0x6A,0x43,0x4D,0x6C, + 0x87,0xCD,0x62,0xE0,0x38,0xB4,0xFB,0xD6,0x40,0xB0,0xFD,0x62,0x4D,0x1F,0xCF,0x6D +}; +static const UInt8 kWS_CA1_G2[kSecPolicySHA256Size] = { + 0xD4,0x87,0xA5,0x6F,0x83,0xB0,0x74,0x82,0xE8,0x5E,0x96,0x33,0x94,0xC1,0xEC,0xC2, + 0xC9,0xE5,0x1D,0x09,0x03,0xEE,0x94,0x6B,0x02,0xC3,0x01,0x58,0x1E,0xD9,0x9E,0x16 +}; +static const UInt8 kWS_CA1_NEW[kSecPolicySHA256Size] = { + 0x4B,0x22,0xD5,0xA6,0xAE,0xC9,0x9F,0x3C,0xDB,0x79,0xAA,0x5E,0xC0,0x68,0x38,0x47, + 0x9C,0xD5,0xEC,0xBA,0x71,0x64,0xF7,0xF2,0x2D,0xC1,0xD6,0x5F,0x63,0xD8,0x57,0x08 +}; +static const UInt8 kWS_CA2_NEW[kSecPolicySHA256Size] = { + 0xD6,0xF0,0x34,0xBD,0x94,0xAA,0x23,0x3F,0x02,0x97,0xEC,0xA4,0x24,0x5B,0x28,0x39, + 0x73,0xE4,0x47,0xAA,0x59,0x0F,0x31,0x0C,0x77,0xF4,0x8F,0xDF,0x83,0x11,0x22,0x54 +}; +static const UInt8 kWS_ECC[kSecPolicySHA256Size] = { + 0x8B,0x45,0xDA,0x1C,0x06,0xF7,0x91,0xEB,0x0C,0xAB,0xF2,0x6B,0xE5,0x88,0xF5,0xFB, + 0x23,0x16,0x5C,0x2E,0x61,0x4B,0xF8,0x85,0x56,0x2D,0x0D,0xCE,0x50,0xB2,0x9B,0x02 +}; +static const UInt8 kSC_SFSCA[kSecPolicySHA256Size] = { + 0xC7,0x66,0xA9,0xBE,0xF2,0xD4,0x07,0x1C,0x86,0x3A,0x31,0xAA,0x49,0x20,0xE8,0x13, + 0xB2,0xD1,0x98,0x60,0x8C,0xB7,0xB7,0xCF,0xE2,0x11,0x43,0xB8,0x36,0xDF,0x09,0xEA +}; +static const UInt8 kSC_SHA2[kSecPolicySHA256Size] = { + 0xE1,0x78,0x90,0xEE,0x09,0xA3,0xFB,0xF4,0xF4,0x8B,0x9C,0x41,0x4A,0x17,0xD6,0x37, + 0xB7,0xA5,0x06,0x47,0xE9,0xBC,0x75,0x23,0x22,0x72,0x7F,0xCC,0x17,0x42,0xA9,0x11 +}; +static const UInt8 kSC_G2[kSecPolicySHA256Size] = { + 0xC7,0xBA,0x65,0x67,0xDE,0x93,0xA7,0x98,0xAE,0x1F,0xAA,0x79,0x1E,0x71,0x2D,0x37, + 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95 +}; + +static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { + static CFSetRef sConstrainedRoots = NULL; + static dispatch_once_t _t; + dispatch_once(&_t, ^{ + const UInt8 *v_hashes[] = { + kWS_CA1_G2, kWS_CA1_NEW, kWS_CA2_NEW, kWS_ECC, + kSC_SFSCA, kSC_SHA2, kSC_G2, kTestDateConstraintsRoot + }; + CFMutableSetRef set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + CFIndex ix, count = sizeof(v_hashes)/sizeof(*v_hashes); + for (ix=0; ix= 0 && !shouldDeny; certIX--) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); + CFDataRef sha256 = SecCertificateCopySHA256Digest(cert); + if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) { + /* matched a constrained root; check notBefore dates on all its children. */ + CFIndex childIX = certIX; + while (--childIX >= 0) { + SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX); + /* 1 Dec 2016 00:00:00 GMT */ + if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) { + SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true); + shouldDeny = true; + break; + } + } + } + CFReleaseNull(sha256); + } +} + +static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) { + if (!pvc || !pvc->policies) { + return false; + } + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); + if (!policy) { + return false; + } + CFStringRef policyName = SecPolicyGetName(policy); + if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) { + return true; + } + CFDictionaryRef options = policy->_options; + if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) { + return true; + } + return false; +} + +/* ASSUMPTIONS: + 1. SecPVCCheckRequireCTConstraints must be called after SecPolicyCheckCT, + so earliest issuance time has already been obtained from SCTs. + 2. If the issuance time value is 0 (i.e. 2001-01-01) or earlier, we + assume it was not set, and thus we did not have CT info. +*/ +static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) { + SecCertificatePathVCRef path = (pvc) ? SecPathBuilderGetPath(pvc->builder) : NULL; + if (!path) { + return; + } + /* If we are evaluating for a SSL server authentication policy, make sure + SCT issuance time is prior to the earliest not-after date constraint. + Note that CT will already be required if there is a not-after date + constraint present (set in SecRVCProcessValidDateConstraints). + */ + if (SecPVCIsSSLServerAuthenticationPolicy(pvc)) { + CFIndex ix, certCount = SecCertificatePathVCGetCount(path); + SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0); + CFAbsoluteTime earliestNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ + CFAbsoluteTime issuanceTime = SecCertificatePathVCIssuanceTime(path); + if (issuanceTime <= 0) { + /* if not set (or prior to 2001-01-01), use leaf's not-before time. */ + issuanceTime = SecCertificateNotValidBefore(certificate); + } + for (ix = 0; ix < certCount; ix++) { + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix); + if (!rvc || !rvc->valid_info || !rvc->valid_info->hasDateConstraints || !rvc->valid_info->notAfterDate) { + continue; + } + /* Found CA certificate with a not-after date constraint. */ + CFAbsoluteTime caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate); + if (caNotAfter < earliestNotAfter) { + earliestNotAfter = caNotAfter; + } + if (issuanceTime > earliestNotAfter) { + /* Issuance time violates the not-after date constraint. */ + secnotice("rvc", "certificate issuance time (%f) is later than allowed value (%f)", + issuanceTime, earliestNotAfter); + SecRVCSetValidDeterminedErrorResult(rvc); + break; + } + } + } + /* If path is CT validated, nothing further to do here. */ + if (SecCertificatePathVCIsCT(path)) { + return; + } + + /* Path is not CT validated, so check if CT was required. */ + SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path); + if (ctp <= kSecPathCTNotRequired || !SecPVCIsSSLServerAuthenticationPolicy(pvc)) { + return; + } + + /* We need to have a recent log list or the CT check may have failed due to the list being out of date. + * Also, honor the CT kill switch. */ + SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); + if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) && + SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable)) { + /* CT was required. Error is always set on leaf certificate. */ + SecPVCSetResultForced(pvc, kSecPolicyCheckCTRequired, + 0, kCFBooleanFalse, true); + if (ctp != kSecPathCTRequiredOverridable) { + /* Normally kSecPolicyCheckCTRequired is recoverable, + so need to manually change trust result here. */ + pvc->result = kSecTrustResultFatalTrustFailure; + } + } + CFReleaseNull(otaref); +} + +/* "Deep" copy the details array */ +static CFArrayRef CF_RETURNS_RETAINED SecPVCCopyDetailsArray(SecPVCRef pvc) { + CFArrayRef details = pvc->details; + CFMutableArrayRef copiedDetails = CFArrayCreateMutable(NULL, CFArrayGetCount(details), &kCFTypeArrayCallBacks); + CFArrayForEach(details, ^(const void *value) { + CFMutableDictionaryRef copiedValue = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value); + CFArrayAppendValue(copiedDetails, copiedValue); + CFReleaseNull(copiedValue); + }); + return copiedDetails; +} + +/* AUDIT[securityd](done): + policy->_options is a caller provided dictionary, only its cf type has + been checked. + */ +void SecPVCPathChecks(SecPVCRef pvc) { + secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder)); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + /* This needs to be initialized before we call any function that might call + SecPVCSetResultForced(). */ + pvc->policyIX = 0; + SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage); + if (SecPVCIsOkResult(pvc) || pvc->details) { + SecPolicyCheckBasicCertificateProcessing(pvc, + kSecPolicyCheckBasicCertificateProcessing); + } + + CFArrayRef policies = pvc->policies; + CFIndex count = CFArrayGetCount(policies); + for (; pvc->policyIX < count; ++pvc->policyIX) { + /* Validate all keys for all policies. */ + pvc->callbacks = gSecPolicyPathCallbacks; + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); + if (!SecPVCIsOkResult(pvc) && !pvc->details) + return; + } + + // Reset + pvc->policyIX = 0; + + /* Check whether the TrustSettings say to deny a cert in the path. */ + SecPVCCheckUsageConstraints(pvc); + + /* Check for Blocklisted certs */ + SecPVCCheckIssuerDateConstraints(pvc); + CFIndex ix; + count = SecCertificatePathVCGetCount(path); + for (ix = 1; ix < count; ix++) { + SecPVCGrayListedKeyChecks(pvc, ix); + SecPVCBlackListedKeyChecks(pvc, ix); + } + + /* Path-based check tests. */ + if (!SecCertificatePathVCIsPathValidated(path)) { + bool ev_check_ok = false; + if (SecCertificatePathVCIsOptionallyEV(path)) { + SecTrustResultType pre_ev_check_result = pvc->result; + CFArrayRef pre_ev_check_details = pvc->details ? SecPVCCopyDetailsArray(pvc) : NULL; + SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation); + ev_check_ok = SecPVCIsOkResult(pvc); + /* If ev checking failed, we still want to accept this chain + as a non EV one, if it was valid as such. */ + pvc->result = pre_ev_check_result; + CFAssignRetained(pvc->details, pre_ev_check_details); + } + + /* Check for CT */ + /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */ + SecPolicyCheckCT(pvc); + + /* Certs are only EV if they are also CT verified (when the Kill Switch isn't enabled and against a recent log list) */ + SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); + if (ev_check_ok && (SecCertificatePathVCIsCT(path) || SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) || + !SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable))) { + SecCertificatePathVCSetIsEV(path, true); + } + CFReleaseNull(otaref); + } + + /* Say that we did the expensive path checks (that we want to skip on the second call) */ + SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder)); + + /* Check that this path meets CT constraints. */ + SecPVCCheckRequireCTConstraints(pvc); + SecPolicyCheckSystemTrustedCTRequired(pvc); + + /* Check that this path meets known-intermediate constraints. */ + SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder); + + secdebug("policy", "end %strusted path: %@", + (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder)); + + return; +} + +void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc) { +#if TARGET_OS_WATCH + /* Since we don't currently allow networking on watchOS, + * don't enforce the revocation-required check here. (32728029) */ + bool required = false; +#else + bool required = true; +#endif + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFIndex ix, certCount = SecCertificatePathVCGetCount(path); + for (ix = 0; ix < certCount; ix++) { + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix); + /* Do we have a valid revocation response? */ + if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) { + /* No valid revocation response. + * Do we require revocation (for that cert per the + * SecCertificateVCRef, or per the pvc)? */ + if (required && (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) || + ((ix == 0) && pvc->require_revocation_response))) { + SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired, + ix, kCFBooleanFalse, true); + } + /* Do we have a definitive Valid revocation result for this cert? */ + if (SecRVCHasDefinitiveValidInfo(rvc) && SecRVCHasRevokedValidInfo(rvc)) { + SecRVCSetValidDeterminedErrorResult(rvc); + } + } + } +} diff --git a/trust/trustd/SecPolicyServer.h b/trust/trustd/SecPolicyServer.h new file mode 100644 index 00000000..fbeebb82 --- /dev/null +++ b/trust/trustd/SecPolicyServer.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008-2010,2012-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecPolicyServer + The functions provided in SecPolicyServer.h provide an interface to + trust policies dealing with certificate revocation. +*/ + +#ifndef _SECURITY_SECPOLICYSERVER_H_ +#define _SECURITY_SECPOLICYSERVER_H_ + +#include +#include "Security/SecPolicyInternal.h" +#include + +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecCertificateServer.h" + +__BEGIN_DECLS + +#define kSecPolicySHA256Size 32 + +void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies); +void SecPVCDelete(SecPVCRef pvc); +void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path); +SecPolicyRef SecPVCGetPolicy(SecPVCRef pv); + +/* Set the string result as the reason for the sub policy check key + failing. The policy check function should continue processing if + this function returns true. */ +bool SecPVCSetResult(SecPVCRef pv, CFStringRef key, CFIndex ix, + CFTypeRef result); +bool SecPVCSetResultForced(SecPVCRef pvc, + CFStringRef key, CFIndex ix, CFTypeRef result, bool force); +bool SecPVCIsOkResult(SecPVCRef pvc); + +/* Is the current result considered successful. */ +bool SecPVCIsOkResult(SecPVCRef pvc); + +/* Compute details */ +void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path); + +/* Run static leaf checks on the path in pvc. */ +SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc); + +/* Run static parent checks on the path in pvc. */ +bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix); + +/* Run dynamic checks on the complete path in pvc. Return true if the + operation is complete, returns false if an async backgroup request was + scheduled. Upon completion of the async background job + SecPathBuilderStep() should be called. */ +void SecPVCPathChecks(SecPVCRef pvc); + +/* Check whether revocation responses were received for certificates + * in the path in pvc. If a valid response was not obtained for a + * certificate, this sets the appropriate error result if revocation + * was required, and/or definitive revocation info is present. */ +void SecPVCPathCheckRevocationResponsesReceived(SecPVCRef pvc); + +typedef void (*SecPolicyCheckFunction)(SecPVCRef pv, CFStringRef key); + +/* + * Used by SecTrust to verify if a particular certificate chain matches + * this policy. Returns true if the policy accepts the certificate chain. +*/ +bool SecPolicyValidate(SecPolicyRef policy, SecPVCRef pvc, CFStringRef key); + +void SecPolicyServerInitialize(void); + +bool SecPolicyIsEVPolicy(const DERItem *policyOID); + +bool SecPVCIsAnchorPerConstraints(SecPVCRef pvc, SecCertificateSourceRef source, SecCertificateRef certificate); + +__END_DECLS + +#endif /* !_SECURITY_SECPOLICYSERVER_H_ */ diff --git a/trust/trustd/SecRevocationDb.c b/trust/trustd/SecRevocationDb.c new file mode 100644 index 00000000..92f9ae42 --- /dev/null +++ b/trust/trustd/SecRevocationDb.c @@ -0,0 +1,3978 @@ +/* + * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/* + * SecRevocationDb.c + */ + +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/SecRevocationNetworking.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilities/debugging.h" +#include "utilities/sec_action.h" +#include "utilities/sqlutils.h" +#include "utilities/SecAppleAnchorPriv.h" +#include "utilities/iOSforOSX.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + ============================================================================== + CoreFoundation utilities + ============================================================================== +*/ + +static bool hashCFThing(CFTypeRef thing, CC_SHA256_CTX* hash_ctx); + +/* comparison function for sorting dictionary keys alphabetically */ +static int compareCFStrings(const void *p, const void *q) { + CFStringRef str1 = *(CFStringRef *)p; + CFStringRef str2 = *(CFStringRef *)q; + if (!(isString(str1) && isString(str2))) { + return -1; /* can't compare non-string types */ + } + CFComparisonResult result = CFStringCompare(str1, str2, 0); + if (result == kCFCompareLessThan) { + return -1; + } else if (result == kCFCompareGreaterThan) { + return 1; + } + return 0; /* (result == kCFCompareEqualTo) */ +} + +static bool hashData(CFDataRef data, CC_SHA256_CTX* hash_ctx) { + if (!isData(data)) { return false; } + uint32_t length = (uint32_t)(CFDataGetLength(data) & 0xFFFFFFFF); + uint32_t n = OSSwapInt32(length); + CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); + const uint8_t *p = (uint8_t*)CFDataGetBytePtr(data); + if (p) { CC_SHA256_Update(hash_ctx, p, length); } + return (p != NULL); +} + +static bool hashString(CFStringRef str, CC_SHA256_CTX* hash_ctx) { + if (!isString(str)) { return false; } + __block bool ok = false; + CFStringPerformWithCString(str, ^(const char *strbuf) { + // hash string length (in bytes, not counting null terminator) + uint32_t c = (uint32_t)(strlen(strbuf) & 0xFFFFFFFF); + uint32_t n = OSSwapInt32(c); + CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); + // hash string bytes + CC_SHA256_Update(hash_ctx, strbuf, c); + ok = true; + }); + return ok; +} + +static bool hashNumber(CFNumberRef num, CC_SHA256_CTX* hash_ctx) { + uint32_t n = 0; + if (!isNumber(num) || !CFNumberGetValue(num, kCFNumberSInt32Type, &n)) { + return false; + } + n = OSSwapInt32(n); + CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); + return true; +} + +static bool hashBoolean(CFBooleanRef value, CC_SHA256_CTX* hash_ctx) { + if (!isBoolean(value)) { return false; } + uint8_t c = CFBooleanGetValue(value) ? 1 : 0; + CC_SHA256_Update(hash_ctx, &c, sizeof(uint8_t)); + return true; +} + +static bool hashArray(CFArrayRef array, CC_SHA256_CTX* hash_ctx) { + if (!isArray(array)) { return false; } + CFIndex count = CFArrayGetCount(array); + uint32_t n = OSSwapInt32(count & 0xFFFFFFFF); + CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); + __block bool ok = true; + CFArrayForEach(array, ^(const void *thing) { + ok &= hashCFThing(thing, hash_ctx); + }); + return ok; +} + +static bool hashDictionary(CFDictionaryRef dictionary, CC_SHA256_CTX* hash_ctx) { + if (!isDictionary(dictionary)) { return false; } + CFIndex count = CFDictionaryGetCount(dictionary); + const void **keys = (const void **)malloc(sizeof(void*) * count); + const void **vals = (const void **)malloc(sizeof(void*) * count); + bool ok = (keys && vals); + if (ok) { + CFDictionaryGetKeysAndValues(dictionary, keys, vals); + qsort(keys, count, sizeof(CFStringRef), compareCFStrings); + uint32_t n = OSSwapInt32(count & 0xFFFFFFFF); + CC_SHA256_Update(hash_ctx, &n, sizeof(uint32_t)); + } + for (CFIndex idx = 0; ok && idx < count; idx++) { + CFStringRef key = (CFStringRef)keys[idx]; + CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(dictionary, key); + ok &= hashString(key, hash_ctx); + ok &= hashCFThing(value, hash_ctx); + } + free(keys); + free(vals); + return ok; +} + +static bool hashCFThing(CFTypeRef thing, CC_SHA256_CTX* hash_ctx) { + if (isArray(thing)) { + return hashArray(thing, hash_ctx); + } else if (isDictionary(thing)) { + return hashDictionary(thing, hash_ctx); + } else if (isData(thing)) { + return hashData(thing, hash_ctx); + } else if (isString(thing)) { + return hashString(thing, hash_ctx); + } else if (isNumber(thing)) { + return hashNumber(thing, hash_ctx); + } else if (isBoolean(thing)) { + return hashBoolean(thing, hash_ctx); + } + return false; +} + +static double htond(double h) { + /* no-op if big endian */ + if (OSHostByteOrder() == OSBigEndian) { + return h; + } + double n; + size_t i=0; + char *hp = (char*)&h; + char *np = (char*)&n; + while (i < sizeof(h)) { np[i] = hp[(sizeof(h)-1)-i]; ++i; } + return n; +} + + +// MARK: - +// MARK: Valid definitions +/* + ============================================================================== + Valid definitions + ============================================================================== +*/ + +const CFStringRef kValidUpdateProdServer = CFSTR("valid.apple.com"); +const CFStringRef kValidUpdateSeedServer = CFSTR("valid.apple.com/seed"); +const CFStringRef kValidUpdateCarryServer = CFSTR("valid.apple.com/carry"); + +static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); +static CFStringRef kUpdateServerKey = CFSTR("ValidUpdateServer"); +static CFStringRef kUpdateEnabledKey = CFSTR("ValidUpdateEnabled"); +static CFStringRef kVerifyEnabledKey = CFSTR("ValidVerifyEnabled"); +static CFStringRef kUpdateIntervalKey = CFSTR("ValidUpdateInterval"); +static CFStringRef kBoolTrueKey = CFSTR("1"); +static CFStringRef kBoolFalseKey = CFSTR("0"); + +/* constant length of boolean string keys */ +#define BOOL_STRING_KEY_LENGTH 1 + +typedef CF_OPTIONS(CFOptionFlags, SecValidInfoFlags) { + kSecValidInfoComplete = 1u << 0, + kSecValidInfoCheckOCSP = 1u << 1, + kSecValidInfoKnownOnly = 1u << 2, + kSecValidInfoRequireCT = 1u << 3, + kSecValidInfoAllowlist = 1u << 4, + kSecValidInfoNoCACheck = 1u << 5, + kSecValidInfoOverridable = 1u << 6, + kSecValidInfoDateConstraints = 1u << 7, + kSecValidInfoNameConstraints = 1u << 8, + kSecValidInfoPolicyConstraints = 1u << 9, + kSecValidInfoNoCAv2Check = 1u << 10, +}; + +/* minimum update interval */ +#define kSecMinUpdateInterval (60.0 * 5) + +/* standard update interval */ +#define kSecStdUpdateInterval (60.0 * 60 * 3) + +/* maximum allowed interval */ +#define kSecMaxUpdateInterval (60.0 * 60 * 24 * 7) + +#define kSecRevocationBasePath "/Library/Keychains/crls" +#define kSecRevocationCurUpdateFile "update-current" +#define kSecRevocationDbFileName "valid.sqlite3" +#define kSecRevocationDbReplaceFile ".valid_replace" + +#define isDbOwner SecOTAPKIIsSystemTrustd + +#define kSecRevocationDbChanged "com.apple.trustd.valid.db-changed" + +/* database schema version + v1 = initial version + v2 = fix for group entry transitions + v3 = handle optional entries in update dictionaries + v4 = add db_format and db_source entries + v5 = add date constraints table, with updated group flags + v6 = explicitly set autovacuum and journal modes at db creation + v7 = add policies column to groups table (policy constraints) + + Note: kSecRevocationDbMinSchemaVersion is the lowest version whose + results can be used. This allows revocation results to be obtained + from an existing db before the next update interval occurs, at which + time we'll update to the current version (kSecRevocationDbSchemaVersion). +*/ +#define kSecRevocationDbSchemaVersion 7 /* current version we support */ +#define kSecRevocationDbMinSchemaVersion 7 /* minimum version we can use */ + +/* update file format +*/ +CF_ENUM(CFIndex) { + kSecValidUpdateFormatG1 = 1, /* initial version */ + kSecValidUpdateFormatG2 = 2, /* signed content, single plist */ + kSecValidUpdateFormatG3 = 3 /* signed content, multiple plists */ +}; + +#define kSecRevocationDbUpdateFormat 3 /* current version we support */ +#define kSecRevocationDbMinUpdateFormat 2 /* minimum version we can use */ + +#define kSecRevocationDbCacheSize 100 + +typedef struct __SecRevocationDb *SecRevocationDbRef; +struct __SecRevocationDb { + SecDbRef db; + dispatch_queue_t update_queue; + bool updateInProgress; + bool unsupportedVersion; + bool changed; + CFMutableArrayRef info_cache_list; + CFMutableDictionaryRef info_cache; + os_unfair_lock info_cache_lock; +}; + +typedef struct __SecRevocationDbConnection *SecRevocationDbConnectionRef; +struct __SecRevocationDbConnection { + SecRevocationDbRef db; + SecDbConnectionRef dbconn; + CFIndex precommitVersion; + CFIndex precommitDbVersion; + CFIndex precommitInterval; + bool fullUpdate; +}; + +bool SecRevocationDbVerifyUpdate(void *update, CFIndex length); +bool SecRevocationDbIngestUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex chunkVersion, CFIndex *outVersion, CFErrorRef *error); +bool _SecRevocationDbApplyUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex version, CFErrorRef *error); +CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval); +bool SecRevocationDbUpdateSchema(SecRevocationDbRef rdb); +CFIndex SecRevocationDbGetUpdateFormat(void); +bool _SecRevocationDbSetUpdateSource(SecRevocationDbConnectionRef dbc, CFStringRef source, CFErrorRef *error); +bool SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef source); +CFStringRef SecRevocationDbCopyUpdateSource(void); +bool SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate, CFErrorRef *error); +CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void); +dispatch_queue_t SecRevocationDbGetUpdateQueue(void); +bool _SecRevocationDbRemoveAllEntries(SecRevocationDbConnectionRef dbc, CFErrorRef *error); +void SecRevocationDbReleaseAllConnections(void); +static bool SecValidUpdateForceReplaceDatabase(void); +static void SecRevocationDbWith(void(^dbJob)(SecRevocationDbRef db)); +static bool SecRevocationDbPerformWrite(SecRevocationDbRef rdb, CFErrorRef *error, bool(^writeJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)); +static bool SecRevocationDbPerformRead(SecRevocationDbRef rdb, CFErrorRef *error, bool(^readJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)); +static SecValidInfoFormat _SecRevocationDbGetGroupFormat(SecRevocationDbConnectionRef dbc, int64_t groupId, SecValidInfoFlags *flags, CFDataRef *data, CFDataRef *policies, CFErrorRef *error); +static bool _SecRevocationDbSetUpdateInterval(SecRevocationDbConnectionRef dbc, int64_t interval, CFErrorRef *error); +static int64_t _SecRevocationDbGetUpdateInterval(SecRevocationDbConnectionRef dbc, CFErrorRef *error); +static bool _SecRevocationDbSetVersion(SecRevocationDbConnectionRef dbc, CFIndex version, CFErrorRef *error); +static int64_t _SecRevocationDbGetVersion(SecRevocationDbConnectionRef dbc, CFErrorRef *error); +static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef rdb, SecRevocationDbConnectionRef dbc, CFErrorRef *error); +static CFArrayRef _SecRevocationDbCopyHashes(SecRevocationDbConnectionRef dbc, CFErrorRef *error); +static bool _SecRevocationDbSetHashes(SecRevocationDbConnectionRef dbc, CFArrayRef hashes, CFErrorRef *error); +static void SecRevocationDbResetCaches(void); +static SecRevocationDbConnectionRef SecRevocationDbConnectionInit(SecRevocationDbRef db, SecDbConnectionRef dbconn, CFErrorRef *error); +static bool SecRevocationDbComputeDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error); + + +static CFDataRef copyInflatedData(CFDataRef data) { + if (!data) { + return NULL; + } + z_stream zs; + memset(&zs, 0, sizeof(zs)); + /* 32 is a magic value which enables automatic header detection + of gzip or zlib compressed data. */ + if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) { + return NULL; + } + zs.next_in = (UInt8 *)(CFDataGetBytePtr(data)); + zs.avail_in = (uInt)CFDataGetLength(data); + + CFMutableDataRef outData = CFDataCreateMutable(NULL, 0); + if (!outData) { + return NULL; + } + CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); + unsigned char *buf = malloc(buf_sz); + int rc; + do { + zs.next_out = (Bytef*)buf; + zs.avail_out = (uInt)buf_sz; + rc = inflate(&zs, 0); + CFIndex outLen = CFDataGetLength(outData); + if (outLen < (CFIndex)zs.total_out) { + CFDataAppendBytes(outData, (const UInt8*)buf, (CFIndex)zs.total_out - outLen); + } + } while (rc == Z_OK); + + inflateEnd(&zs); + free(buf); + if (rc != Z_STREAM_END) { + CFReleaseSafe(outData); + return NULL; + } + return (CFDataRef)outData; +} + +static CFDataRef copyDeflatedData(CFDataRef data) { + if (!data) { + return NULL; + } + z_stream zs; + memset(&zs, 0, sizeof(zs)); + if (deflateInit(&zs, Z_BEST_COMPRESSION) != Z_OK) { + return NULL; + } + zs.next_in = (UInt8 *)(CFDataGetBytePtr(data)); + zs.avail_in = (uInt)CFDataGetLength(data); + + CFMutableDataRef outData = CFDataCreateMutable(NULL, 0); + if (!outData) { + return NULL; + } + CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); + unsigned char *buf = malloc(buf_sz); + int rc = Z_BUF_ERROR; + do { + zs.next_out = (Bytef*)buf; + zs.avail_out = (uInt)buf_sz; + rc = deflate(&zs, Z_FINISH); + + if (rc == Z_OK || rc == Z_STREAM_END) { + CFIndex buf_used = buf_sz - zs.avail_out; + CFDataAppendBytes(outData, (const UInt8*)buf, buf_used); + } + else if (rc == Z_BUF_ERROR) { + free(buf); + buf_sz = malloc_good_size(buf_sz * 2); + buf = malloc(buf_sz); + if (buf) { + rc = Z_OK; /* try again with larger buffer */ + } + } + } while (rc == Z_OK && zs.avail_in); + + deflateEnd(&zs); + free(buf); + if (rc != Z_STREAM_END) { + CFReleaseSafe(outData); + return NULL; + } + return (CFDataRef)outData; +} + +/* Read file opens the file, mmaps it and then closes the file. */ +int readValidFile(const char *fileName, + CFDataRef *bytes) { // mmapped and returned -- must be munmapped! + int rtn, fd; + const uint8_t *buf = NULL; + struct stat sb; + size_t size = 0; + + *bytes = NULL; + fd = open(fileName, O_RDONLY); + if (fd < 0) { return errno; } + rtn = fstat(fd, &sb); + if (rtn) { goto errOut; } + if (sb.st_size > (off_t) ((UINT32_MAX >> 1)-1)) { + rtn = EFBIG; + goto errOut; + } + size = (size_t)sb.st_size; + + buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!buf || buf == MAP_FAILED) { + rtn = errno; + secerror("unable to map %s (errno %d)", fileName, rtn); + goto errOut; + } + + *bytes = CFDataCreateWithBytesNoCopy(NULL, buf, size, kCFAllocatorNull); + +errOut: + close(fd); + if(rtn) { + CFReleaseNull(*bytes); + if (buf) { + int unmap_err = munmap((void *)buf, size); + if (unmap_err != 0) { + secerror("unable to unmap %ld bytes at %p (error %d)", (long)size, buf, rtn); + } + } + } + return rtn; +} + +static bool removeFileWithSuffix(const char *basepath, const char *suffix) { + bool result = false; + char *path = NULL; + asprintf(&path, "%s%s", basepath, suffix); + if (path) { + if (remove(path) == -1) { + int error = errno; + if (error == ENOENT) { + result = true; // not an error if the file did not exist + } else { + secnotice("validupdate", "remove (%s): %s", path, strerror(error)); + } + } else { + result = true; + } + free(path); + } + return result; +} + +static CFDataRef CF_RETURNS_RETAINED createPoliciesData(CFArrayRef policies) { + /* + * Given an array of CFNumber values (in the range 0..127), + * allocate and return a CFDataRef representation. Per Valid specification, + * a zero-length array is allowed, meaning no policies are permitted. + */ + CFIndex count = (policies) ? CFArrayGetCount(policies) : -1; + if (count < 0 || count > 127) { + return NULL; /* either no constraints, or far more than we expect. */ + } + CFDataRef data = NULL; + CFIndex length = 1 + (sizeof(int8_t) * count); + int8_t *bytes = malloc(length); + if (bytes) { + int8_t *p = bytes; + *p++ = (int8_t)(count & 0xFF); + for (CFIndex idx = 0; idx < count; idx++) { + int8_t pval = 0; + CFNumberRef value = (CFNumberRef)CFArrayGetValueAtIndex(policies, idx); + if (isNumber(value)) { + (void)CFNumberGetValue(value, kCFNumberSInt8Type, &pval); + } + *p++ = pval; + } + data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)bytes, length); + } + free(bytes); + return data; +} + +static CFDataRef CF_RETURNS_RETAINED cfToHexData(CFDataRef data, bool prependWildcard) { + if (!isData(data)) { return NULL; } + CFIndex len = CFDataGetLength(data) * 2; + CFMutableStringRef hex = CFStringCreateMutable(NULL, len+1); + static const char* digits[]={ + "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; + if (prependWildcard) { + CFStringAppendCString(hex, "%", 1); + } + const uint8_t* p = CFDataGetBytePtr(data); + for (CFIndex i = 0; i < CFDataGetLength(data); i++) { + CFStringAppendCString(hex, digits[p[i] >> 4], 1); + CFStringAppendCString(hex, digits[p[i] & 0xf], 1); + } + CFDataRef result = CFStringCreateExternalRepresentation(NULL, hex, kCFStringEncodingUTF8, 0); + CFReleaseSafe(hex); + return result; +} + +static bool copyFilterComponents(CFDataRef xmlData, CFDataRef * CF_RETURNS_RETAINED xor, + CFArrayRef * CF_RETURNS_RETAINED params) { + /* + The 'xmlData' parameter is a flattened XML dictionary, + containing 'xor' and 'params' keys. First order of + business is to reconstitute the blob into components. + */ + bool result = false; + CFRetainSafe(xmlData); + CFDataRef propListData = xmlData; + /* Expand data blob if needed */ + CFDataRef inflatedData = copyInflatedData(propListData); + if (inflatedData) { + CFReleaseSafe(propListData); + propListData = inflatedData; + } + CFDataRef xorData = NULL; + CFArrayRef paramsArray = NULL; + CFPropertyListRef nto1 = CFPropertyListCreateWithData(kCFAllocatorDefault, propListData, 0, NULL, NULL); + CFReleaseSafe(propListData); + if (nto1) { + xorData = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("xor")); + CFRetainSafe(xorData); + paramsArray = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("params")); + CFRetainSafe(paramsArray); + CFReleaseSafe(nto1); + } + result = (xorData && paramsArray); + if (xor) { + *xor = xorData; + } else { + CFReleaseSafe(xorData); + } + if (params) { + *params = paramsArray; + } else { + CFReleaseSafe(paramsArray); + } + return result; +} + +// MARK: - +// MARK: SecValidUpdate +/* + ============================================================================== + SecValidUpdate + ============================================================================== +*/ + +CFAbsoluteTime gUpdateStarted = 0.0; +CFAbsoluteTime gNextUpdate = 0.0; +static CFIndex gUpdateInterval = 0; +static CFIndex gLastVersion = 0; + +/* Update Format: + 1. The length of the signed data, as a 4-byte integer in network byte order. + 2. The signed data, which consists of: + a. A 4-byte integer in network byte order, the count of plists to follow; and then for each plist: + i. A 4-byte integer, the length of each plist + ii. A plist, in binary form + b. There may be other data after the plists in the signed data, described by a future version of this specification. + 3. The length of the following CMS blob, as a 4-byte integer in network byte order. + 4. A detached CMS signature of the signed data described above. + 5. There may be additional data after the CMS blob, described by a future version of this specification. + + Note: the difference between g2 and g3 format is the addition of the 4-byte count in (2a). +*/ +static bool SecValidUpdateProcessData(SecRevocationDbConnectionRef dbc, CFIndex format, CFDataRef updateData, CFErrorRef *error) { + bool result = false; + if (!updateData || format < 2) { + SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: invalid update format")); + return result; + } + CFIndex version = 0; + CFIndex interval = 0; + const UInt8* p = CFDataGetBytePtr(updateData); + size_t bytesRemaining = (p) ? (size_t)CFDataGetLength(updateData) : 0; + /* make sure there is enough data to contain length and count */ + if (bytesRemaining < ((CFIndex)sizeof(uint32_t) * 2)) { + secinfo("validupdate", "Skipping property list creation (length %ld is too short)", (long)bytesRemaining); + SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: data length is too short")); + return result; + } + /* get length of signed data */ + uint32_t dataLength = OSSwapInt32(*((uint32_t *)p)); + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + + /* get plist count (G3 format and later) */ + uint32_t plistCount = 1; + uint32_t plistTotal = 1; + if (format > kSecValidUpdateFormatG2) { + plistCount = OSSwapInt32(*((uint32_t *)p)); + plistTotal = plistCount; + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + } + if (dataLength > bytesRemaining) { + secinfo("validupdate", "Skipping property list creation (dataLength=%ld, bytesRemaining=%ld)", + (long)dataLength, (long)bytesRemaining); + SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: data longer than expected")); + return result; + } + + /* process each chunked plist */ + bool ok = true; + CFErrorRef localError = NULL; + uint32_t plistProcessed = 0; + while (plistCount > 0 && bytesRemaining > 0) { + CFPropertyListRef propertyList = NULL; + uint32_t plistLength = dataLength; + if (format > kSecValidUpdateFormatG2) { + plistLength = OSSwapInt32(*((uint32_t *)p)); + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + } + --plistCount; + ++plistProcessed; + + if (plistLength <= bytesRemaining) { + CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, p, plistLength, kCFAllocatorNull); + propertyList = CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable, NULL, NULL); + CFReleaseNull(data); + } + if (isDictionary(propertyList)) { + secdebug("validupdate", "Ingesting plist chunk %u of %u, length: %u", + plistProcessed, plistTotal, plistLength); + CFIndex curVersion = -1; + ok = ok && SecRevocationDbIngestUpdate(dbc, (CFDictionaryRef)propertyList, version, &curVersion, &localError); + if (plistProcessed == 1) { + dbc->precommitVersion = version = curVersion; + // get server-provided interval + CFTypeRef value = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, + CFSTR("check-again")); + if (isNumber(value)) { + CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); + } + // get server-provided hash list + value = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, + CFSTR("hash")); + ok = _SecRevocationDbSetHashes(dbc, (CFArrayRef)value, &localError); + } + if (ok && curVersion < 0) { + plistCount = 0; // we already had this version; skip remaining plists + result = true; + } + } else { + secinfo("validupdate", "Failed to deserialize update chunk %u of %u", + plistProcessed, plistTotal); + SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: failed to get update chunk")); + if (plistProcessed == 1) { + gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); + } + } + /* All finished with this property list */ + CFReleaseSafe(propertyList); + + bytesRemaining -= plistLength; + p += plistLength; + } + + if (ok && version > 0) { + secdebug("validupdate", "Update received: v%ld", (long)version); + gLastVersion = version; + gNextUpdate = SecRevocationDbComputeNextUpdateTime(interval); + secdebug("validupdate", "Next update time: %f", gNextUpdate); + result = true; + } + + (void) CFErrorPropagate(localError, error); + return result; +} + +void SecValidUpdateVerifyAndIngest(CFDataRef updateData, CFStringRef updateServer, bool fullUpdate) { + if (!updateData) { + secnotice("validupdate", "invalid update data"); + return; + } + /* Verify CMS signature on signed data */ + if (!SecRevocationDbVerifyUpdate((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) { + secerror("failed to verify valid update"); + TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, errSecVerifyFailed); + return; + } + /* Read current update source from database. */ + CFStringRef dbSource = SecRevocationDbCopyUpdateSource(); + if (dbSource && updateServer && (kCFCompareEqualTo != CFStringCompare(dbSource, updateServer, + kCFCompareCaseInsensitive))) { + secnotice("validupdate", "switching db source from \"%@\" to \"%@\"", dbSource, updateServer); + } + CFReleaseNull(dbSource); + + /* Ingest the update. This is now performed under a single immediate write transaction, + so other writers are blocked (but not other readers), and the changes can be rolled back + in their entirety if any error occurs. */ + __block bool ok = true; + __block CFErrorRef localError = NULL; + SecRevocationDbWith(^(SecRevocationDbRef rdb) { + ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + if (fullUpdate) { + /* Must completely replace existing database contents */ + secdebug("validupdate", "starting to process full update; clearing database"); + ok = ok && _SecRevocationDbRemoveAllEntries(dbc, blockError); + ok = ok && _SecRevocationDbSetUpdateSource(dbc, updateServer, blockError); + dbc->precommitVersion = 0; + dbc->fullUpdate = true; + } + CFIndex startingVersion = dbc->precommitVersion; + ok = ok && SecValidUpdateProcessData(dbc, kSecValidUpdateFormatG3, updateData, blockError); + rdb->changed = ok && (startingVersion < dbc->precommitVersion); + if (!ok) { + secerror("failed to process valid update: %@", blockError ? *blockError : NULL); + TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, errSecDecode); + } else { + TrustdHealthAnalyticsLogSuccess(TAEventValidUpdate); + } + return ok; + }); + if (rdb->changed) { + rdb->changed = false; + bool verifyEnabled = false; + CFBooleanRef value = (CFBooleanRef)CFPreferencesCopyValue(kVerifyEnabledKey, + kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isBoolean(value)) { + verifyEnabled = CFBooleanGetValue(value); + } + CFReleaseNull(value); + if (verifyEnabled) { + /* compute and verify database content hashes */ + ok = ok && SecRevocationDbPerformRead(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + ok = ok && SecRevocationDbComputeDigests(dbc, blockError); + if (!ok) { + /* digests failed to verify, so roll back to known-good snapshot */ + (void) SecValidUpdateForceReplaceDatabase(); + } + return ok; + }); + } + /* signal other trustd instances that the database has been updated */ + notify_post(kSecRevocationDbChanged); + } + }); + + /* remember next update time in case of restart (separate write transaction) */ + (void) SecRevocationDbSetNextUpdateTime(gNextUpdate, NULL); + + CFReleaseSafe(localError); +} + +static bool SecValidUpdateForceReplaceDatabase(void) { + __block bool result = false; + + // write semaphore file that we will pick up when we next launch + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbReplaceFile), ^(const char *utf8String) { + struct stat sb; + int fd = open(utf8String, O_WRONLY | O_CREAT, DEFFILEMODE); + if (fd == -1 || fstat(fd, &sb)) { + secnotice("validupdate", "unable to write %s (error %d)", utf8String, errno); + } else { + result = true; + } + if (fd >= 0) { + close(fd); + } + }); + if (result) { + // exit as gracefully as possible so we can replace the database + secnotice("validupdate", "process exiting to replace db file"); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + xpc_transaction_exit_clean(); + }); + } + return result; +} + +static bool SecValidUpdateSatisfiedLocally(CFStringRef server, CFIndex version, bool safeToReplace) { + __block bool result = false; + SecOTAPKIRef otapkiRef = NULL; + bool relaunching = false; + static int sNumLocalUpdates = 0; + + // if we've replaced the database with a local asset twice in a row, + // something is wrong with it. Get this update from the server. + if (sNumLocalUpdates > 1) { + secdebug("validupdate", "%d consecutive db resets, ignoring local asset", sNumLocalUpdates); + goto updateExit; + } + + // if a non-production server is specified, we will not be able to use a + // local production asset since its update sequence will be different. + if (kCFCompareEqualTo != CFStringCompare(server, kValidUpdateProdServer, + kCFCompareCaseInsensitive)) { + secdebug("validupdate", "non-production server specified, ignoring local asset"); + goto updateExit; + } + + // check static database asset(s) + otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (!otapkiRef) { + goto updateExit; + } + CFIndex assetVersion = SecOTAPKIGetValidSnapshotVersion(otapkiRef); + CFIndex assetFormat = SecOTAPKIGetValidSnapshotFormat(otapkiRef); + // version <= 0 means the database is invalid or empty. + // version > 0 means we have some version, but we need to see if a + // newer version is available as a local asset. + if (assetVersion <= version || assetFormat < kSecValidUpdateFormatG3) { + // asset is not newer than ours, or its version is unknown + goto updateExit; + } + + // replace database only if safe to do so (i.e. called at startup) + if (!safeToReplace) { + relaunching = SecValidUpdateForceReplaceDatabase(); + goto updateExit; + } + + // try to copy uncompressed database asset, if available + const char *validDbPathBuf = SecOTAPKIGetValidDatabaseSnapshot(otapkiRef); + if (validDbPathBuf) { + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { + secdebug("validupdate", "will copy data from \"%s\"", validDbPathBuf); + copyfile_state_t state = copyfile_state_alloc(); + int retval = copyfile(validDbPathBuf, path, state, COPYFILE_DATA); + copyfile_state_free(state); + if (retval < 0) { + secnotice("validupdate", "copyfile error %d", retval); + } else { + result = true; + } + }); + } + +updateExit: + CFReleaseNull(otapkiRef); + if (result) { + sNumLocalUpdates++; + gLastVersion = SecRevocationDbGetVersion(); + // note: snapshot should already have latest schema and production source, + // but set it here anyway so we don't keep trying to replace the db. + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void)SecRevocationDbSetUpdateSource(db, server); + (void)SecRevocationDbUpdateSchema(db); + }); + gUpdateStarted = 0; + secdebug("validupdate", "local update to g%ld/v%ld complete at %f", + (long)SecRevocationDbGetUpdateFormat(), (long)gLastVersion, + (double)CFAbsoluteTimeGetCurrent()); + } else { + sNumLocalUpdates = 0; // reset counter + } + if (relaunching) { + // request is locally satisfied; don't schedule a network update + result = true; + } + return result; +} + +static bool SecValidUpdateSchedule(bool updateEnabled, CFStringRef server, CFIndex version) { + /* Check if we have a later version available locally */ + if (SecValidUpdateSatisfiedLocally(server, version, false)) { + return true; + } + + /* If update not permitted return */ + if (!updateEnabled) { + return false; + } + +#if !TARGET_OS_BRIDGE + /* Schedule as a maintenance task */ + secdebug("validupdate", "will fetch v%lu from \"%@\"", (unsigned long)version, server); + return SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); +#else + return false; +#endif +} + +static CFStringRef SecRevocationDbGetDefaultServer(void) { +#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE + #if RC_SEED_BUILD + CFStringRef defaultServer = kValidUpdateSeedServer; + #else // !RC_SEED_BUILD + CFStringRef defaultServer = kValidUpdateProdServer; + #endif // !RC_SEED_BUILD + if (os_variant_has_internal_diagnostics("com.apple.security")) { + defaultServer = kValidUpdateCarryServer; + } + return defaultServer; +#else // TARGET_OS_WATCH || TARGET_OS_BRIDGE + /* Because watchOS and bridgeOS can't update over the air, we should + * always use the prod server so that the valid database built into the + * image is used. */ + return kValidUpdateProdServer; +#endif +} + +void SecRevocationDbInitialize() { + if (!isDbOwner()) { return; } + os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.initialize"); + __block bool initializeDb = false; + + /* create base path if it doesn't exist */ + WithPathInRevocationInfoDirectory(NULL, ^(const char *utf8String) { + (void)mkpath_np(utf8String, 0755); + }); + + /* check semaphore file */ + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbReplaceFile), ^(const char *path) { + struct stat sb; + if (stat(path, &sb) == 0) { + initializeDb = true; /* file was found, so we will replace the database */ + if (remove(path) == -1) { + int error = errno; + secnotice("validupdate", "remove (%s): %s", path, strerror(error)); + } + } + }); + + /* check database */ + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { + if (initializeDb) { + /* remove old database file(s) */ + (void)removeFileWithSuffix(path, ""); + (void)removeFileWithSuffix(path, "-journal"); + (void)removeFileWithSuffix(path, "-shm"); + (void)removeFileWithSuffix(path, "-wal"); + } + else { + struct stat sb; + if (stat(path, &sb) == -1) { + initializeDb = true; /* file not found, so we will create the database */ + } + } + }); + + if (!initializeDb) { + os_release(transaction); + return; /* database exists and doesn't need replacing */ + } + + /* initialize database from local asset */ + CFTypeRef value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + CFStringRef server = (isString(value)) ? (CFStringRef)value : (CFStringRef)SecRevocationDbGetDefaultServer(); + CFIndex version = 0; + secnotice("validupdate", "initializing database"); + if (!SecValidUpdateSatisfiedLocally(server, version, true)) { +#if !TARGET_OS_BRIDGE + /* Schedule full update as a maintenance task */ + (void)SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); +#endif + } + CFReleaseSafe(value); + os_release(transaction); +} + + +// MARK: - +// MARK: SecValidInfoRef +/* + ============================================================================== + SecValidInfoRef + ============================================================================== +*/ + +CFGiblisWithCompareFor(SecValidInfo); + +static SecValidInfoRef SecValidInfoCreate(SecValidInfoFormat format, + CFOptionFlags flags, + bool isOnList, + CFDataRef certHash, + CFDataRef issuerHash, + CFDataRef anchorHash, + CFDateRef notBeforeDate, + CFDateRef notAfterDate, + CFDataRef nameConstraints, + CFDataRef policyConstraints) { + SecValidInfoRef validInfo; + validInfo = CFTypeAllocate(SecValidInfo, struct __SecValidInfo, kCFAllocatorDefault); + if (!validInfo) { return NULL; } + + CFRetainSafe(certHash); + CFRetainSafe(issuerHash); + CFRetainSafe(anchorHash); + CFRetainSafe(notBeforeDate); + CFRetainSafe(notAfterDate); + CFRetainSafe(nameConstraints); + CFRetainSafe(policyConstraints); + + validInfo->format = format; + validInfo->certHash = certHash; + validInfo->issuerHash = issuerHash; + validInfo->anchorHash = anchorHash; + validInfo->isOnList = isOnList; + validInfo->valid = (flags & kSecValidInfoAllowlist); + validInfo->complete = (flags & kSecValidInfoComplete); + validInfo->checkOCSP = (flags & kSecValidInfoCheckOCSP); + validInfo->knownOnly = (flags & kSecValidInfoKnownOnly); + validInfo->requireCT = (flags & kSecValidInfoRequireCT); + validInfo->noCACheck = (flags & kSecValidInfoNoCAv2Check); + validInfo->overridable = (flags & kSecValidInfoOverridable); + validInfo->hasDateConstraints = (flags & kSecValidInfoDateConstraints); + validInfo->hasNameConstraints = (flags & kSecValidInfoNameConstraints); + validInfo->hasPolicyConstraints = (flags & kSecValidInfoPolicyConstraints); + validInfo->notBeforeDate = notBeforeDate; + validInfo->notAfterDate = notAfterDate; + validInfo->nameConstraints = nameConstraints; + validInfo->policyConstraints = policyConstraints; + + return validInfo; +} + +static void SecValidInfoDestroy(CFTypeRef cf) { + SecValidInfoRef validInfo = (SecValidInfoRef)cf; + if (validInfo) { + CFReleaseNull(validInfo->certHash); + CFReleaseNull(validInfo->issuerHash); + CFReleaseNull(validInfo->anchorHash); + CFReleaseNull(validInfo->notBeforeDate); + CFReleaseNull(validInfo->notAfterDate); + CFReleaseNull(validInfo->nameConstraints); + CFReleaseNull(validInfo->policyConstraints); + } +} + +void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor) { + if (!validInfo) { + return; + } + CFDataRef anchorHash = NULL; + if (anchor) { + anchorHash = SecCertificateCopySHA256Digest(anchor); + + /* clear no-ca flag for anchors where we want OCSP checked [32523118] */ + if (SecIsAppleTrustAnchor(anchor, 0)) { + validInfo->noCACheck = false; + } + } + CFReleaseNull(validInfo->anchorHash); + validInfo->anchorHash = anchorHash; +} + +static Boolean SecValidInfoCompare(CFTypeRef a, CFTypeRef b) { + SecValidInfoRef validInfoA = (SecValidInfoRef)a; + SecValidInfoRef validInfoB = (SecValidInfoRef)b; + if (validInfoA == validInfoB) { + return true; + } + if (!validInfoA || !validInfoB || + (CFGetTypeID(a) != SecValidInfoGetTypeID()) || + (CFGetTypeID(b) != SecValidInfoGetTypeID())) { + return false; + } + return CFEqualSafe(validInfoA->certHash, validInfoB->certHash) && CFEqualSafe(validInfoA->issuerHash, validInfoB->issuerHash); +} + +static CFStringRef SecValidInfoCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecValidInfoRef validInfo = (SecValidInfoRef)cf; + CFStringRef certHash = CFDataCopyHexString(validInfo->certHash); + CFStringRef issuerHash = CFDataCopyHexString(validInfo->issuerHash); + CFStringRef desc = CFStringCreateWithFormat(NULL, formatOptions, CFSTR("validInfo certHash: %@ issuerHash: %@"), certHash, issuerHash); + CFReleaseNull(certHash); + CFReleaseNull(issuerHash); + return desc; +} + + +// MARK: - +// MARK: SecRevocationDb +/* + ============================================================================== + SecRevocationDb + ============================================================================== +*/ + +/* SecRevocationDbCheckNextUpdate returns true if we dispatched an + update request, otherwise false. +*/ +static bool _SecRevocationDbCheckNextUpdate(void) { + // are we the db owner instance? + if (!isDbOwner()) { + return false; + } + CFTypeRef value = NULL; + + // is it time to check? + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + CFAbsoluteTime minNextUpdate = now + gUpdateInterval; + gUpdateStarted = now; + + if (0 == gNextUpdate) { + // first time we're called, check if we have a saved nextUpdate value + gNextUpdate = SecRevocationDbGetNextUpdateTime(); + minNextUpdate = now; + if (gNextUpdate < minNextUpdate) { + gNextUpdate = minNextUpdate; + } + // allow pref to override update interval, if it exists + CFIndex interval = -1; + value = (CFNumberRef)CFPreferencesCopyValue(kUpdateIntervalKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isNumber(value)) { + if (CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval)) { + if (interval < kSecMinUpdateInterval) { + interval = kSecMinUpdateInterval; + } else if (interval > kSecMaxUpdateInterval) { + interval = kSecMaxUpdateInterval; + } + } + } + CFReleaseNull(value); + gUpdateInterval = kSecStdUpdateInterval; + if (interval > 0) { + gUpdateInterval = interval; + } + // pin next update time to the preferred update interval + if (gNextUpdate > (gUpdateStarted + gUpdateInterval)) { + gNextUpdate = gUpdateStarted + gUpdateInterval; + } + secdebug("validupdate", "next update at %f (in %f seconds)", + (double)gUpdateStarted, (double)gNextUpdate-gUpdateStarted); + } + if (gNextUpdate > now) { + gUpdateStarted = 0; + return false; + } + secnotice("validupdate", "starting update"); + + // set minimum next update time here in case we can't get an update + gNextUpdate = minNextUpdate; + + // determine which server to query + CFStringRef server; + value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isString(value)) { + server = (CFStringRef) CFRetain(value); + } else { + server = (CFStringRef) CFRetain(SecRevocationDbGetDefaultServer()); + } + CFReleaseNull(value); + + // determine version of our current database + CFIndex version = SecRevocationDbGetVersion(); + secdebug("validupdate", "got version %ld from db", (long)version); + if (version <= 0) { + if (gLastVersion > 0) { + secdebug("validupdate", "error getting version; using last good version: %ld", (long)gLastVersion); + } + version = gLastVersion; + } + + // determine source of our current database + // (if this ever changes, we will need to reload the db) + CFStringRef db_source = SecRevocationDbCopyUpdateSource(); + if (!db_source) { + db_source = (CFStringRef) CFRetain(kValidUpdateProdServer); + } + + // determine whether we need to recreate the database + CFIndex db_version = SecRevocationDbGetSchemaVersion(); + CFIndex db_format = SecRevocationDbGetUpdateFormat(); + if (db_version < kSecRevocationDbSchemaVersion || + db_format < kSecRevocationDbUpdateFormat || + kCFCompareEqualTo != CFStringCompare(server, db_source, kCFCompareCaseInsensitive)) { + // we need to fully rebuild the db contents, so we set our version to 0. + version = gLastVersion = 0; + } + + // determine whether update fetching is enabled +#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) + bool updateEnabled = true; // macOS 10.13 or iOS 11.0 +#else + bool updateEnabled = false; +#endif + value = (CFBooleanRef)CFPreferencesCopyValue(kUpdateEnabledKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isBoolean(value)) { + updateEnabled = CFBooleanGetValue((CFBooleanRef)value); + } + CFReleaseNull(value); + + // Schedule maintenance work + bool result = SecValidUpdateSchedule(updateEnabled, server, version); + CFReleaseNull(server); + CFReleaseNull(db_source); + return result; +} + +void SecRevocationDbCheckNextUpdate(void) { + static dispatch_once_t once; + static sec_action_t action; + + dispatch_once(&once, ^{ + dispatch_queue_t update_queue = SecRevocationDbGetUpdateQueue(); + action = sec_action_create_with_queue(update_queue, "update_check", kSecMinUpdateInterval); + sec_action_set_handler(action, ^{ + os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.checkNextUpdate"); + (void)_SecRevocationDbCheckNextUpdate(); + os_release(transaction); + }); + }); + sec_action_perform(action); +} + +/* This function verifies an update, in this format: + 1) unsigned 32-bit network-byte-order length of binary plist + 2) binary plist data + 3) unsigned 32-bit network-byte-order length of CMS message + 4) CMS message (containing certificates and signature over binary plist) + + The length argument is the total size of the packed update data. +*/ +bool SecRevocationDbVerifyUpdate(void *update, CFIndex length) { + if (!update || length <= (CFIndex)sizeof(uint32_t)) { + return false; + } + uint32_t plistLength = OSSwapInt32(*((uint32_t *)update)); + if ((plistLength + (CFIndex)(sizeof(uint32_t)*2)) > (uint64_t) length) { + secdebug("validupdate", "ERROR: reported plist length (%lu)+%lu exceeds total length (%lu)\n", + (unsigned long)plistLength, (unsigned long)sizeof(uint32_t)*2, (unsigned long)length); + return false; + } + uint8_t *plistData = (uint8_t *)update + sizeof(uint32_t); + uint8_t *sigData = (uint8_t *)plistData + plistLength; + uint32_t sigLength = OSSwapInt32(*((uint32_t *)sigData)); + sigData += sizeof(uint32_t); + if ((plistLength + sigLength + (CFIndex)(sizeof(uint32_t) * 2)) != (uint64_t) length) { + secdebug("validupdate", "ERROR: reported lengths do not add up to total length\n"); + return false; + } + + OSStatus status = 0; + CMSSignerStatus signerStatus; + CMSDecoderRef cms = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CFDataRef content = NULL; + + if ((content = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + (const UInt8 *)plistData, (CFIndex)plistLength, kCFAllocatorNull)) == NULL) { + secdebug("validupdate", "CFDataCreateWithBytesNoCopy failed (%ld bytes)\n", (long)plistLength); + return false; + } + + if ((status = CMSDecoderCreate(&cms)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderCreate failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderUpdateMessage(cms, sigData, sigLength)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderUpdateMessage failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderSetDetachedContent(cms, content)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderSetDetachedContent failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderFinalizeMessage(cms)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderFinalizeMessage failed with error %d\n", (int)status); + goto verifyExit; + } + + policy = SecPolicyCreateApplePinned(CFSTR("ValidUpdate"), // kSecPolicyNameAppleValidUpdate + CFSTR("1.2.840.113635.100.6.2.10"), // System Integration 2 Intermediate Certificate + CFSTR("1.2.840.113635.100.6.51")); // Valid update signing OID + + // Check that the first signer actually signed this message. + if ((status = CMSDecoderCopySignerStatus(cms, 0, policy, + false, &signerStatus, &trust, NULL)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderCopySignerStatus failed with error %d\n", (int)status); + goto verifyExit; + } + // Make sure the signature verifies against the detached content + if (signerStatus != kCMSSignerValid) { + secdebug("validupdate", "ERROR: signature did not verify (signer status %d)\n", (int)signerStatus); + status = errSecInvalidSignature; + goto verifyExit; + } + // Make sure the signing certificate is valid for the specified policy + SecTrustResultType trustResult = kSecTrustResultInvalid; + status = SecTrustEvaluate(trust, &trustResult); + if (status != errSecSuccess) { + secdebug("validupdate", "SecTrustEvaluate failed with error %d (trust=%p)\n", (int)status, (void *)trust); + } else if (!(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) { + secdebug("validupdate", "SecTrustEvaluate failed with trust result %d\n", (int)trustResult); + status = errSecVerificationFailure; + goto verifyExit; + } + +verifyExit: + CFReleaseSafe(content); + CFReleaseSafe(trust); + CFReleaseSafe(policy); + CFReleaseSafe(cms); + + return (status == errSecSuccess); +} + +CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval) { + CFIndex interval = updateInterval; + // try to use interval preference if it exists + CFTypeRef value = (CFNumberRef)CFPreferencesCopyValue(kUpdateIntervalKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isNumber(value)) { + CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); + } + CFReleaseNull(value); + + if (interval <= 0) { + interval = kSecStdUpdateInterval; + } + + // sanity check + if (interval < kSecMinUpdateInterval) { + interval = kSecMinUpdateInterval; + } else if (interval > kSecMaxUpdateInterval) { + interval = kSecMaxUpdateInterval; + } + + // compute randomization factor, between 0 and 50% of the interval + CFIndex fuzz = arc4random() % (long)(interval/2.0); + CFAbsoluteTime nextUpdate = CFAbsoluteTimeGetCurrent() + interval + fuzz; + secdebug("validupdate", "next update in %ld seconds", (long)(interval + fuzz)); + return nextUpdate; +} + +void SecRevocationDbComputeAndSetNextUpdateTime(void) { + gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); + (void) SecRevocationDbSetNextUpdateTime(gNextUpdate, NULL); + gUpdateStarted = 0; /* no update is currently in progress */ +} + +bool SecRevocationDbIngestUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex chunkVersion, CFIndex *outVersion, CFErrorRef *error) { + bool ok = false; + CFIndex version = 0; + CFErrorRef localError = NULL; + if (!update) { + SecError(errSecParam, &localError, CFSTR("SecRevocationDbIngestUpdate: invalid update parameter")); + goto setVersionAndExit; + } + CFTypeRef value = (CFNumberRef)CFDictionaryGetValue(update, CFSTR("version")); + if (isNumber(value)) { + if (!CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &version)) { + version = 0; + } + } + if (version == 0) { + // only the first chunk will have a version, so the second and + // subsequent chunks will need to pass it in chunkVersion. + version = chunkVersion; + } + // check precommitted version since update hasn't been committed yet + CFIndex curVersion = dbc->precommitVersion; + if (version > curVersion || chunkVersion > 0) { + ok = _SecRevocationDbApplyUpdate(dbc, update, version, &localError); + secdebug("validupdate", "_SecRevocationDbApplyUpdate=%s, v%ld, precommit=%ld, full=%s", + (ok) ? "1" : "0", (long)version, (long)dbc->precommitVersion, + (dbc->fullUpdate) ? "1" : "0"); + } else { + secdebug("validupdate", "we have v%ld, skipping update to v%ld", + (long)curVersion, (long)version); + version = -1; // invalid, so we know to skip subsequent chunks + ok = true; // this is not an error condition + } +setVersionAndExit: + if (outVersion) { + *outVersion = version; + } + (void) CFErrorPropagate(localError, error); + return ok; +} + + +/* Database schema */ + +/* admin table holds these key-value (or key-ival) pairs: + 'version' (integer) // version of database content + 'check_again' (double) // CFAbsoluteTime of next check (optional) + 'db_version' (integer) // version of database schema + 'db_hash' (blob) // SHA-256 database hash + --> entries in admin table are unique by text key + + issuers table holds map of issuing CA hashes to group identifiers: + groupid (integer) // associated group identifier in group ID table + issuer_hash (blob) // SHA-256 hash of issuer certificate (primary key) + --> entries in issuers table are unique by issuer_hash; + multiple issuer entries may have the same groupid! + + groups table holds records with these attributes: + groupid (integer) // ordinal ID associated with this group entry + flags (integer) // a bitmask of the following values: + kSecValidInfoComplete (0x00000001) set if we have all revocation info for this issuer group + kSecValidInfoCheckOCSP (0x00000002) set if must check ocsp for certs from this issuer group + kSecValidInfoKnownOnly (0x00000004) set if any CA from this issuer group must be in database + kSecValidInfoRequireCT (0x00000008) set if all certs from this issuer group must have SCTs + kSecValidInfoAllowlist (0x00000010) set if this entry describes valid certs (i.e. is allowed) + kSecValidInfoNoCACheck (0x00000020) set if this entry does not require an OCSP check to accept (deprecated) + kSecValidInfoOverridable (0x00000040) set if the trust status is recoverable and can be overridden + kSecValidInfoDateConstraints (0x00000080) set if this group has not-before or not-after constraints + kSecValidInfoNameConstraints (0x00000100) set if this group has name constraints in database + kSecValidInfoPolicyConstraints (0x00000200) set if this group has policy constraints in database + kSecValidInfoNoCAv2Check (0x00000400) set if this entry does not require an OCSP check to accept + format (integer) // an integer describing format of entries: + kSecValidInfoFormatUnknown (0) unknown format + kSecValidInfoFormatSerial (1) serial number, not greater than 20 bytes in length + kSecValidInfoFormatSHA256 (2) SHA-256 hash, 32 bytes in length + kSecValidInfoFormatNto1 (3) filter data blob of arbitrary length + data (blob) // Bloom filter data if format is 'nto1', otherwise NULL + policies (blob) // NULL, or uint8_t count value followed by array of int8_t policy values + --> entries in groups table are unique by groupid + + serials table holds serial number blobs with these attributes: + groupid (integer) // identifier for issuer group in the groups table + serial (blob) // serial number + --> entries in serials table are unique by serial and groupid + + hashes table holds SHA-256 hashes of certificates with these attributes: + groupid (integer) // identifier for issuer group in the groups table + sha256 (blob) // SHA-256 hash of subject certificate + --> entries in hashes table are unique by sha256 and groupid + + dates table holds notBefore and notAfter dates (as CFAbsoluteTime) with these attributes: + groupid (integer) // identifier for issuer group in the groups table (primary key) + notbefore (real) // issued certs are invalid if their notBefore is prior to this date + notafter (real) // issued certs are invalid after this date (or their notAfter, if earlier) + --> entries in dates table are unique by groupid, and only exist if kSecValidInfoDateConstraints is true + + */ +#define createTablesSQL CFSTR("CREATE TABLE IF NOT EXISTS admin(" \ + "key TEXT PRIMARY KEY NOT NULL," \ + "ival INTEGER NOT NULL," \ + "value BLOB" \ + ");" \ + "CREATE TABLE IF NOT EXISTS issuers(" \ + "groupid INTEGER NOT NULL," \ + "issuer_hash BLOB PRIMARY KEY NOT NULL" \ + ");" \ + "CREATE INDEX IF NOT EXISTS issuer_idx ON issuers(issuer_hash);" \ + "CREATE TABLE IF NOT EXISTS groups(" \ + "groupid INTEGER PRIMARY KEY AUTOINCREMENT," \ + "flags INTEGER," \ + "format INTEGER," \ + "data BLOB," \ + "policies BLOB" \ + ");" \ + "CREATE TABLE IF NOT EXISTS serials(" \ + "groupid INTEGER NOT NULL," \ + "serial BLOB NOT NULL," \ + "UNIQUE(groupid,serial)" \ + ");" \ + "CREATE TABLE IF NOT EXISTS hashes(" \ + "groupid INTEGER NOT NULL," \ + "sha256 BLOB NOT NULL," \ + "UNIQUE(groupid,sha256)" \ + ");" \ + "CREATE TABLE IF NOT EXISTS dates(" \ + "groupid INTEGER PRIMARY KEY NOT NULL," \ + "notbefore REAL," \ + "notafter REAL" \ + ");" \ + "CREATE TRIGGER IF NOT EXISTS group_del " \ + "BEFORE DELETE ON groups FOR EACH ROW " \ + "BEGIN " \ + "DELETE FROM serials WHERE groupid=OLD.groupid; " \ + "DELETE FROM hashes WHERE groupid=OLD.groupid; " \ + "DELETE FROM issuers WHERE groupid=OLD.groupid; " \ + "DELETE FROM dates WHERE groupid=OLD.groupid; " \ + "END;") + +#define selectGroupIdSQL CFSTR("SELECT DISTINCT groupid " \ + "FROM issuers WHERE issuer_hash=?") +#define selectVersionSQL CFSTR("SELECT ival FROM admin " \ + "WHERE key='version'") +#define selectDbVersionSQL CFSTR("SELECT ival FROM admin " \ + "WHERE key='db_version'") +#define selectDbFormatSQL CFSTR("SELECT ival FROM admin " \ + "WHERE key='db_format'") +#define selectDbHashSQL CFSTR("SELECT value FROM admin " \ + "WHERE key='db_hash'") +#define selectDbSourceSQL CFSTR("SELECT value FROM admin " \ + "WHERE key='db_source'") +#define selectNextUpdateSQL CFSTR("SELECT value FROM admin " \ + "WHERE key='check_again'") +#define selectUpdateIntervalSQL CFSTR("SELECT ival FROM admin " \ + "WHERE key='interval'") +#define selectGroupRecordSQL CFSTR("SELECT flags,format,data,policies " \ + "FROM groups WHERE groupid=?") +#define selectSerialRecordSQL CFSTR("SELECT rowid FROM serials " \ + "WHERE groupid=? AND serial=?") +#define selectDateRecordSQL CFSTR("SELECT notbefore,notafter FROM " \ + "dates WHERE groupid=?") +#define selectHashRecordSQL CFSTR("SELECT rowid FROM hashes " \ + "WHERE groupid=? AND sha256=?") +#define insertAdminRecordSQL CFSTR("INSERT OR REPLACE INTO admin " \ + "(key,ival,value) VALUES (?,?,?)") +#define insertIssuerRecordSQL CFSTR("INSERT OR REPLACE INTO issuers " \ + "(groupid,issuer_hash) VALUES (?,?)") +#define insertGroupRecordSQL CFSTR("INSERT OR REPLACE INTO groups " \ + "(groupid,flags,format,data,policies) VALUES (?,?,?,?,?)") +#define insertSerialRecordSQL CFSTR("INSERT OR REPLACE INTO serials " \ + "(groupid,serial) VALUES (?,?)") +#define deleteSerialRecordSQL CFSTR("DELETE FROM serials " \ + "WHERE groupid=? AND hex(serial) LIKE ?") +#define insertSha256RecordSQL CFSTR("INSERT OR REPLACE INTO hashes " \ + "(groupid,sha256) VALUES (?,?)") +#define deleteSha256RecordSQL CFSTR("DELETE FROM hashes " \ + "WHERE groupid=? AND hex(sha256) LIKE ?") +#define insertDateRecordSQL CFSTR("INSERT OR REPLACE INTO dates " \ + "(groupid,notbefore,notafter) VALUES (?,?,?)") +#define deleteGroupRecordSQL CFSTR("DELETE FROM groups " \ + "WHERE groupid=?") +#define deleteGroupIssuersSQL CFSTR("DELETE FROM issuers " \ + "WHERE groupid=?") +#define addPoliciesColumnSQL CFSTR("ALTER TABLE groups " \ + "ADD COLUMN policies BLOB") +#define updateGroupPoliciesSQL CFSTR("UPDATE OR IGNORE groups " \ + "SET policies=? WHERE groupid=?") + +#define updateConstraintsTablesSQL CFSTR("" \ +"CREATE TABLE IF NOT EXISTS dates(" \ + "groupid INTEGER PRIMARY KEY NOT NULL," \ + "notbefore REAL," \ + "notafter REAL" \ +");") + +#define updateGroupDeleteTriggerSQL CFSTR("" \ + "DROP TRIGGER IF EXISTS group_del;" \ + "CREATE TRIGGER group_del BEFORE DELETE ON groups FOR EACH ROW " \ + "BEGIN " \ + "DELETE FROM serials WHERE groupid=OLD.groupid; " \ + "DELETE FROM hashes WHERE groupid=OLD.groupid; " \ + "DELETE FROM issuers WHERE groupid=OLD.groupid; " \ + "DELETE FROM dates WHERE groupid=OLD.groupid; " \ + "END;") + +#define deleteAllEntriesSQL CFSTR("" \ + "DELETE FROM groups; " \ + "DELETE FROM admin WHERE key='version'; " \ + "DELETE FROM sqlite_sequence") + + +/* Database management */ + +static SecDbRef SecRevocationDbCreate(CFStringRef path) { + /* only the db owner should open a read-write connection. */ + __block bool readWrite = isDbOwner(); + mode_t mode = 0644; + + SecDbRef result = SecDbCreate(path, mode, readWrite, false, true, true, 1, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + __block bool ok = true; + if (readWrite) { + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + /* Create all database tables, indexes, and triggers. + * SecDbOpen will set auto_vacuum and journal_mode for us before we get called back.*/ + ok = ok && SecDbExec(dbconn, createTablesSQL, error); + *commit = ok; + }); + } + if (!ok || (error && *error)) { + CFIndex errCode = errSecInternalComponent; + if (error && *error) { + errCode = CFErrorGetCode(*error); + } + secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationCreate, TAFatalError, errCode); + } + return ok; + }); + + return result; +} + +static dispatch_once_t kSecRevocationDbOnce; +static SecRevocationDbRef kSecRevocationDb = NULL; + +static SecRevocationDbRef SecRevocationDbInit(CFStringRef db_name) { + SecRevocationDbRef rdb; + dispatch_queue_attr_t attr; + + require(rdb = (SecRevocationDbRef)malloc(sizeof(struct __SecRevocationDb)), errOut); + rdb->db = NULL; + rdb->update_queue = NULL; + rdb->updateInProgress = false; + rdb->unsupportedVersion = false; + rdb->changed = false; + + require(rdb->db = SecRevocationDbCreate(db_name), errOut); + attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0); + attr = dispatch_queue_attr_make_with_autorelease_frequency(attr, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM); + require(rdb->update_queue = dispatch_queue_create(NULL, attr), errOut); + require(rdb->info_cache_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut); + require(rdb->info_cache = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + rdb->info_cache_lock = OS_UNFAIR_LOCK_INIT; + + if (!isDbOwner()) { + /* register for changes signaled by the db owner instance */ + int out_token = 0; + notify_register_dispatch(kSecRevocationDbChanged, &out_token, rdb->update_queue, ^(int __unused token) { + secnotice("validupdate", "Got notification of database change"); + SecRevocationDbResetCaches(); + }); + } + return rdb; + +errOut: + secdebug("validupdate", "Failed to create db at \"%@\"", db_name); + if (rdb) { + if (rdb->update_queue) { + dispatch_release(rdb->update_queue); + } + CFReleaseSafe(rdb->db); + free(rdb); + } + return NULL; +} + +static CFStringRef SecRevocationDbCopyPath(void) { + CFURLRef revDbURL = NULL; + CFStringRef revInfoRelPath = NULL; + if ((revInfoRelPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), kSecRevocationDbFileName)) != NULL) { + revDbURL = SecCopyURLForFileInRevocationInfoDirectory(revInfoRelPath); + } + CFReleaseSafe(revInfoRelPath); + + CFStringRef revDbPath = NULL; + if (revDbURL) { + revDbPath = CFURLCopyFileSystemPath(revDbURL, kCFURLPOSIXPathStyle); + CFRelease(revDbURL); + } + return revDbPath; +} + +static void SecRevocationDbWith(void(^dbJob)(SecRevocationDbRef db)) { + dispatch_once(&kSecRevocationDbOnce, ^{ + CFStringRef dbPath = SecRevocationDbCopyPath(); + if (dbPath) { + kSecRevocationDb = SecRevocationDbInit(dbPath); + CFRelease(dbPath); + if (kSecRevocationDb && isDbOwner()) { + /* check and update schema immediately after database is opened */ + SecRevocationDbUpdateSchema(kSecRevocationDb); + } + } + }); + // Do pre job run work here (cancel idle timers etc.) + if (kSecRevocationDb->updateInProgress) { + return; // this would block since SecDb has an exclusive transaction lock + } + dbJob(kSecRevocationDb); + // Do post job run work here (gc timer, etc.) +} + +static bool SecRevocationDbPerformWrite(SecRevocationDbRef rdb, CFErrorRef *error, + bool(^writeJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)) { + __block bool ok = true; + __block CFErrorRef localError = NULL; + + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbTransaction(dbconn, kSecDbImmediateTransactionType, &localError, ^(bool *commit) { + SecRevocationDbConnectionRef dbc = SecRevocationDbConnectionInit(rdb, dbconn, &localError); + ok = ok && writeJob(dbc, &localError); + *commit = ok; + free(dbc); + }); + }); + ok &= CFErrorPropagate(localError, error); + return ok; +} + +static bool SecRevocationDbPerformRead(SecRevocationDbRef rdb, CFErrorRef *error, + bool(^readJob)(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError)) { + __block CFErrorRef localError = NULL; + __block bool ok = true; + + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + SecRevocationDbConnectionRef dbc = SecRevocationDbConnectionInit(rdb, dbconn, &localError); + ok = ok && readJob(dbc, &localError); + free(dbc); + }); + ok &= CFErrorPropagate(localError, error); + return ok; +} + +static SecRevocationDbConnectionRef SecRevocationDbConnectionInit(SecRevocationDbRef db, SecDbConnectionRef dbconn, CFErrorRef *error) { + SecRevocationDbConnectionRef dbc = NULL; + CFErrorRef localError = NULL; + + dbc = (SecRevocationDbConnectionRef)malloc(sizeof(struct __SecRevocationDbConnection)); + if (dbc) { + dbc->db = db; + dbc->dbconn = dbconn; + dbc->precommitVersion = (CFIndex)_SecRevocationDbGetVersion(dbc, &localError); + dbc->precommitDbVersion = (CFIndex)_SecRevocationDbGetSchemaVersion(db, dbc, &localError); + dbc->precommitInterval = 0; /* set only if we are explicitly given a new value */ + dbc->fullUpdate = false; + } + (void) CFErrorPropagate(localError, error); + return dbc; +} + +static CF_RETURNS_RETAINED CFDataRef createCacheKey(CFDataRef certHash, CFDataRef issuerHash) { + CFMutableDataRef concat = CFDataCreateMutableCopy(NULL, 0, certHash); + CFDataAppend(concat, issuerHash); + CFDataRef result = SecSHA256DigestCreateFromData(NULL, concat); + CFReleaseNull(concat); + return result; +} + +static CF_RETURNS_RETAINED SecValidInfoRef SecRevocationDbCacheRead(SecRevocationDbRef db, + SecCertificateRef certificate, + CFDataRef issuerHash) { + if (!db) { + return NULL; + } + SecValidInfoRef result = NULL; + if (!db || !db->info_cache || !db->info_cache_list) { + return result; + } + CFIndex ix = kCFNotFound; + CFDataRef certHash = SecCertificateCopySHA256Digest(certificate); + CFDataRef cacheKey = createCacheKey(certHash, issuerHash); + + os_unfair_lock_lock(&db->info_cache_lock); // grab the cache lock before using the cache + if (0 <= (ix = CFArrayGetFirstIndexOfValue(db->info_cache_list, + CFRangeMake(0, CFArrayGetCount(db->info_cache_list)), + cacheKey))) { + result = (SecValidInfoRef)CFDictionaryGetValue(db->info_cache, cacheKey); + // Verify this really is the right result + if (CFEqualSafe(result->certHash, certHash) && CFEqualSafe(result->issuerHash, issuerHash)) { + // Cache hit. Move the entry to the bottom of the list. + CFArrayRemoveValueAtIndex(db->info_cache_list, ix); + CFArrayAppendValue(db->info_cache_list, cacheKey); + secdebug("validcache", "cache hit: %@", cacheKey); + } else { + // Just remove this bad entry + CFArrayRemoveValueAtIndex(db->info_cache_list, ix); + CFDictionaryRemoveValue(db->info_cache, cacheKey); + secdebug("validcache", "cache remove bad: %@", cacheKey); + secnotice("validcache", "found a bad valid info cache entry at %ld", (long)ix); + } + } + CFRetainSafe(result); + os_unfair_lock_unlock(&db->info_cache_lock); + CFReleaseSafe(certHash); + CFReleaseSafe(cacheKey); + return result; +} + +static void SecRevocationDbCacheWrite(SecRevocationDbRef db, + SecValidInfoRef validInfo) { + if (!db || !validInfo || !db->info_cache || !db->info_cache_list) { + return; + } + + CFDataRef cacheKey = createCacheKey(validInfo->certHash, validInfo->issuerHash); + + os_unfair_lock_lock(&db->info_cache_lock); // grab the cache lock before using the cache + // check to make sure another thread didn't add this entry to the cache already + if (0 > CFArrayGetFirstIndexOfValue(db->info_cache_list, + CFRangeMake(0, CFArrayGetCount(db->info_cache_list)), + cacheKey)) { + CFDictionaryAddValue(db->info_cache, cacheKey, validInfo); + if (kSecRevocationDbCacheSize <= CFArrayGetCount(db->info_cache_list)) { + // Remove least recently used cache entry. + secdebug("validcache", "cache remove stale: %@", CFArrayGetValueAtIndex(db->info_cache_list, 0)); + CFDictionaryRemoveValue(db->info_cache, CFArrayGetValueAtIndex(db->info_cache_list, 0)); + CFArrayRemoveValueAtIndex(db->info_cache_list, 0); + } + CFArrayAppendValue(db->info_cache_list, cacheKey); + secdebug("validcache", "cache add: %@", cacheKey); + } + os_unfair_lock_unlock(&db->info_cache_lock); + CFReleaseNull(cacheKey); +} + +static void SecRevocationDbCachePurge(SecRevocationDbRef db) { + if (!db || !db->info_cache || !db->info_cache_list) { + return; + } + + /* grab the cache lock and clear all entries */ + os_unfair_lock_lock(&db->info_cache_lock); + CFArrayRemoveAllValues(db->info_cache_list); + CFDictionaryRemoveAllValues(db->info_cache); + secdebug("validcache", "cache purge"); + os_unfair_lock_unlock(&db->info_cache_lock); +} + +static int64_t _SecRevocationDbGetUpdateInterval(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up interval entry in admin table; returns -1 on error */ + __block int64_t interval = -1; + __block bool ok = true; + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectUpdateIntervalSQL, &localError, ^bool(sqlite3_stmt *selectInterval) { + ok = ok && SecDbStep(dbc->dbconn, selectInterval, &localError, ^void(bool *stop) { + interval = sqlite3_column_int64(selectInterval, 0); + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbGetUpdateInterval failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return interval; +} + +static bool _SecRevocationDbSetUpdateInterval(SecRevocationDbConnectionRef dbc, int64_t interval, CFErrorRef *error) { + secdebug("validupdate", "setting interval to %lld", interval); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertInterval) { + const char *intervalKey = "interval"; + ok = ok && SecDbBindText(insertInterval, 1, intervalKey, strlen(intervalKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertInterval, 2, + (sqlite3_int64)interval, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertInterval, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetUpdateInterval failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static CFArrayRef _SecRevocationDbCopyHashes(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* return a retained copy of the db_hash array stored in the admin table; or NULL on error */ + __block CFMutableArrayRef hashes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + __block bool ok = (dbc && hashes); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectDbHashSQL, &localError, ^bool(sqlite3_stmt *selectDbHash) { + ok = ok && SecDbStep(dbc->dbconn, selectDbHash, &localError, ^void(bool *stop) { + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectDbHash, 0); + uint64_t len = sqlite3_column_bytes(selectDbHash, 0); + CFIndex hashLen = CC_SHA256_DIGEST_LENGTH; + while (p && len >= (uint64_t)hashLen) { + CFDataRef hash = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)p, hashLen); + if (hash) { + CFArrayAppendValue(hashes, hash); + CFReleaseNull(hash); + } + len -= hashLen; + p += hashLen; + } + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + CFReleaseNull(hashes); + } + (void) CFErrorPropagate(localError, error); + return hashes; +} + +static bool _SecRevocationDbSetHashes(SecRevocationDbConnectionRef dbc, CFArrayRef hashes, CFErrorRef *error) { + /* flatten and store db_hash array in the admin table */ + __block CFErrorRef localError = NULL; + __block bool ok = (dbc && hashes); + + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertHashes) { + CFIndex count = CFArrayGetCount(hashes); + CFIndex hashLen = CC_SHA256_DIGEST_LENGTH, dataLen = hashLen * count; + uint8_t *dataPtr = (uint8_t *)calloc(dataLen, 1); + uint8_t *p = dataPtr; + for (CFIndex idx = 0; idx < count && p; idx++) { + CFDataRef hash = CFArrayGetValueAtIndex(hashes, idx); + uint8_t *h = (hash) ? (uint8_t *)CFDataGetBytePtr(hash) : NULL; + if (h && CFDataGetLength(hash) == hashLen) { memcpy(p, h, hashLen); } + p += hashLen; + } + const char *hashKey = "db_hash"; + ok = ok && SecDbBindText(insertHashes, 1, hashKey, strlen(hashKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertHashes, 2, + (sqlite3_int64)0, &localError); + ok = ok && SecDbBindBlob(insertHashes, 3, + dataPtr, dataLen, + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertHashes, &localError, NULL); + free(dataPtr); + return ok; + }); + if (!ok || localError) { + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static int64_t _SecRevocationDbGetVersion(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up version entry in admin table; returns -1 on error */ + __block int64_t version = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectVersionSQL, &localError, ^bool(sqlite3_stmt *selectVersion) { + ok = ok && SecDbStep(dbc->dbconn, selectVersion, &localError, ^void(bool *stop) { + version = sqlite3_column_int64(selectVersion, 0); + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbGetVersion failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return version; +} + +static bool _SecRevocationDbSetVersion(SecRevocationDbConnectionRef dbc, CFIndex version, CFErrorRef *error) { + secdebug("validupdate", "setting version to %ld", (long)version); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertVersion) { + const char *versionKey = "version"; + ok = ok && SecDbBindText(insertVersion, 1, versionKey, strlen(versionKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertVersion, 2, + (sqlite3_int64)version, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertVersion, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetVersion failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static int64_t _SecRevocationDbReadSchemaVersionFromDb(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up db_version entry in admin table; returns -1 on error */ + __block int64_t db_version = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectDbVersionSQL, &localError, ^bool(sqlite3_stmt *selectDbVersion) { + ok = ok && SecDbStep(dbc->dbconn, selectDbVersion, &localError, ^void(bool *stop) { + db_version = sqlite3_column_int64(selectDbVersion, 0); + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbReadSchemaVersionFromDb failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return db_version; +} + +static _Atomic int64_t gSchemaVersion = -1; +static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef rdb, SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (dbc) { + atomic_init(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, error)); + } else { + (void) SecRevocationDbPerformRead(rdb, error, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + atomic_init(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); + return true; + }); + } + }); + if (atomic_load(&gSchemaVersion) == -1) { + /* Initial read(s) failed. Try to read the schema version again. */ + if (dbc) { + atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, error)); + } else { + (void) SecRevocationDbPerformRead(rdb, error, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); + return true; + }); + } + } + return atomic_load(&gSchemaVersion); +} + +static void SecRevocationDbResetCaches(void) { + SecRevocationDbWith(^(SecRevocationDbRef db) { + db->unsupportedVersion = false; + db->changed = false; + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + atomic_store(&gSchemaVersion, _SecRevocationDbReadSchemaVersionFromDb(dbc, blockError)); + return true; + }); + SecRevocationDbCachePurge(db); + }); +} + +static bool _SecRevocationDbSetSchemaVersion(SecRevocationDbConnectionRef dbc, CFIndex dbversion, CFErrorRef *error) { + if (dbversion > 0) { + int64_t db_version = (dbc) ? dbc->precommitDbVersion : -1; + if (db_version >= dbversion) { + return true; /* requested schema is earlier than current schema */ + } + } + secdebug("validupdate", "setting db_version to %ld", (long)dbversion); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbVersion) { + const char *dbVersionKey = "db_version"; + ok = ok && SecDbBindText(insertDbVersion, 1, dbVersionKey, strlen(dbVersionKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertDbVersion, 2, + (sqlite3_int64)dbversion, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertDbVersion, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetSchemaVersion failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } else { + dbc->db->changed = true; /* will notify clients of this change */ + dbc->db->unsupportedVersion = false; + dbc->precommitDbVersion = dbversion; + atomic_store(&gSchemaVersion, (int64_t)dbversion); + } + CFReleaseSafe(localError); + return ok; +} + +static bool _SecRevocationDbUpdateSchema(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + __block int64_t db_version = (dbc) ? dbc->precommitDbVersion : 0; + if (db_version >= kSecRevocationDbSchemaVersion) { + return ok; /* schema version already up to date */ + } + secdebug("validupdate", "updating db schema from v%lld to v%lld", + (long long)db_version, (long long)kSecRevocationDbSchemaVersion); + + if (ok && db_version < 5) { + /* apply v5 changes (add dates table and replace trigger) */ + ok &= SecDbWithSQL(dbc->dbconn, updateConstraintsTablesSQL, &localError, ^bool(sqlite3_stmt *updateTables) { + ok = SecDbStep(dbc->dbconn, updateTables, &localError, NULL); + return ok; + }); + ok &= SecDbWithSQL(dbc->dbconn, updateGroupDeleteTriggerSQL, &localError, ^bool(sqlite3_stmt *updateTrigger) { + ok = SecDbStep(dbc->dbconn, updateTrigger, &localError, NULL); + return ok; + }); + secdebug("validupdate", "applied schema update to v5 (%s)", (ok) ? "ok" : "failed!"); + } + if (ok && db_version < 6) { + /* apply v6 changes (the SecDb layer will update autovacuum mode if needed, so we don't execute + any SQL here, but we do want the database to be replaced in case transaction scope problems + with earlier versions caused missing entries.) */ + secdebug("validupdate", "applied schema update to v6 (%s)", (ok) ? "ok" : "failed!"); + if (db_version > 0) { + SecValidUpdateForceReplaceDatabase(); + } + } + if (ok && db_version < 7) { + /* apply v7 changes (add policies column in groups table) */ + ok &= SecDbWithSQL(dbc->dbconn, addPoliciesColumnSQL, &localError, ^bool(sqlite3_stmt *addPoliciesColumn) { + ok = SecDbStep(dbc->dbconn, addPoliciesColumn, &localError, NULL); + return ok; + }); + secdebug("validupdate", "applied schema update to v7 (%s)", (ok) ? "ok" : "failed!"); + } + + if (!ok) { + secerror("_SecRevocationDbUpdateSchema failed: %@", localError); + } else { + ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +bool SecRevocationDbUpdateSchema(SecRevocationDbRef rdb) { + /* note: this function assumes it is called only by the database owner. + non-owner (read-only) clients will fail if changes to the db are needed. */ + if (!rdb || !rdb->db) { + return false; + } + __block bool ok = true; + __block CFErrorRef localError = NULL; + ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + return _SecRevocationDbUpdateSchema(dbc, blockError); + }); + CFReleaseSafe(localError); + return ok; +} + +static int64_t _SecRevocationDbGetUpdateFormat(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up db_format entry in admin table; returns -1 on error */ + __block int64_t db_format = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectDbFormatSQL, &localError, ^bool(sqlite3_stmt *selectDbFormat) { + ok &= SecDbStep(dbc->dbconn, selectDbFormat, &localError, ^void(bool *stop) { + db_format = sqlite3_column_int64(selectDbFormat, 0); + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbGetUpdateFormat failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return db_format; +} + +static bool _SecRevocationDbSetUpdateFormat(SecRevocationDbConnectionRef dbc, CFIndex dbformat, CFErrorRef *error) { + secdebug("validupdate", "setting db_format to %ld", (long)dbformat); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbFormat) { + const char *dbFormatKey = "db_format"; + ok = ok && SecDbBindText(insertDbFormat, 1, dbFormatKey, strlen(dbFormatKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertDbFormat, 2, + (sqlite3_int64)dbformat, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertDbFormat, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetUpdateFormat failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } else { + dbc->db->changed = true; /* will notify clients of this change */ + dbc->db->unsupportedVersion = false; + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static CFStringRef _SecRevocationDbCopyUpdateSource(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up db_source entry in admin table; returns NULL on error */ + __block CFStringRef updateSource = NULL; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectDbSourceSQL, &localError, ^bool(sqlite3_stmt *selectDbSource) { + ok &= SecDbStep(dbc->dbconn, selectDbSource, &localError, ^void(bool *stop) { + const UInt8 *p = (const UInt8 *)sqlite3_column_blob(selectDbSource, 0); + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectDbSource, 0); + if (length > 0) { + updateSource = CFStringCreateWithBytes(kCFAllocatorDefault, p, length, kCFStringEncodingUTF8, false); + } + } + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbCopyUpdateSource failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return updateSource; +} + +bool _SecRevocationDbSetUpdateSource(SecRevocationDbConnectionRef dbc, CFStringRef updateSource, CFErrorRef *error) { + if (!updateSource) { + secerror("_SecRevocationDbSetUpdateSource failed: %d", errSecParam); + return false; + } + __block char buffer[256]; + __block const char *updateSourceCStr = CFStringGetCStringPtr(updateSource, kCFStringEncodingUTF8); + if (!updateSourceCStr) { + if (CFStringGetCString(updateSource, buffer, 256, kCFStringEncodingUTF8)) { + updateSourceCStr = buffer; + } + } + if (!updateSourceCStr) { + secerror("_SecRevocationDbSetUpdateSource failed: unable to get UTF-8 encoding"); + return false; + } + secdebug("validupdate", "setting update source to \"%s\"", updateSourceCStr); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { + const char *dbSourceKey = "db_source"; + ok = ok && SecDbBindText(insertRecord, 1, dbSourceKey, strlen(dbSourceKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertRecord, 2, + (sqlite3_int64)0, &localError); + ok = ok && SecDbBindBlob(insertRecord, 3, + updateSourceCStr, strlen(updateSourceCStr), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertRecord, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetUpdateSource failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + CFReleaseSafe(localError); + return ok; +} + +bool SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef updateSource) { + /* note: this function assumes it is called only by the database owner. + non-owner (read-only) clients will fail if changes to the db are needed. */ + if (!rdb || !rdb->db) { + return false; + } + CFErrorRef localError = NULL; + bool ok = true; + ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + return _SecRevocationDbSetUpdateSource(dbc, updateSource, error); + }); + CFReleaseSafe(localError); + return ok; +} + +static CFAbsoluteTime _SecRevocationDbGetNextUpdateTime(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* look up check_again entry in admin table; returns 0 on error */ + __block CFAbsoluteTime nextUpdate = 0; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectNextUpdateSQL, &localError, ^bool(sqlite3_stmt *selectNextUpdate) { + ok &= SecDbStep(dbc->dbconn, selectNextUpdate, &localError, ^void(bool *stop) { + CFAbsoluteTime *p = (CFAbsoluteTime *)sqlite3_column_blob(selectNextUpdate, 0); + if (p != NULL) { + if (sizeof(CFAbsoluteTime) == sqlite3_column_bytes(selectNextUpdate, 0)) { + nextUpdate = *p; + } + } + *stop = true; + }); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbGetNextUpdateTime failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return nextUpdate; +} + +static bool _SecRevocationDbSetNextUpdateTime(SecRevocationDbConnectionRef dbc, CFAbsoluteTime nextUpdate, CFErrorRef *error){ + secdebug("validupdate", "setting next update to %f", (double)nextUpdate); + + __block CFErrorRef localError = NULL; + __block bool ok = (dbc != NULL); + ok = ok && SecDbWithSQL(dbc->dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { + const char *nextUpdateKey = "check_again"; + ok = ok && SecDbBindText(insertRecord, 1, nextUpdateKey, strlen(nextUpdateKey), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(insertRecord, 2, + (sqlite3_int64)0, &localError); + ok = ok && SecDbBindBlob(insertRecord, 3, + &nextUpdate, sizeof(CFAbsoluteTime), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertRecord, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbSetNextUpdate failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +bool _SecRevocationDbRemoveAllEntries(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + /* clear out the contents of the database and start fresh */ + bool ok = (dbc != NULL); + CFErrorRef localError = NULL; + + /* _SecRevocationDbUpdateSchema was called when db was opened, so no need to do it again. */ + + /* delete all entries */ + ok = ok && SecDbExec(dbc->dbconn, deleteAllEntriesSQL, &localError); + secnotice("validupdate", "resetting database, result: %d (expected 1)", (ok) ? 1 : 0); + + /* one more thing: update the schema version and format to current */ + ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); + ok = ok && _SecRevocationDbSetUpdateFormat(dbc, kSecRevocationDbUpdateFormat, &localError); + + if (!ok || localError) { + secerror("_SecRevocationDbRemoveAllEntries failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbUpdateIssuers(SecRevocationDbConnectionRef dbc, int64_t groupId, CFArrayRef issuers, CFErrorRef *error) { + /* insert or replace issuer records in issuers table */ + if (!issuers || groupId < 0) { + return false; /* must have something to insert, and a group to associate with it */ + } + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + if (isArray(issuers)) { + CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers); + for (issuerIX=0; issuerIXdbconn, insertIssuerRecordSQL, &localError, ^bool(sqlite3_stmt *insertIssuer) { + ok = ok && SecDbBindInt64(insertIssuer, 1, + groupId, &localError); + ok = ok && SecDbBindBlob(insertIssuer, 2, + CFDataGetBytePtr(hash), + CFDataGetLength(hash), + SQLITE_TRANSIENT, &localError); + /* Execute the insert statement for this issuer record. */ + ok = ok && SecDbStep(dbc->dbconn, insertIssuer, &localError, NULL); + return ok; + }); + } + } + if (!ok || localError) { + secerror("_SecRevocationDbUpdateIssuers failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static SecValidInfoFormat _SecRevocationDbGetGroupFormatForData(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDataRef data) { + /* determine existing format if groupId is supplied and this is a partial update, + otherwise return the expected format for the given data. */ + SecValidInfoFormat format = kSecValidInfoFormatUnknown; + if (groupId >= 0 && !dbc->fullUpdate) { + format = _SecRevocationDbGetGroupFormat(dbc, groupId, NULL, NULL, NULL, NULL); + } + if (format == kSecValidInfoFormatUnknown && data != NULL) { + /* group doesn't exist, so determine format based on length of specified data. + len <= 20 is a serial number (actually, <=37, but != 32.) + len==32 is a sha256 hash. otherwise: nto1. */ + CFIndex length = CFDataGetLength(data); + if (length == 32) { + format = kSecValidInfoFormatSHA256; + } else if (length <= 37) { + format = kSecValidInfoFormatSerial; + } else if (length > 0) { + format = kSecValidInfoFormatNto1; + } + } + return format; +} + +static bool _SecRevocationDbUpdateIssuerData(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* update/delete records in serials or hashes table. */ + if (!dict || groupId < 0) { + return false; /* must have something to insert, and a group to associate with it */ + } + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + /* process deletions */ + CFArrayRef deleteArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("delete")); + if (isArray(deleteArray)) { + SecValidInfoFormat format = kSecValidInfoFormatUnknown; + CFIndex processed=0, identifierIX, identifierCount = CFArrayGetCount(deleteArray); + for (identifierIX=0; identifierIXdbconn, sql, &localError, ^bool(sqlite3_stmt *deleteIdentifier) { + /* (groupid,serial|sha256) */ + CFDataRef hexData = cfToHexData(identifierData, true); + if (!hexData) { return false; } + ok = ok && SecDbBindInt64(deleteIdentifier, 1, + groupId, &localError); + ok = ok && SecDbBindBlob(deleteIdentifier, 2, + CFDataGetBytePtr(hexData), + CFDataGetLength(hexData), + SQLITE_TRANSIENT, &localError); + /* Execute the delete statement for the identifier record. */ + ok = ok && SecDbStep(dbc->dbconn, deleteIdentifier, &localError, NULL); + CFReleaseSafe(hexData); + return ok; + }); + if (ok) { ++processed; } + } +#if VERBOSE_LOGGING + secdebug("validupdate", "Processed %ld of %ld deletions for group %lld, result=%s", + processed, identifierCount, groupId, (ok) ? "true" : "false"); +#endif + } + /* process additions */ + CFArrayRef addArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("add")); + if (isArray(addArray)) { + SecValidInfoFormat format = kSecValidInfoFormatUnknown; + CFIndex processed=0, identifierIX, identifierCount = CFArrayGetCount(addArray); + for (identifierIX=0; identifierIXdbconn, sql, &localError, ^bool(sqlite3_stmt *insertIdentifier) { + /* rowid,(groupid,serial|sha256) */ + /* rowid is autoincremented and we never set it directly */ + ok = ok && SecDbBindInt64(insertIdentifier, 1, + groupId, &localError); + ok = ok && SecDbBindBlob(insertIdentifier, 2, + CFDataGetBytePtr(identifierData), + CFDataGetLength(identifierData), + SQLITE_TRANSIENT, &localError); + /* Execute the insert statement for the identifier record. */ + ok = ok && SecDbStep(dbc->dbconn, insertIdentifier, &localError, NULL); + return ok; + }); + if (ok) { ++processed; } + } +#if VERBOSE_LOGGING + secdebug("validupdate", "Processed %ld of %ld additions for group %lld, result=%s", + processed, identifierCount, groupId, (ok) ? "true" : "false"); +#endif + } + if (!ok || localError) { + secerror("_SecRevocationDbUpdatePerIssuerData failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbCopyDateConstraints(SecRevocationDbConnectionRef dbc, + int64_t groupId, CFDateRef *notBeforeDate, CFDateRef *notAfterDate, CFErrorRef *error) { + /* return true if one or both date constraints exist for a given groupId. + the actual constraints are optionally returned in output CFDateRef parameters. + caller is responsible for releasing date and error parameters, if provided. + */ + __block bool ok = (dbc != NULL); + __block CFDateRef localNotBefore = NULL; + __block CFDateRef localNotAfter = NULL; + __block CFErrorRef localError = NULL; + + ok = ok && SecDbWithSQL(dbc->dbconn, selectDateRecordSQL, &localError, ^bool(sqlite3_stmt *selectDates) { + /* (groupid,notbefore,notafter) */ + ok &= SecDbBindInt64(selectDates, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, selectDates, &localError, ^(bool *stop) { + /* if column has no value, its type will be SQLITE_NULL */ + if (SQLITE_NULL != sqlite3_column_type(selectDates, 0)) { + CFAbsoluteTime nb = (CFAbsoluteTime)sqlite3_column_double(selectDates, 0); + localNotBefore = CFDateCreate(NULL, nb); + } + if (SQLITE_NULL != sqlite3_column_type(selectDates, 1)) { + CFAbsoluteTime na = (CFAbsoluteTime)sqlite3_column_double(selectDates, 1); + localNotAfter = CFDateCreate(NULL, na); + } + }); + return ok; + }); + /* must have at least one date constraint to return true. + since date constraints are optional, not finding any should not log an error. */ + ok = ok && !localError && (localNotBefore != NULL || localNotAfter != NULL); + if (localError) { + secerror("_SecRevocationDbCopyDateConstraints failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + if (!ok) { + CFReleaseNull(localNotBefore); + CFReleaseNull(localNotAfter); + } + if (notBeforeDate) { + *notBeforeDate = localNotBefore; + } else { + CFReleaseSafe(localNotBefore); + } + if (notAfterDate) { + *notAfterDate = localNotAfter; + } else { + CFReleaseSafe(localNotAfter); + } + + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbUpdateDateConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* Called only from _SecRevocationDbUpdateIssuerConstraints. + Function assumes that the caller has checked the input arguments. + */ + __block bool ok = true; + __block CFErrorRef localError = NULL; + __block CFAbsoluteTime notBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ + __block CFAbsoluteTime notAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ + + CFDateRef notBeforeDate = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-before")); + CFDateRef notAfterDate = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-after")); + + if (isDate(notBeforeDate)) { + notBefore = CFDateGetAbsoluteTime(notBeforeDate); + } else { + notBeforeDate = NULL; + } + if (isDate(notAfterDate)) { + notAfter = CFDateGetAbsoluteTime(notAfterDate); + } else { + notAfterDate = NULL; + } + if (!(notBeforeDate || notAfterDate)) { + return ok; /* no dates supplied, so we have nothing to update for this issuer */ + } + + if (!(notBeforeDate && notAfterDate) && !dbc->fullUpdate) { + /* only one date was supplied, so check for existing date constraints */ + CFDateRef curNotBeforeDate = NULL; + CFDateRef curNotAfterDate = NULL; + if (_SecRevocationDbCopyDateConstraints(dbc, groupId, &curNotBeforeDate, + &curNotAfterDate, &localError)) { + if (!notBeforeDate) { + notBeforeDate = curNotBeforeDate; + notBefore = CFDateGetAbsoluteTime(notBeforeDate); + } else { + CFReleaseSafe(curNotBeforeDate); + } + if (!notAfterDate) { + notAfterDate = curNotAfterDate; + notAfter = CFDateGetAbsoluteTime(notAfterDate); + } else { + CFReleaseSafe(curNotAfterDate); + } + } + } + ok = ok && SecDbWithSQL(dbc->dbconn, insertDateRecordSQL, &localError, ^bool(sqlite3_stmt *insertDate) { + /* (groupid,notbefore,notafter) */ + ok = ok && SecDbBindInt64(insertDate, 1, groupId, &localError); + ok = ok && SecDbBindDouble(insertDate, 2, notBefore, &localError); + ok = ok && SecDbBindDouble(insertDate, 3, notAfter, &localError); + ok = ok && SecDbStep(dbc->dbconn, insertDate, &localError, NULL); + return ok; + }); + + if (!ok || localError) { + secinfo("validupdate", "_SecRevocationDbUpdateDateConstraints failed (ok=%s, localError=%@)", + (ok) ? "1" : "0", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbUpdatePolicyConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* Called only from _SecRevocationDbUpdateIssuerConstraints. + Function assumes that the caller has checked the input arguments. + */ + __block bool ok = true; + __block CFErrorRef localError = NULL; + CFArrayRef policies = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies")); + if (!isArray(policies)) { + return ok; /* no policies supplied, so nothing to update for this issuer */ + } + + __block CFDataRef data = createPoliciesData(policies); + ok = data && SecDbWithSQL(dbc->dbconn, updateGroupPoliciesSQL, &localError, ^bool(sqlite3_stmt *updatePolicies) { + /* (policies,groupid) */ + ok = ok && SecDbBindBlob(updatePolicies, 1, + CFDataGetBytePtr(data), + CFDataGetLength(data), + SQLITE_TRANSIENT, &localError); + ok = ok && SecDbBindInt64(updatePolicies, 2, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, updatePolicies, &localError, NULL); + return ok; + }); + CFReleaseSafe(data); + + if (!ok || localError) { + secinfo("validupdate", "_SecRevocationDbUpdatePolicyConstraints failed (ok=%s, localError=%@)", + (ok) ? "1" : "0", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbUpdateNameConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* Called only from _SecRevocationDbUpdateIssuerConstraints. + Function assumes that the caller has checked the input arguments. + */ + + /* %%% (TBI:9254570) update name constraint entries here */ + return true; +} + +static bool _SecRevocationDbUpdateIssuerConstraints(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* check input arguments */ + if (!dbc || !dict || groupId < 0) { + return false; + } + bool ok = true; + ok = ok && _SecRevocationDbUpdateDateConstraints(dbc, groupId, dict, error); + ok = ok && _SecRevocationDbUpdateNameConstraints(dbc, groupId, dict, error); + ok = ok && _SecRevocationDbUpdatePolicyConstraints(dbc, groupId, dict, error); + return ok; +} + +static SecValidInfoFormat _SecRevocationDbGetGroupFormat(SecRevocationDbConnectionRef dbc, + int64_t groupId, SecValidInfoFlags *flags, CFDataRef *data, CFDataRef *policies, CFErrorRef *error) { + /* return group record fields for a given groupId. + on success, returns a non-zero format type, and other field values in optional output parameters. + caller is responsible for releasing data, policies, and error parameters, if provided. + */ + __block bool ok = (dbc != NULL); + __block SecValidInfoFormat format = 0; + __block CFErrorRef localError = NULL; + + /* Select the group record to determine flags and format. */ + ok = ok && SecDbWithSQL(dbc->dbconn, selectGroupRecordSQL, &localError, ^bool(sqlite3_stmt *selectGroup) { + ok = ok && SecDbBindInt64(selectGroup, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, selectGroup, &localError, ^(bool *stop) { + if (flags) { + *flags = (SecValidInfoFlags)sqlite3_column_int(selectGroup, 0); + } + format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); + if (data) { + //%%% stream the data from the db into a streamed decompression + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); + if (p != NULL && format == kSecValidInfoFormatNto1) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); + *data = CFDataCreate(kCFAllocatorDefault, p, length); + } + } + if (policies) { + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 3); + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 3); + *policies = CFDataCreate(kCFAllocatorDefault, p, length); + } + } + }); + return ok; + }); + if (!ok || localError) { + secdebug("validupdate", "GetGroupFormat for groupId %lu failed", (unsigned long)groupId); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + format = kSecValidInfoFormatUnknown; + } + (void) CFErrorPropagate(localError, error); + if (!(format > kSecValidInfoFormatUnknown)) { + secdebug("validupdate", "GetGroupFormat: got format %d for groupId %lld", format, (long long)groupId); + } + return format; +} + +static bool _SecRevocationDbUpdateFlags(CFDictionaryRef dict, CFStringRef key, SecValidInfoFlags mask, SecValidInfoFlags *flags) { + /* If a boolean value exists in the given dictionary for the given key, + or an explicit "1" or "0" is specified as the key string, + set or clear the corresponding bit(s) defined by the mask argument. + Function returns true if the flags value was changed, false otherwise. + */ + if (!isDictionary(dict) || !isString(key) || !flags) { + return false; + } + bool hasValue = false, newValue = false, result = false; + CFTypeRef value = (CFBooleanRef)CFDictionaryGetValue(dict, key); + if (isBoolean(value)) { + newValue = CFBooleanGetValue((CFBooleanRef)value); + hasValue = true; + } else if (BOOL_STRING_KEY_LENGTH == CFStringGetLength(key)) { + if (CFStringCompare(key, kBoolTrueKey, 0) == kCFCompareEqualTo) { + hasValue = newValue = true; + } else if (CFStringCompare(key, kBoolFalseKey, 0) == kCFCompareEqualTo) { + hasValue = true; + } + } + if (hasValue) { + SecValidInfoFlags oldFlags = *flags; + if (newValue) { + *flags |= mask; + } else { + *flags &= ~(mask); + } + result = (*flags != oldFlags); + } + return result; +} + +static bool _SecRevocationDbUpdateFilter(CFDictionaryRef dict, CFDataRef oldData, CFDataRef * __nonnull CF_RETURNS_RETAINED xmlData) { + /* If xor and/or params values exist in the given dictionary, create a new + property list containing the updated values, and return as a flattened + data blob in the xmlData output parameter (note: caller must release.) + Function returns true if there is new xmlData to save, false otherwise. + */ + bool result = false; + bool xorProvided = false; + bool paramsProvided = false; + bool missingData = false; + + if (!dict || !xmlData) { + return result; /* no-op if no dictionary is provided, or no way to update the data */ + } + *xmlData = NULL; + CFDataRef xorCurrent = NULL; + CFDataRef xorUpdate = (CFDataRef)CFDictionaryGetValue(dict, CFSTR("xor")); + if (isData(xorUpdate)) { + xorProvided = true; + } + CFArrayRef paramsCurrent = NULL; + CFArrayRef paramsUpdate = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("params")); + if (isArray(paramsUpdate)) { + paramsProvided = true; + } + if (!(xorProvided || paramsProvided)) { + return result; /* nothing to update, so we can bail out here. */ + } + + CFPropertyListRef nto1Current = NULL; + CFMutableDictionaryRef nto1Update = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!nto1Update) { + return result; + } + + /* turn old data into property list */ + CFDataRef data = (CFDataRef)CFRetainSafe(oldData); + CFDataRef inflatedData = copyInflatedData(data); + if (inflatedData) { + CFReleaseSafe(data); + data = inflatedData; + } + if (data) { + nto1Current = CFPropertyListCreateWithData(kCFAllocatorDefault, data, 0, NULL, NULL); + CFReleaseSafe(data); + } + if (nto1Current) { + xorCurrent = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("xor")); + paramsCurrent = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("params")); + } + + /* set current or updated xor data in new property list */ + if (xorProvided) { + CFDataRef xorNew = NULL; + if (xorCurrent) { + CFIndex xorUpdateLen = CFDataGetLength(xorUpdate); + CFMutableDataRef xor = CFDataCreateMutableCopy(NULL, 0, xorCurrent); + if (xor && xorUpdateLen > 0) { + /* truncate or zero-extend data to match update size */ + CFDataSetLength(xor, xorUpdateLen); + /* exclusive-or update bytes over the existing data */ + UInt8 *xorP = (UInt8 *)CFDataGetMutableBytePtr(xor); + UInt8 *updP = (UInt8 *)CFDataGetBytePtr(xorUpdate); + if (xorP && updP) { + for (int idx = 0; idx < xorUpdateLen; idx++) { + xorP[idx] = xorP[idx] ^ updP[idx]; + } + } + } + xorNew = (CFDataRef)xor; + } else { + xorNew = (CFDataRef)CFRetainSafe(xorUpdate); + } + if (xorNew) { + CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorNew); + CFReleaseSafe(xorNew); + } else { + secdebug("validupdate", "Failed to get updated filter data"); + missingData = true; + } + } else if (xorCurrent) { + /* not provided, so use existing xor value */ + CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorCurrent); + } else { + secdebug("validupdate", "Failed to get current filter data"); + missingData = true; + } + + /* set current or updated params in new property list */ + if (paramsProvided) { + CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsUpdate); + } else if (paramsCurrent) { + /* not provided, so use existing params value */ + CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsCurrent); + } else { + /* missing params: neither provided nor existing */ + secdebug("validupdate", "Failed to get current filter params"); + missingData = true; + } + + CFReleaseSafe(nto1Current); + if (!missingData) { + *xmlData = CFPropertyListCreateData(kCFAllocatorDefault, nto1Update, + kCFPropertyListXMLFormat_v1_0, + 0, NULL); + result = (*xmlData != NULL); + } + CFReleaseSafe(nto1Update); + + /* compress the xmlData blob, if possible */ + if (result) { + CFDataRef deflatedData = copyDeflatedData(*xmlData); + if (deflatedData) { + if (CFDataGetLength(deflatedData) < CFDataGetLength(*xmlData)) { + CFRelease(*xmlData); + *xmlData = deflatedData; + } else { + CFRelease(deflatedData); + } + } + } + return result; +} + + +static int64_t _SecRevocationDbUpdateGroup(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* insert group record for a given groupId. + if the specified groupId is < 0, a new group entry is created. + returns the groupId on success, or -1 on failure. + */ + if (!dict) { + return groupId; /* no-op if no dictionary is provided */ + } + + __block int64_t result = -1; + __block bool ok = (dbc != NULL); + __block bool isFormatChange = false; + __block CFErrorRef localError = NULL; + + __block SecValidInfoFlags flags = 0; + __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; + __block SecValidInfoFormat formatUpdate = kSecValidInfoFormatUnknown; + __block CFDataRef data = NULL; + __block CFDataRef policies = NULL; + + if (groupId >= 0) { + /* fetch the flags and data for an existing group record, in case some are being changed. */ + if (ok) { + format = _SecRevocationDbGetGroupFormat(dbc, groupId, &flags, &data, &policies, NULL); + } + if (format == kSecValidInfoFormatUnknown) { + secdebug("validupdate", "existing group %lld has unknown format %d, flags=0x%lx", + (long long)groupId, format, flags); + //%%% clean up by deleting all issuers with this groupId, then the group record, + // or just force a full update? note: we can get here if we fail to bind the + // format value in the prepared SQL statement below. + return -1; + } + } + CFTypeRef value = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("format")); + if (isString(value)) { + if (CFStringCompare((CFStringRef)value, CFSTR("serial"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatSerial; + } else if (CFStringCompare((CFStringRef)value, CFSTR("sha256"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatSHA256; + } else if (CFStringCompare((CFStringRef)value, CFSTR("nto1"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatNto1; + } + } + /* if format value is explicitly supplied, then this is effectively a new group entry. */ + isFormatChange = (formatUpdate > kSecValidInfoFormatUnknown && + formatUpdate != format && + groupId >= 0); + + if (isFormatChange) { + secdebug("validupdate", "group %lld format change from %d to %d", + (long long)groupId, format, formatUpdate); + /* format of an existing group is changing; delete the group first. + this should ensure that all entries referencing the old groupid are deleted. + */ + ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { + ok = ok && SecDbBindInt64(deleteResponse, 1, groupId, &localError); + /* Execute the delete statement. */ + ok = ok && SecDbStep(dbc->dbconn, deleteResponse, &localError, NULL); + return ok; + }); + } + ok = ok && SecDbWithSQL(dbc->dbconn, insertGroupRecordSQL, &localError, ^bool(sqlite3_stmt *insertGroup) { + /* (groupid,flags,format,data,policies) */ + /* groups.groupid */ + if (ok && (!isFormatChange) && (groupId >= 0)) { + /* bind to existing groupId row if known, otherwise will insert and autoincrement */ + ok = SecDbBindInt64(insertGroup, 1, groupId, &localError); + if (!ok) { + secdebug("validupdate", "failed to set groupId %lld", (long long)groupId); + } + } + /* groups.flags */ + if (ok) { + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("complete"), kSecValidInfoComplete, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("check-ocsp"), kSecValidInfoCheckOCSP, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("known-intermediates-only"), kSecValidInfoKnownOnly, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("require-ct"), kSecValidInfoRequireCT, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("valid"), kSecValidInfoAllowlist, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("no-ca"), kSecValidInfoNoCACheck, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("no-ca-v2"), kSecValidInfoNoCAv2Check, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("overridable"), kSecValidInfoOverridable, &flags); + + /* date constraints exist if either "not-before" or "not-after" keys are found */ + CFTypeRef notBeforeValue = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-before")); + CFTypeRef notAfterValue = (CFDateRef)CFDictionaryGetValue(dict, CFSTR("not-after")); + if (isDate(notBeforeValue) || isDate(notAfterValue)) { + (void)_SecRevocationDbUpdateFlags(dict, kBoolTrueKey, kSecValidInfoDateConstraints, &flags); + /* Note that the spec defines not-before and not-after dates as optional, such that + not providing one does not change the database contents. Therefore, we can never clear + this flag; either a new date entry will be supplied, or a format change will cause + the entire group entry to be deleted. */ + } + /* policy constraints exist if "policies" key is found */ + CFTypeRef policiesValue = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies")); + if (isArray(policiesValue)) { + (void)_SecRevocationDbUpdateFlags(dict, kBoolTrueKey, kSecValidInfoPolicyConstraints, &flags); + /* As above, not providing this value in an update does not change the existing state, + so we never need to clear this flag once it is set. */ + } + + /* %%% (TBI:9254570) name constraints don't exist yet */ + (void)_SecRevocationDbUpdateFlags(dict, kBoolFalseKey, kSecValidInfoNameConstraints, &flags); + + ok = SecDbBindInt(insertGroup, 2, (int)flags, &localError); + if (!ok) { + secdebug("validupdate", "failed to set flags (%lu) for groupId %lld", flags, (long long)groupId); + } + } + /* groups.format */ + if (ok) { + SecValidInfoFormat formatValue = format; + if (formatUpdate > kSecValidInfoFormatUnknown) { + formatValue = formatUpdate; + } + ok = SecDbBindInt(insertGroup, 3, (int)formatValue, &localError); + if (!ok) { + secdebug("validupdate", "failed to set format (%d) for groupId %lld", formatValue, (long long)groupId); + } + } + /* groups.data */ + CFDataRef xmlData = NULL; + if (ok) { + bool hasFilter = ((formatUpdate == kSecValidInfoFormatNto1) || + (formatUpdate == kSecValidInfoFormatUnknown && + format == kSecValidInfoFormatNto1)); + if (hasFilter) { + CFDataRef dataValue = data; /* use existing data */ + if (_SecRevocationDbUpdateFilter(dict, data, &xmlData)) { + dataValue = xmlData; /* use updated data */ + } + if (dataValue) { + ok = SecDbBindBlob(insertGroup, 4, + CFDataGetBytePtr(dataValue), + CFDataGetLength(dataValue), + SQLITE_TRANSIENT, &localError); + } + if (!ok) { + secdebug("validupdate", "failed to set data for groupId %lld", + (long long)groupId); + } + } + /* else there is no data, so NULL is implicitly bound to column 4 */ + } + /* groups.policies */ + CFDataRef newPoliciesData = NULL; + if (ok) { + CFDataRef policiesValue = policies; /* use existing policies */ + newPoliciesData = createPoliciesData((CFArrayRef)CFDictionaryGetValue(dict, CFSTR("policies"))); + if (newPoliciesData) { + policiesValue = newPoliciesData; /* use updated policies */ + } + if (policiesValue) { + ok = SecDbBindBlob(insertGroup, 5, + CFDataGetBytePtr(policiesValue), + CFDataGetLength(policiesValue), + SQLITE_TRANSIENT, &localError); + } + /* else there is no policy data, so NULL is implicitly bound to column 5 */ + if (!ok) { + secdebug("validupdate", "failed to set policies for groupId %lld", + (long long)groupId); + } + } + + /* Execute the insert statement for the group record. */ + if (ok) { + ok = SecDbStep(dbc->dbconn, insertGroup, &localError, NULL); + if (!ok) { + secdebug("validupdate", "failed to execute insertGroup statement for groupId %lld", + (long long)groupId); + } + result = (int64_t)sqlite3_last_insert_rowid(SecDbHandle(dbc->dbconn)); + } + if (!ok) { + secdebug("validupdate", "failed to insert group %lld", (long long)result); + } + /* Clean up temporary allocations made in this block. */ + CFReleaseSafe(xmlData); + CFReleaseSafe(newPoliciesData); + return ok; + }); + + CFReleaseSafe(data); + CFReleaseSafe(policies); + + if (!ok || localError) { + secerror("_SecRevocationDbUpdateGroup failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return result; +} + +static int64_t _SecRevocationDbGroupIdForIssuerHash(SecRevocationDbConnectionRef dbc, CFDataRef hash, CFErrorRef *error) { + /* look up issuer hash in issuers table to get groupid, if it exists */ + __block int64_t groupId = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + if (!hash) { + secdebug("validupdate", "failed to get hash (%@)", hash); + } + require(hash && dbc, errOut); + + /* This is the starting point for any lookup; find a group id for the given issuer hash. + Before we do that, need to verify the current db_version. We cannot use results from a + database created with a schema version older than the minimum supported version. + However, we may be able to use results from a newer version. At the next database + update interval, if the existing schema is old, we'll be removing and recreating + the database contents with the current schema version. + */ + int64_t db_version = _SecRevocationDbGetSchemaVersion(dbc->db, dbc, NULL); + if (db_version < kSecRevocationDbMinSchemaVersion) { + if (!dbc->db->unsupportedVersion) { + secdebug("validupdate", "unsupported db_version: %lld", (long long)db_version); + dbc->db->unsupportedVersion = true; /* only warn once for a given unsupported version */ + } + } + require_quiet(db_version >= kSecRevocationDbMinSchemaVersion, errOut); + + /* Look up provided issuer_hash in the issuers table. + */ + ok = ok && SecDbWithSQL(dbc->dbconn, selectGroupIdSQL, &localError, ^bool(sqlite3_stmt *selectGroupId) { + ok &= SecDbBindBlob(selectGroupId, 1, CFDataGetBytePtr(hash), CFDataGetLength(hash), SQLITE_TRANSIENT, &localError); + ok &= SecDbStep(dbc->dbconn, selectGroupId, &localError, ^(bool *stopGroupId) { + groupId = sqlite3_column_int64(selectGroupId, 0); + }); + return ok; + }); + +errOut: + if (!ok || localError) { + secerror("_SecRevocationDbGroupIdForIssuerHash failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return groupId; +} + +static bool _SecRevocationDbApplyGroupDelete(SecRevocationDbConnectionRef dbc, CFDataRef issuerHash, CFErrorRef *error) { + /* delete group associated with the given issuer; + schema trigger will delete associated issuers, serials, and hashes. */ + __block int64_t groupId = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + if (ok) { + groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, &localError); + } + if (groupId < 0) { + if (!localError) { + SecError(errSecParam, &localError, CFSTR("group not found for issuer")); + } + ok = false; + } + ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { + ok &= SecDbBindInt64(deleteResponse, 1, groupId, &localError); + /* Execute the delete statement. */ + ok = ok && SecDbStep(dbc->dbconn, deleteResponse, &localError, NULL); + return ok; + }); + if (!ok || localError) { + secerror("_SecRevocationDbApplyGroupDelete failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationWrite, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef dict, CFErrorRef *error) { + /* process one issuer group's update dictionary */ + __block int64_t groupId = -1; + __block bool ok = (dbc != NULL); + __block CFErrorRef localError = NULL; + + CFArrayRef issuers = (dict) ? (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("issuer-hash")) : NULL; + /* if this is not a full update, then look for existing group id */ + if (ok && isArray(issuers) && !dbc->fullUpdate) { + CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers); + /* while we have issuers and haven't found a matching group id */ + for (issuerIX=0; issuerIX= 0) { + /* according to the spec, we must replace all existing issuers with + the new issuers list, so delete all issuers in the group first. */ + ok = ok && SecDbWithSQL(dbc->dbconn, deleteGroupIssuersSQL, &localError, ^bool(sqlite3_stmt *deleteIssuers) { + ok = ok && SecDbBindInt64(deleteIssuers, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, deleteIssuers, &localError, NULL); + return ok; + }); + } + } + /* create or update the group entry */ + if (ok) { + groupId = _SecRevocationDbUpdateGroup(dbc, groupId, dict, &localError); + } + if (groupId < 0) { + secdebug("validupdate", "failed to get groupId"); + ok = false; + } else { + /* create or update issuer entries, now that we know the group id */ + ok = ok && _SecRevocationDbUpdateIssuers(dbc, groupId, issuers, &localError); + /* create or update entries in serials or hashes tables */ + ok = ok && _SecRevocationDbUpdateIssuerData(dbc, groupId, dict, &localError); + /* create or update entries in dates/names/policies tables */ + ok = ok && _SecRevocationDbUpdateIssuerConstraints(dbc, groupId, dict, &localError); + } + + (void) CFErrorPropagate(localError, error); + return ok; +} + +bool _SecRevocationDbApplyUpdate(SecRevocationDbConnectionRef dbc, CFDictionaryRef update, CFIndex version, CFErrorRef *error) { + /* process entire update dictionary */ + if (!dbc || !dbc->db || !update) { + secerror("_SecRevocationDbApplyUpdate failed: invalid args"); + SecError(errSecParam, error, CFSTR("_SecRevocationDbApplyUpdate: invalid db or update parameter")); + return false; + } + + CFDictionaryRef localUpdate = (CFDictionaryRef)CFRetainSafe(update); + CFErrorRef localError = NULL; + bool ok = true; + + CFTypeRef value = NULL; + CFIndex deleteCount = 0; + CFIndex updateCount = 0; + + dbc->db->updateInProgress = true; + + /* check whether this is a full update */ + value = (CFBooleanRef)CFDictionaryGetValue(update, CFSTR("full")); + if (isBoolean(value) && CFBooleanGetValue((CFBooleanRef)value)) { + /* clear the database before processing a full update */ + dbc->fullUpdate = true; + secdebug("validupdate", "update has \"full\" attribute; clearing database"); + ok = ok && _SecRevocationDbRemoveAllEntries(dbc, &localError); + } + + /* process 'delete' list */ + value = (CFArrayRef)CFDictionaryGetValue(localUpdate, CFSTR("delete")); + if (isArray(value)) { + deleteCount = CFArrayGetCount((CFArrayRef)value); + secdebug("validupdate", "processing %ld deletes", (long)deleteCount); + for (CFIndex deleteIX=0; deleteIXprecommitInterval) { + interval = (dbc->precommitInterval > 0) ? dbc->precommitInterval : kSecStdUpdateInterval; + ok = ok && _SecRevocationDbSetUpdateInterval(dbc, interval, &localError); + } + + /* set db_version if not already set */ + int64_t db_version = _SecRevocationDbGetSchemaVersion(dbc->db, dbc, NULL); + if (db_version <= 0) { + ok = ok && _SecRevocationDbSetSchemaVersion(dbc, kSecRevocationDbSchemaVersion, &localError); + } + + /* set db_format if not already set */ + int64_t db_format = _SecRevocationDbGetUpdateFormat(dbc, NULL); + if (db_format <= 0) { + ok = ok && _SecRevocationDbSetUpdateFormat(dbc, kSecRevocationDbUpdateFormat, &localError); + } + + /* purge the in-memory cache */ + SecRevocationDbCachePurge(dbc->db); + + dbc->db->updateInProgress = false; + + (void) CFErrorPropagate(localError, error); + return ok; +} + +static bool _SecRevocationDbSerialInGroup(SecRevocationDbConnectionRef dbc, + CFDataRef serial, + int64_t groupId, + CFErrorRef *error) { + __block bool result = false; + __block bool ok = true; + __block CFErrorRef localError = NULL; + require(dbc && serial, errOut); + ok &= SecDbWithSQL(dbc->dbconn, selectSerialRecordSQL, &localError, ^bool(sqlite3_stmt *selectSerial) { + ok &= SecDbBindInt64(selectSerial, 1, groupId, &localError); + ok &= SecDbBindBlob(selectSerial, 2, CFDataGetBytePtr(serial), + CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); + ok &= SecDbStep(dbc->dbconn, selectSerial, &localError, ^(bool *stop) { + int64_t foundRowId = (int64_t)sqlite3_column_int64(selectSerial, 0); + result = (foundRowId > 0); + }); + return ok; + }); + +errOut: + if (!ok || localError) { + secerror("_SecRevocationDbSerialInGroup failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return result; +} + +static bool _SecRevocationDbCertHashInGroup(SecRevocationDbConnectionRef dbc, + CFDataRef certHash, + int64_t groupId, + CFErrorRef *error) { + __block bool result = false; + __block bool ok = true; + __block CFErrorRef localError = NULL; + require(dbc && certHash, errOut); + ok &= SecDbWithSQL(dbc->dbconn, selectHashRecordSQL, &localError, ^bool(sqlite3_stmt *selectHash) { + ok &= SecDbBindInt64(selectHash, 1, groupId, &localError); + ok = SecDbBindBlob(selectHash, 2, CFDataGetBytePtr(certHash), + CFDataGetLength(certHash), SQLITE_TRANSIENT, &localError); + ok &= SecDbStep(dbc->dbconn, selectHash, &localError, ^(bool *stop) { + int64_t foundRowId = (int64_t)sqlite3_column_int64(selectHash, 0); + result = (foundRowId > 0); + }); + return ok; + }); + +errOut: + if (!ok || localError) { + secerror("_SecRevocationDbCertHashInGroup failed: %@", localError); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TARevocationDb, TAOperationRead, TAFatalError, + localError ? CFErrorGetCode(localError) : errSecInternalComponent); + } + (void) CFErrorPropagate(localError, error); + return result; +} + +static bool _SecRevocationDbSerialInFilter(SecRevocationDbConnectionRef dbc, + CFDataRef serialData, + CFDataRef xmlData) { + /* N-To-1 filter implementation. + The 'xmlData' parameter is a flattened XML dictionary, + containing 'xor' and 'params' keys. First order of + business is to reconstitute the blob into components. + */ + bool result = false; + CFRetainSafe(xmlData); + CFDataRef propListData = xmlData; + /* Expand data blob if needed */ + CFDataRef inflatedData = copyInflatedData(propListData); + if (inflatedData) { + CFReleaseSafe(propListData); + propListData = inflatedData; + } + CFDataRef xor = NULL; + CFArrayRef params = NULL; + CFPropertyListRef nto1 = CFPropertyListCreateWithData(kCFAllocatorDefault, propListData, 0, NULL, NULL); + if (nto1) { + xor = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("xor")); + params = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1, CFSTR("params")); + } + uint8_t *hash = (xor) ? (uint8_t*)CFDataGetBytePtr(xor) : NULL; + CFIndex hashLen = (hash) ? CFDataGetLength(xor) : 0; + uint8_t *serial = (serialData) ? (uint8_t*)CFDataGetBytePtr(serialData) : NULL; + CFIndex serialLen = (serial) ? CFDataGetLength(serialData) : 0; + + require(hash && serial && params, errOut); + + const uint32_t FNV_OFFSET_BASIS = 2166136261; + const uint32_t FNV_PRIME = 16777619; + bool notInHash = false; + CFIndex ix, count = CFArrayGetCount(params); + for (ix = 0; ix < count; ix++) { + int32_t param; + CFNumberRef cfnum = (CFNumberRef)CFArrayGetValueAtIndex(params, ix); + if (!isNumber(cfnum) || + !CFNumberGetValue(cfnum, kCFNumberSInt32Type, ¶m)) { + secinfo("validupdate", "error processing filter params at index %ld", (long)ix); + continue; + } + /* process one param */ + uint32_t hval = FNV_OFFSET_BASIS ^ param; + CFIndex i = serialLen; + while (i > 0) { + hval = ((hval ^ (serial[--i])) * FNV_PRIME) & 0xFFFFFFFF; + } + hval = hval % (hashLen * 8); + if ((hash[hval/8] & (1 << (hval % 8))) == 0) { + notInHash = true; /* definitely not in hash */ + break; + } + } + if (!notInHash) { + /* probabilistically might be in hash if we get here. */ + result = true; + } + +errOut: + CFReleaseSafe(nto1); + CFReleaseSafe(propListData); + return result; +} + +static SecValidInfoRef _SecRevocationDbValidInfoForCertificate(SecRevocationDbConnectionRef dbc, + SecCertificateRef certificate, + CFDataRef issuerHash, + CFErrorRef *error) { + __block CFErrorRef localError = NULL; + __block SecValidInfoFlags flags = 0; + __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; + __block CFDataRef data = NULL; + + bool matched = false; + bool isOnList = false; + int64_t groupId = 0; + CFDataRef serial = NULL; + CFDataRef certHash = NULL; + CFDateRef notBeforeDate = NULL; + CFDateRef notAfterDate = NULL; + CFDataRef names = NULL; + CFDataRef policies = NULL; + SecValidInfoRef result = NULL; + + require((serial = SecCertificateCopySerialNumberData(certificate, NULL)) != NULL, errOut); + require((certHash = SecCertificateCopySHA256Digest(certificate)) != NULL, errOut); + require_quiet((groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, &localError)) > 0, errOut); + + /* Look up the group record to determine flags and format. */ + format = _SecRevocationDbGetGroupFormat(dbc, groupId, &flags, &data, &policies, &localError); + + if (format == kSecValidInfoFormatUnknown) { + /* No group record found for this issuer. Don't return a SecValidInfoRef */ + goto errOut; + } + else if (format == kSecValidInfoFormatSerial) { + /* Look up certificate's serial number in the serials table. */ + matched = _SecRevocationDbSerialInGroup(dbc, serial, groupId, &localError); + } + else if (format == kSecValidInfoFormatSHA256) { + /* Look up certificate's SHA-256 hash in the hashes table. */ + matched = _SecRevocationDbCertHashInGroup(dbc, certHash, groupId, &localError); + } + else if (format == kSecValidInfoFormatNto1) { + /* Perform a Bloom filter match against the serial. If matched is false, + then the cert is definitely not in the list. But if matched is true, + we don't know for certain, so we would need to check OCSP. */ + matched = _SecRevocationDbSerialInFilter(dbc, serial, data); + } + + if (matched) { + /* Found a specific match for this certificate. */ + secdebug("validupdate", "Valid db matched certificate: %@, format=%d, flags=0x%lx", + certHash, format, flags); + isOnList = true; + } + + /* If supplemental constraints are present for this issuer, then we always match. */ + if ((flags & kSecValidInfoDateConstraints) && + (_SecRevocationDbCopyDateConstraints(dbc, groupId, ¬BeforeDate, ¬AfterDate, &localError))) { + secdebug("validupdate", "Valid db matched supplemental date constraints for groupId %lld: nb=%@, na=%@", + (long long)groupId, notBeforeDate, notAfterDate); + } + + + /* Return SecValidInfo for certificates for which an issuer entry is found. */ + result = SecValidInfoCreate(format, flags, isOnList, + certHash, issuerHash, /*anchorHash*/ NULL, + notBeforeDate, notAfterDate, + names, policies); + + if (result && SecIsAppleTrustAnchor(certificate, 0)) { + /* Prevent a catch-22. */ + secdebug("validupdate", "Valid db match for Apple trust anchor: %@, format=%d, flags=0x%lx", + certHash, format, flags); + CFReleaseNull(result); + } + +errOut: + (void) CFErrorPropagate(localError, error); + CFReleaseSafe(data); + CFReleaseSafe(certHash); + CFReleaseSafe(serial); + CFReleaseSafe(notBeforeDate); + CFReleaseSafe(notAfterDate); + CFReleaseSafe(names); + CFReleaseSafe(policies); + return result; +} + +static SecValidInfoRef _SecRevocationDbCopyMatching(SecRevocationDbConnectionRef dbc, + SecCertificateRef certificate, + SecCertificateRef issuer) { + SecValidInfoRef result = NULL; + CFErrorRef error = NULL; + CFDataRef issuerHash = NULL; + + require(dbc && certificate && issuer, errOut); + require(issuerHash = SecCertificateCopySHA256Digest(issuer), errOut); + + /* Check for the result in the cache. */ + result = SecRevocationDbCacheRead(dbc->db, certificate, issuerHash); + + /* Upon cache miss, get the result from the database and add it to the cache. */ + if (!result) { + result = _SecRevocationDbValidInfoForCertificate(dbc, certificate, issuerHash, &error); + SecRevocationDbCacheWrite(dbc->db, result); + } + +errOut: + CFReleaseSafe(issuerHash); + CFReleaseSafe(error); + return result; +} + +/* Return the update source as a retained CFStringRef. + If the value cannot be obtained, NULL is returned. +*/ +CFStringRef SecRevocationDbCopyUpdateSource(void) { + __block CFStringRef result = NULL; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + result = _SecRevocationDbCopyUpdateSource(dbc, blockError); + return (bool)result; + }); + }); + return result; +} + +/* Set the next update value for the revocation database. + (This function is expected to be called only by the database + maintainer, normally the system instance of trustd. If the + caller does not have write access, this is a no-op.) +*/ +bool SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate, CFErrorRef *error) { + __block bool ok = true; + __block CFErrorRef localError = NULL; + SecRevocationDbWith(^(SecRevocationDbRef rdb) { + ok &= SecRevocationDbPerformWrite(rdb, &localError, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + return _SecRevocationDbSetNextUpdateTime(dbc, nextUpdate, blockError); + }); + }); + (void) CFErrorPropagate(localError, error); + return ok; +} + +/* Return the next update value as a CFAbsoluteTime. + If the value cannot be obtained, -1 is returned. +*/ +CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void) { + __block CFAbsoluteTime result = -1; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + result = _SecRevocationDbGetNextUpdateTime(dbc, blockError); + return true; + }); + }); + return result; +} + +/* Return the serial background queue for database updates. + If the queue cannot be obtained, NULL is returned. +*/ +dispatch_queue_t SecRevocationDbGetUpdateQueue(void) { + __block dispatch_queue_t result = NULL; + SecRevocationDbWith(^(SecRevocationDbRef db) { + result = (db) ? db->update_queue : NULL; + }); + return result; +} + +/* Release all connections to the revocation database. +*/ +void SecRevocationDbReleaseAllConnections(void) { + SecRevocationDbWith(^(SecRevocationDbRef db) { + SecDbReleaseAllConnections((db) ? db->db : NULL); + }); +} + +/* === SecRevocationDb API === */ + +/* Given a certificate and its issuer, returns a SecValidInfoRef if the + valid database contains matching info; otherwise returns NULL. + Caller must release the returned SecValidInfoRef when finished. +*/ +SecValidInfoRef SecRevocationDbCopyMatching(SecCertificateRef certificate, + SecCertificateRef issuer) { + __block SecValidInfoRef result = NULL; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + result = _SecRevocationDbCopyMatching(dbc, certificate, issuer); + return (bool)result; + }); + }); + return result; +} + +/* Given an issuer, returns true if an entry for this issuer exists in + the database (i.e. a known CA). If the provided certificate is NULL, + or its entry is not found, the function returns false. +*/ +bool SecRevocationDbContainsIssuer(SecCertificateRef issuer) { + if (!issuer) { + return false; + } + __block bool result = false; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + CFDataRef issuerHash = SecCertificateCopySHA256Digest(issuer); + int64_t groupId = _SecRevocationDbGroupIdForIssuerHash(dbc, issuerHash, blockError); + CFReleaseSafe(issuerHash); + result = (groupId > 0); + return result; + }); + }); + return result; +} + +/* Return the current version of the revocation database. + A version of 0 indicates an empty database which must be populated. + If the version cannot be obtained, -1 is returned. +*/ +CFIndex SecRevocationDbGetVersion(void) { + __block CFIndex result = -1; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + result = (CFIndex)_SecRevocationDbGetVersion(dbc, blockError); + return (result >= 0); + }); + }); + return result; +} + +/* Return the current schema version of the revocation database. + A version of 0 indicates an empty database which must be populated. + If the schema version cannot be obtained, -1 is returned. + */ +CFIndex SecRevocationDbGetSchemaVersion(void) { + __block CFIndex result = -1; + SecRevocationDbWith(^(SecRevocationDbRef db) { + result = (CFIndex)_SecRevocationDbGetSchemaVersion(db, NULL, NULL); + }); + return result; +} + +/* Return the current update format of the revocation database. + A version of 0 indicates the format was unknown. + If the update format cannot be obtained, -1 is returned. + */ +CFIndex SecRevocationDbGetUpdateFormat(void) { + __block CFIndex result = -1; + SecRevocationDbWith(^(SecRevocationDbRef db) { + (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) { + result = (CFIndex)_SecRevocationDbGetUpdateFormat(dbc, blockError); + return (result >= 0); + }); + }); + return result; +} + +// MARK: - +// MARK: Digests +/* + ============================================================================== + Digest computation + ============================================================================== +*/ + +/* Returns array of SHA-256 hashes computed over the contents of a valid.sqlite3 + database, in the order specified by the valid-server-api documentation. The + resulting hashes can be compared against those in the update's 'hash' array. + + Hash 0: full database (all fields in initial Valid specification) + Hash 1: all issuer_hash arrays, plus not-after and not-before dates for each + Hash 2: subset of issuer_hash arrays where the no-ca-v2 flag is set +*/ +static CF_RETURNS_RETAINED CFArrayRef SecRevocationDbComputeFullContentDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + if (!dbc) { return NULL; } + __block bool ok = true; + __block CFErrorRef localError = NULL; + __block uint32_t N[4]={0,0,0,0}; + __block CC_SHA256_CTX hash0_ctx, hash1_ctx, hash2_ctx; + CC_SHA256_Init(&hash0_ctx); + CC_SHA256_Init(&hash1_ctx); + CC_SHA256_Init(&hash2_ctx); + + // Add version, check-again, and update (array count) fields as array of N. + // (Note: 'N' is defined as "unsigned 32-bit integer in network byte order") + int64_t version = _SecRevocationDbGetVersion(dbc, NULL); + N[0] = OSSwapInt32(version & 0xffffffff); + int64_t interval = _SecRevocationDbGetUpdateInterval(dbc, NULL); + if (interval < 0) { + interval = kSecStdUpdateInterval; // if we didn't store it, assume default + } + N[1] = OSSwapInt32(interval & 0xffffffff); + __block int64_t count = 0; + ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT count(*) FROM groups"), &localError, ^bool(sqlite3_stmt *selectGroupsCount) { + ok = ok && SecDbStep(dbc->dbconn, selectGroupsCount, &localError, ^void(bool *stop) { + count = sqlite3_column_int64(selectGroupsCount, 0); + *stop = true; + }); + return ok; + }); + N[2] = OSSwapInt32(count & 0xffffffff); + CC_SHA256_Update(&hash0_ctx, N, sizeof(uint32_t) * 3); + + // Sort the update array in order of minimum 'issuer-hash' entry. + // The issuer-hash array is first sorted to determine the lowest issuer-hash, + // and that value is used to sort the update entries. + // + // For our sqlite database, recreating the update array order means fetching + // the groupid column from the issuers table after sorting on issuer_hash, + // using DISTINCT to remove duplicates. Then, for each returned groupid, we + // obtain its list of issuers, its list of serials or hashes, and other data. + + ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT DISTINCT groupid FROM issuers ORDER BY issuer_hash ASC"), &localError, ^bool(sqlite3_stmt *selectGroups) { + ok = ok && SecDbForEach(dbc->dbconn, selectGroups, &localError, ^bool(int row_index) { + __block int64_t groupId = sqlite3_column_int64(selectGroups, 0); + ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT flags,format,data FROM groups WHERE groupid=?"), &localError, ^bool(sqlite3_stmt *selectGroup) { + ok = ok && SecDbBindInt64(selectGroup, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, selectGroup, &localError, ^(bool *stop) { + // per-group info is hashed in the following order: + // - issuer_hash array data (sorted) + // - flag bytes, in order listed below + // - format string [serial|sha256|nto1] + // - add array data (sorted), if [serial|sha256] + // - params (if present) + // - xor data (if present) + + int64_t flags = sqlite3_column_int64(selectGroup, 0); + bool noCAv2 = (flags & kSecValidInfoNoCAv2Check); + + // instead of recreating the issuer_hash array in memory, + // hash its length (item count) followed by the data of each issuer_hash. + ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT count(*) FROM issuers WHERE groupid=?"), &localError, ^bool(sqlite3_stmt *selectIssuersCount) { + ok = ok && SecDbBindInt64(selectIssuersCount, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, selectIssuersCount, &localError, ^void(bool *stop) { + count = sqlite3_column_int64(selectIssuersCount, 0); + *stop = true; + }); + return ok; + }); + uint32_t n = OSSwapInt32(count & 0xffffffff); + CC_SHA256_Update(&hash0_ctx, &n, sizeof(uint32_t)); + CC_SHA256_Update(&hash1_ctx, &n, sizeof(uint32_t)); + if (noCAv2) { + CC_SHA256_Update(&hash2_ctx, &n, sizeof(uint32_t)); + } + + // process issuer_hash entries for this group + ok = ok && SecDbWithSQL(dbc->dbconn, CFSTR("SELECT issuer_hash FROM issuers WHERE groupid=? ORDER BY issuer_hash ASC"), &localError, ^bool(sqlite3_stmt *selectIssuerHash) { + ok = ok && SecDbBindInt64(selectIssuerHash, 1, groupId, &localError); + ok = ok && SecDbForEach(dbc->dbconn, selectIssuerHash, &localError, ^bool(int row_index) { + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectIssuerHash, 0); + CFDataRef data = NULL; + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectIssuerHash, 0); + data = CFDataCreate(kCFAllocatorDefault, p, length); + } + if (data != NULL) { + hashData(data, &hash0_ctx); + hashData(data, &hash1_ctx); + if (noCAv2) { + hashData(data, &hash2_ctx); + } + CFRelease(data); + } else { + ok = false; + } + return ok; + }); + return ok; + }); + + // process flags, converting to array of unsigned 8-bit values, either 0 or 1: + // [ complete, check-ocsp, known-intermediates-only, no-ca, overridable, require-ct, valid ] + uint8_t C[8]={0,0,0,0,0,0,0,0}; + C[0] = (flags & kSecValidInfoComplete) ? 1 : 0; + C[1] = (flags & kSecValidInfoCheckOCSP) ? 1 : 0; + C[2] = (flags & kSecValidInfoKnownOnly) ? 1 : 0; + C[3] = (flags & kSecValidInfoNoCACheck) ? 1 : 0; + C[4] = (flags & kSecValidInfoOverridable) ? 1 : 0; + C[5] = (flags & kSecValidInfoRequireCT) ? 1 : 0; + C[6] = (flags & kSecValidInfoAllowlist) ? 1 : 0; + CC_SHA256_Update(&hash0_ctx, C, sizeof(uint8_t) * 7); + + // process format, converting integer to string value [serial|sha256|nto1] + SecValidInfoFormat format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); + switch (format) { + case kSecValidInfoFormatSerial: + hashString(CFSTR("serial"), &hash0_ctx); + break; + case kSecValidInfoFormatSHA256: + hashString(CFSTR("sha256"), &hash0_ctx); + break; + case kSecValidInfoFormatNto1: + hashString(CFSTR("nto1"), &hash0_ctx); + break; + case kSecValidInfoFormatUnknown: + default: + ok = false; // unexpected format values are not allowed + break; + } + // process 'add' array (serial or sha256 format). + // instead of recreating the 'add' array in memory, + // hash its length (item count) followed by the data of each entry. + CFStringRef arrayCountSql = NULL; + if (format == kSecValidInfoFormatSerial) { + arrayCountSql = CFSTR("SELECT count(*) FROM serials WHERE groupid=?"); + } else if (format == kSecValidInfoFormatSHA256) { + arrayCountSql = CFSTR("SELECT count(*) FROM hashes WHERE groupid=?"); + } + if (arrayCountSql) { + ok = ok && SecDbWithSQL(dbc->dbconn, arrayCountSql, &localError, ^bool(sqlite3_stmt *selectAddCount) { + ok = ok && SecDbBindInt64(selectAddCount, 1, groupId, &localError); + ok = ok && SecDbStep(dbc->dbconn, selectAddCount, &localError, ^void(bool *stop) { + count = sqlite3_column_int64(selectAddCount, 0); + *stop = true; + }); + return ok; + }); + n = OSSwapInt32(count & 0xffffffff); + CC_SHA256_Update(&hash0_ctx, &n, sizeof(uint32_t)); + } + // process data entries for this group + CFStringRef arrayDataSql = NULL; + if (format == kSecValidInfoFormatSerial) { + arrayDataSql = CFSTR("SELECT serial FROM serials WHERE groupid=? ORDER BY serial ASC"); + } else if (format == kSecValidInfoFormatSHA256) { + arrayDataSql = CFSTR("SELECT sha256 FROM hashes WHERE groupid=? ORDER by sha256 ASC"); + } + if (arrayDataSql) { + ok = ok && SecDbWithSQL(dbc->dbconn, arrayDataSql, &localError, ^bool(sqlite3_stmt *selectAddData) { + ok = ok && SecDbBindInt64(selectAddData, 1, groupId, &localError); + ok = ok && SecDbForEach(dbc->dbconn, selectAddData, &localError, ^bool(int row_index) { + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectAddData, 0); + CFDataRef data = NULL; + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectAddData, 0); + data = CFDataCreate(kCFAllocatorDefault, p, length); + } + if (data != NULL) { + hashData(data, &hash0_ctx); + CFRelease(data); + } else { + ok = false; + } + return ok; + }); + return ok; + }); + } + + // process params and xor data, if format is nto1 + if (format == kSecValidInfoFormatNto1) { + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); + CFDataRef data = NULL; + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); + data = CFDataCreate(kCFAllocatorDefault, p, length); + } + if (data != NULL) { + // unpack params and xor data + CFDataRef xor = NULL; + CFArrayRef params = NULL; + if (copyFilterComponents(data, &xor, ¶ms)) { + hashArray(params, &hash0_ctx); + hashData(xor, &hash0_ctx); + } else { + ok = false; + } + CFReleaseSafe(xor); + CFReleaseSafe(params); + } + CFReleaseSafe(data); + } + + // process date constraints [not-after, not-before] + CFAbsoluteTime notBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ + CFAbsoluteTime notAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ + CFDateRef notBeforeDate = NULL; + CFDateRef notAfterDate = NULL; + if (_SecRevocationDbCopyDateConstraints(dbc, groupId, ¬BeforeDate, ¬AfterDate, &localError)) { + if (notBeforeDate) { + notBefore = CFDateGetAbsoluteTime(notBeforeDate); + CFReleaseNull(notBeforeDate); + } + if (notAfterDate) { + notAfter = CFDateGetAbsoluteTime(notAfterDate); + CFReleaseNull(notAfterDate); + } + } + double nb = htond(notBefore); + double na = htond(notAfter); + CC_SHA256_Update(&hash1_ctx, &na, sizeof(double)); + CC_SHA256_Update(&hash1_ctx, &nb, sizeof(double)); + + *stop = true; + }); // per-group step + return ok; + }); // per-group select + return ok; + }); // for each group in list + return ok; + }); // select full group list + + CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (result) { + uint8_t digest[CC_SHA256_DIGEST_LENGTH]; + CFDataRef data = NULL; + CC_SHA256_Final(digest, &hash0_ctx); + if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { + CFArrayAppendValue(result, data); + CFReleaseNull(data); + } + CC_SHA256_Final(digest, &hash1_ctx); + if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { + CFArrayAppendValue(result, data); + CFReleaseNull(data); + } + CC_SHA256_Final(digest, &hash2_ctx); + if ((data = CFDataCreate(NULL, (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH)) != NULL) { + CFArrayAppendValue(result, data); + CFReleaseNull(data); + } + } + (void) CFErrorPropagate(localError, error); + return result; +} + +static bool SecRevocationDbComputeDigests(SecRevocationDbConnectionRef dbc, CFErrorRef *error) { + secinfo("validupdate", "Started verifying db content"); + bool result = true; + CFArrayRef expectedList = _SecRevocationDbCopyHashes(dbc, error); + CFIndex expectedCount = (expectedList) ? CFArrayGetCount(expectedList) : 0; + if (expectedCount < 1) { + secinfo("validupdate", "Unable to read db_hash values"); + CFReleaseNull(expectedList); + return result; // %%%% this will happen on first update, when db_hash isn't there + } + CFArrayRef computedList = SecRevocationDbComputeFullContentDigests(dbc, error); + CFIndex computedCount = (computedList) ? CFArrayGetCount(computedList) : 0; + for (CFIndex idx = 0; idx < expectedCount; idx++) { + if (idx >= computedCount) { + continue; // server provided additional hash value that we don't yet compute + } + CFDataRef expectedHash = (CFDataRef)CFArrayGetValueAtIndex(expectedList, idx); + CFDataRef computedHash = (CFDataRef)CFArrayGetValueAtIndex(computedList, idx); + if (!CFEqualSafe(expectedHash, computedHash)) { + result = false; + break; + } + } + if (!result) { + secinfo("validupdate", "Expected: %@", expectedList); + secinfo("validupdate", "Computed: %@", computedList); + } + secinfo("validupdate", "Finished verifying db content; result=%s", + (result) ? "SUCCESS" : "FAIL"); + CFReleaseSafe(expectedList); + CFReleaseSafe(computedList); + return result; +} + diff --git a/trust/trustd/SecRevocationDb.h b/trust/trustd/SecRevocationDb.h new file mode 100644 index 00000000..8559cfb5 --- /dev/null +++ b/trust/trustd/SecRevocationDb.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +/*! + @header SecRevocationDb + The functions in SecRevocationDb.h provide an interface to look up + revocation information, and refresh that information periodically. + */ + +#ifndef _SECURITY_SECREVOCATIONDB_H_ +#define _SECURITY_SECREVOCATIONDB_H_ + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +/* issuer group data format */ +typedef CF_ENUM(uint32_t, SecValidInfoFormat) { + kSecValidInfoFormatUnknown = 0, + kSecValidInfoFormatSerial = 1, + kSecValidInfoFormatSHA256 = 2, + kSecValidInfoFormatNto1 = 3 +}; + +/* policy types */ +typedef CF_ENUM(int8_t, SecValidPolicy) { + kSecValidPolicyNone = -1, + kSecValidPolicyAny = 0, + kSecValidPolicyServerAuthentication = 1, + kSecValidPolicyClientAuthentication = 2, + kSecValidPolicyEmailProtection = 3, + kSecValidPolicyCodeSigning = 4, + kSecValidPolicyTimeStamping = 5, +}; + +/*! + @typedef SecValidInfoRef + @abstract CFType used to return valid info lookup results. + */ +typedef struct __SecValidInfo *SecValidInfoRef; + +struct __SecValidInfo { + CFRuntimeBase _base; + + SecValidInfoFormat format; // format of per-issuer validity data + CFDataRef certHash; // SHA-256 hash of cert to which the following info applies + CFDataRef issuerHash; // SHA-256 hash of issuing CA certificate + CFDataRef anchorHash; // SHA-256 hash of anchor certificate (optional) + bool isOnList; // true if this cert was found on allow list or block list + bool valid; // true if this is an allow list, false if a block list + bool complete; // true if list is complete (i.e. status is definitive) + bool checkOCSP; // true if complete is false and OCSP check is required + bool knownOnly; // true if intermediate CAs under issuer must be found in database + bool requireCT; // true if this cert must have CT proof + bool noCACheck; // true if an entry does not require an OCSP check to accept + bool overridable; // true if the trust status is recoverable and can be overridden + bool hasDateConstraints; // true if this issuer has supplemental date constraints + bool hasNameConstraints; // true if this issuer has supplemental name constraints + bool hasPolicyConstraints; // true if this issuer has policy constraints + CFDateRef notBeforeDate; // minimum notBefore for this certificate (if hasDateConstraints is true) + CFDateRef notAfterDate; // maximum notAfter for this certificate (if hasDateConstraints is true) + CFDataRef nameConstraints; // name constraints blob (if hasNameConstraints is true) + CFDataRef policyConstraints; // policy constraints blob (if policyConstraints is true) +}; + +/*! + @function SecValidInfoSetAnchor + @abstract Updates a SecValidInfo reference with info about the anchor certificate in a chain. + @param validInfo The SecValidInfo reference to be updated. + @param anchor The certificate which anchors the chain for the certificate in this SecValidInfo reference. + @discussion A SecValidInfo reference contains information about a single certificate and its issuer. In some cases, it may be necessary to additionally examine the anchor of the certificate chain to determine validity. + */ +void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor); + +/*! + @function SecRevocationDbCheckNextUpdate + @abstract Periodic hook to poll for updates. + */ +void SecRevocationDbCheckNextUpdate(void); + +/*! + @function SecRevocationDbCopyMatching + @abstract Returns a SecValidInfo reference if matching revocation (or allow list) info was found. + @param certificate The certificate whose validity status is being requested. + @param issuer The issuing CA certificate. If the cert is self-signed, the same reference should be passed in both certificate and issuer parameters. Omitting either cert parameter is an error and NULL will be returned. + @result A SecValidInfoRef if there was matching revocation info. Caller must release this reference when finished by calling CFRelease. NULL is returned if no matching info was found in the database. + */ +SecValidInfoRef SecRevocationDbCopyMatching(SecCertificateRef certificate, + SecCertificateRef issuer); + +/*! + @function SecRevocationDbContainsIssuer + @abstract Returns true if the database contains an entry for the specified CA certificate. + @param issuer The certificate being checked. + @result If a matching issuer group was found, returns true, otherwise false. +*/ +bool SecRevocationDbContainsIssuer(SecCertificateRef issuer); + +/*! + @function SecRevocationDbGetVersion + @abstract Returns a CFIndex containing the version number of the database. + @result On success, the returned version will be a value greater than or equal to zero. A version of 0 indicates an empty database which has yet to be populated. If the version cannot be obtained, -1 is returned. + */ +CFIndex SecRevocationDbGetVersion(void); + +/*! + @function SecRevocationDbGetSchemaVersion + @abstract Returns a CFIndex containing the schema version number of the database. + @result On success, the returned version will be a value greater than or equal to zero. A version of 0 indicates an empty database which has yet to be populated. If the version cannot be obtained, -1 is returned. + */ +CFIndex SecRevocationDbGetSchemaVersion(void); + +/*! + @function SecValidUpdateVerifyAndIngest + @abstract Callback for receiving update data. + @param updateData The decompressed update data. + @param updateServer The source server for this data. + @param fullUpdate If true, a full update was requested. + */ +void SecValidUpdateVerifyAndIngest(CFDataRef updateData, CFStringRef updateServer, bool fullUpdate); + +/*! + @function readValidFile + @abstract Reads data into a CFDataRef using mmap. + @param fileName The file to read. + @param bytes The data read from the file. + @result An integer indicating failure (non-zero) or success. + @discussion This function mmaps the file and then makes a no-copy CFData for use of that mmapped file. This data MUST be munmapped when the caller has finished with the data. + */ +int readValidFile(const char *fileName, CFDataRef *bytes); + +/*! + @function SecRevocationDbComputeAndSetNextUpdateTime + @abstract Callback to push forward next update. + */ +void SecRevocationDbComputeAndSetNextUpdateTime(void); + +/*! + @function SecRevocationDbInitialize + @abstract Initializes revocation database if it doesn't exist or needs to be replaced. This should only be called once at process startup, before any database connections are established. + */ +void SecRevocationDbInitialize(void); + +extern const CFStringRef kValidUpdateProdServer; +extern const CFStringRef kValidUpdateSeedServer; +extern const CFStringRef kValidUpdateCarryServer; + +/*! + @function SecRevocationDbCopyUpdateSource + @abstract Returns the server source for updates of the revocation database. + @result The base string of the server URI. + */ +CFStringRef SecRevocationDbCopyUpdateSource(void); + + +__END_DECLS + +#endif /* _SECURITY_SECREVOCATIONDB_H_ */ diff --git a/trust/trustd/SecRevocationNetworking.h b/trust/trustd/SecRevocationNetworking.h new file mode 100644 index 00000000..e642f193 --- /dev/null +++ b/trust/trustd/SecRevocationNetworking.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +#ifndef _SECURITY_SECREVOCATIONNETWORKING_H_ +#define _SECURITY_SECREVOCATIONNETWORKING_H_ + +#import +#import "trust/trustd/SecRevocationServer.h" + +bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version); +bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert); + +#endif /* _SECURITY_SECREVOCATIONNETWORKING_H_ */ diff --git a/trust/trustd/SecRevocationNetworking.m b/trust/trustd/SecRevocationNetworking.m new file mode 100644 index 00000000..c1852066 --- /dev/null +++ b/trust/trustd/SecRevocationNetworking.m @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2017-2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +#include +#import +#import + +#include +#include +#include +#include +#include +#include "utilities/debugging.h" +#include "utilities/SecCFWrappers.h" +#include "utilities/SecPLWrappers.h" +#include "utilities/SecFileLocations.h" + +#include "SecRevocationDb.h" +#include "SecRevocationServer.h" +#include "SecTrustServer.h" +#include "SecOCSPRequest.h" +#include "SecOCSPResponse.h" + +#import "SecTrustLoggingServer.h" +#import "TrustURLSessionDelegate.h" + +#import "SecRevocationNetworking.h" + +/* MARK: Valid Update Networking */ +static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); +static CFStringRef kUpdateWiFiOnlyKey = CFSTR("ValidUpdateWiFiOnly"); +static CFStringRef kUpdateBackgroundKey = CFSTR("ValidUpdateBackground"); + +extern CFAbsoluteTime gUpdateStarted; +extern CFAbsoluteTime gNextUpdate; + +static int checkBasePath(const char *basePath) { + return mkpath_np((char*)basePath, 0755); +} + +static uint64_t systemUptimeInSeconds() { + struct timeval boottime; + size_t tv_size = sizeof(boottime); + time_t now, uptime = 0; + int mib[2]; + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + (void) time(&now); + if (sysctl(mib, 2, &boottime, &tv_size, NULL, 0) != -1 && + boottime.tv_sec != 0) { + uptime = now - boottime.tv_sec; + } + return (uint64_t)uptime; +} + +typedef void (^CompletionHandler)(void); + +@interface ValidDelegate : NSObject +@property CompletionHandler handler; +@property dispatch_queue_t revDbUpdateQueue; +@property os_transaction_t transaction; +@property NSString *currentUpdateServer; +@property NSFileHandle *currentUpdateFile; +@property NSURL *currentUpdateFileURL; +@property BOOL finishedDownloading; +@end + +@implementation ValidDelegate + +- (void)reschedule { + /* POWER LOG EVENT: operation canceled */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : (self->_finishedDownloading) ? @"updateCanceled" : @"downloadCanceled" + }); + secnotice("validupdate", "%s canceled at %f", + (self->_finishedDownloading) ? "update" : "download", + (double)CFAbsoluteTimeGetCurrent()); + + self->_handler(); + SecRevocationDbComputeAndSetNextUpdateTime(); + if (self->_transaction) { + self->_transaction = nil; + } +} + +- (void)updateDb:(NSUInteger)version { + __block NSURL *updateFileURL = self->_currentUpdateFileURL; + __block NSString *updateServer = self->_currentUpdateServer; + __block NSFileHandle *updateFile = self->_currentUpdateFile; + if (!updateFileURL || !updateFile) { + [self reschedule]; + return; + } + + /* Hold a transaction until we finish the update */ + __block os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.updateDb"); + dispatch_async(_revDbUpdateQueue, ^{ + /* POWER LOG EVENT: background update started */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"updateStarted" + }); + secnotice("validupdate", "update started at %f", (double)CFAbsoluteTimeGetCurrent()); + + CFDataRef updateData = NULL; + const char *updateFilePath = [updateFileURL fileSystemRepresentation]; + int rtn; + if ((rtn = readValidFile(updateFilePath, &updateData)) != 0) { + secerror("failed to read %@ with error %d", updateFileURL, rtn); + TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TAFatalError, rtn); + [self reschedule]; + transaction = nil; + return; + } + + secdebug("validupdate", "verifying and ingesting data from %@", updateFileURL); + SecValidUpdateVerifyAndIngest(updateData, (__bridge CFStringRef)updateServer, (0 == version)); + if ((rtn = munmap((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) != 0) { + secerror("unable to unmap current update %ld bytes at %p (error %d)", CFDataGetLength(updateData), CFDataGetBytePtr(updateData), rtn); + } + CFReleaseNull(updateData); + + /* We're done with this file */ + [updateFile closeFile]; + if (updateFilePath) { + (void)remove(updateFilePath); + } + self->_currentUpdateFile = nil; + self->_currentUpdateFileURL = nil; + self->_currentUpdateServer = nil; + + /* POWER LOG EVENT: background update finished */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"updateFinished" + }); + + /* Update is complete */ + secnotice("validupdate", "update finished at %f", (double)CFAbsoluteTimeGetCurrent()); + gUpdateStarted = 0; + + self->_handler(); + transaction = nil; // we're all done now + }); +} + +- (NSInteger)versionFromTask:(NSURLSessionTask *)task { + return atol([task.taskDescription cStringUsingEncoding:NSUTF8StringEncoding]); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + /* nsurlsessiond started our download. Create a transaction since we're going to be working for a little bit */ + self->_transaction = os_transaction_create("com.apple.trustd.valid.download"); + secinfo("validupdate", "Session %@ data task %@ returned response %ld (%@), expecting %lld bytes", + session, dataTask, (long)[(NSHTTPURLResponse *)response statusCode], + [response MIMEType], [response expectedContentLength]); + + WithPathInRevocationInfoDirectory(NULL, ^(const char *utf8String) { + (void)checkBasePath(utf8String); + }); + CFURLRef updateFileURL = SecCopyURLForFileInRevocationInfoDirectory(CFSTR("update-current")); + self->_currentUpdateFileURL = (updateFileURL) ? CFBridgingRelease(updateFileURL) : nil; + const char *updateFilePath = [self->_currentUpdateFileURL fileSystemRepresentation]; + if (!updateFilePath) { + secnotice("validupdate", "failed to find revocation info directory. canceling task %@", dataTask); + completionHandler(NSURLSessionResponseCancel); + [self reschedule]; + return; + } + + /* Clean up any old files from previous tasks. */ + (void)remove(updateFilePath); + + int fd; + off_t off; + fd = open(updateFilePath, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd < 0 || (off = lseek(fd, 0, SEEK_SET)) < 0) { + secnotice("validupdate","unable to open %@ (errno %d)", self->_currentUpdateFileURL, errno); + } + if (fd >= 0) { + close(fd); + } + + /* POWER LOG EVENT: background download actually started */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadStarted" + }); + secnotice("validupdate", "download started at %f", (double)CFAbsoluteTimeGetCurrent()); + + NSError *error = nil; + self->_currentUpdateFile = [NSFileHandle fileHandleForWritingToURL:self->_currentUpdateFileURL error:&error]; + if (!self->_currentUpdateFile) { + secnotice("validupdate", "failed to open %@: %@. canceling task %@", self->_currentUpdateFileURL, error, dataTask); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error]; +#endif // ENABLE_TRUSTD_ANALYTICS + completionHandler(NSURLSessionResponseCancel); + [self reschedule]; + return; + } + + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + secdebug("validupdate", "Session %@ data task %@ returned %lu bytes (%lld bytes so far) out of expected %lld bytes", + session, dataTask, (unsigned long)[data length], [dataTask countOfBytesReceived], [dataTask countOfBytesExpectedToReceive]); + + if (!self->_currentUpdateFile) { + secnotice("validupdate", "received data, but output file is not open"); + [dataTask cancel]; + [self reschedule]; + return; + } + + @try { + /* Writing can fail and throw an exception, e.g. if we run out of disk space. */ + [self->_currentUpdateFile writeData:data]; + } + @catch(NSException *exception) { + secnotice("validupdate", "%s", exception.description.UTF8String); + TrustdHealthAnalyticsLogErrorCode(TAEventValidUpdate, TARecoverableError, errSecDiskFull); + [dataTask cancel]; + [self reschedule]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + if (error) { + secnotice("validupdate", "Session %@ task %@ failed with error %@", session, task, error); +#if ENABLE_TRUSTD_ANALYTICS + [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error]; +#endif // ENABLE_TRUSTD_ANALYTICS + [self reschedule]; + /* close file before we leave */ + [self->_currentUpdateFile closeFile]; + self->_currentUpdateFile = nil; + self->_currentUpdateServer = nil; + self->_currentUpdateFileURL = nil; + } else { + /* POWER LOG EVENT: background download finished */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadFinished" + }); + secnotice("validupdate", "download finished at %f", (double)CFAbsoluteTimeGetCurrent()); + secdebug("validupdate", "Session %@ task %@ succeeded", session, task); + self->_finishedDownloading = YES; + [self updateDb:[self versionFromTask:task]]; + } + if (self->_transaction) { + self->_transaction = nil; + } +} + +@end + +@interface ValidUpdateRequest : NSObject +@property NSTimeInterval updateScheduled; +@property NSURLSession *backgroundSession; +@end + +static ValidUpdateRequest *request = nil; + +@implementation ValidUpdateRequest + +- (NSURLSessionConfiguration *)validUpdateConfiguration { + /* preferences to override defaults */ + CFTypeRef value = NULL; + bool updateOnWiFiOnly = true; + value = CFPreferencesCopyValue(kUpdateWiFiOnlyKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isBoolean(value)) { + updateOnWiFiOnly = CFBooleanGetValue((CFBooleanRef)value); + } + CFReleaseNull(value); + bool updateInBackground = true; + value = CFPreferencesCopyValue(kUpdateBackgroundKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (isBoolean(value)) { + updateInBackground = CFBooleanGetValue((CFBooleanRef)value); + } + CFReleaseNull(value); + + NSURLSessionConfiguration *config = nil; + if (updateInBackground) { + config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: @"com.apple.trustd.networking.background"]; + config.networkServiceType = NSURLNetworkServiceTypeBackground; + config.discretionary = YES; + config._requiresPowerPluggedIn = YES; + config.allowsCellularAccess = (!updateOnWiFiOnly) ? YES : NO; + } else { + config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; // no cookies or data storage + config.networkServiceType = NSURLNetworkServiceTypeDefault; + config.discretionary = NO; + } + + config.HTTPAdditionalHeaders = @{ @"User-Agent" : @"com.apple.trustd/2.0", + @"Accept" : @"*/*", + @"Accept-Encoding" : @"gzip,deflate,br"}; + + config.TLSMinimumSupportedProtocol = kTLSProtocol12; + + return config; +} + +- (void) createSession:(dispatch_queue_t)updateQueue forServer:(NSString *)updateServer { + NSURLSessionConfiguration *config = [self validUpdateConfiguration]; + ValidDelegate *delegate = [[ValidDelegate alloc] init]; + delegate.handler = ^(void) { + request.updateScheduled = 0.0; + secdebug("validupdate", "resetting scheduled time"); + }; + delegate.transaction = NULL; + delegate.revDbUpdateQueue = updateQueue; + delegate.finishedDownloading = NO; + delegate.currentUpdateServer = [updateServer copy]; + + /* Callbacks should be on a separate NSOperationQueue. + We'll then dispatch the work on updateQueue and return from the callback. */ + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 1; + _backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; +} + +- (BOOL) scheduleUpdateFromServer:(NSString *)server forVersion:(NSUInteger)version withQueue:(dispatch_queue_t)updateQueue { + if (!server) { + secnotice("validupdate", "invalid update request"); + return NO; + } + + if (!updateQueue) { + secnotice("validupdate", "missing update queue, skipping update"); + return NO; + } + + /* nsurlsessiond waits for unlock to finish launching, so we can't block trust evaluations + * on scheduling this background task. Also, we want to wait a sufficient amount of time + * after system boot before trying to initiate network activity, to avoid the possibility + * of a performance regression in the boot path. */ + dispatch_async(updateQueue, ^{ + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + if (self.updateScheduled != 0.0) { + secdebug("validupdate", "update in progress (scheduled %f)", (double)self.updateScheduled); + return; + } else { + uint64_t uptime = systemUptimeInSeconds(); + const uint64_t minUptime = 180; + if (uptime < minUptime) { + gNextUpdate = now + (minUptime - uptime); + gUpdateStarted = 0; + secnotice("validupdate", "postponing update until %f", gNextUpdate); + return; + } else { + self.updateScheduled = now; + secnotice("validupdate", "scheduling update at %f", (double)self.updateScheduled); + } + } + + /* we have an update to schedule, so take a transaction while we work */ + os_transaction_t transaction = os_transaction_create("com.apple.trustd.valid.scheduleUpdate"); + + /* clear all old sessions and cleanup disk (for previous download tasks) */ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + @autoreleasepool { + [NSURLSession _obliterateAllBackgroundSessionsWithCompletionHandler:^{ + secnotice("validupdate", "removing all old sessions for trustd"); + }]; + } + }); + + if (!self.backgroundSession) { + [self createSession:updateQueue forServer:server]; + } else { + ValidDelegate *delegate = (ValidDelegate *)[self.backgroundSession delegate]; + delegate.currentUpdateServer = [server copy]; + } + + /* POWER LOG EVENT: scheduling our background download session now */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadScheduled", + @"version" : @(version) + }); + + NSURL *validUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/g3/v%ld", + server, (unsigned long)version]]; + NSURLSessionDataTask *dataTask = [self.backgroundSession dataTaskWithURL:validUrl]; + dataTask.taskDescription = [NSString stringWithFormat:@"%lu",(unsigned long)version]; + [dataTask resume]; + secnotice("validupdate", "scheduled background data task %@ at %f", dataTask, CFAbsoluteTimeGetCurrent()); + (void) transaction; // dead store + transaction = nil; // ARC releases the transaction + }); + + return YES; +} +@end + +bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + @autoreleasepool { + request = [[ValidUpdateRequest alloc] init]; + } + }); + @autoreleasepool { + return [request scheduleUpdateFromServer:(__bridge NSString*)server forVersion:version withQueue:queue]; + } +} + +/* MARK: - */ +/* MARK: OCSP Fetch Networking */ +#define OCSP_REQUEST_THRESHOLD 10 + +@interface OCSPFetchDelegate : TrustURLSessionDelegate +@end + +@implementation OCSPFetchDelegate +- (BOOL)fetchNext:(NSURLSession *)session { + SecORVCRef orvc = (SecORVCRef)self.context; + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); + + BOOL result = true; + if ((result = [super fetchNext:session])) { + /* no fetch scheduled */ + orvc->done = true; + } else { + if (self.URIix > 0) { + orvc->responder = (__bridge CFURLRef)self.URIs[self.URIix - 1]; + } else { + orvc->responder = (__bridge CFURLRef)self.URIs[0]; + } + if (analytics) { + analytics->ocsp_fetches++; + } + } + return result; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + /* call the superclass's method to set expiration */ + [super URLSession:session task:task didCompleteWithError:error]; + + __block SecORVCRef orvc = (SecORVCRef)self.context; + if (!orvc || !orvc->builder) { + /* We already returned to the PathBuilder state machine. */ + return; + } + + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); + if (error) { + /* Log the error */ + secnotice("rvc", "Failed to download ocsp response %@, with error %@", task.originalRequest.URL, error); + if (analytics) { + analytics->ocsp_fetch_failed++; + } + } else { + SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate((__bridge CFDataRef)self.response); + if (ocspResponse) { + SecORVCConsumeOCSPResponse(orvc, ocspResponse, self.expiration, true, false); + if (analytics && !orvc->done) { + /* We got an OCSP response that didn't pass validation */ + analytics-> ocsp_validation_failed = true; + } + } else if (analytics) { + /* We got something that wasn't an OCSP response (e.g. captive portal) -- + * we consider that a fetch failure */ + analytics->ocsp_fetch_failed++; + } + } + + /* If we didn't get a valid OCSP response, try the next URI */ + if (!orvc->done) { + (void)[self fetchNext:session]; + } + + /* We got a valid OCSP response or couldn't schedule any more fetches. + * Close the session, update the PVCs, decrement the async count, and callback if we're all done. */ + if (orvc->done) { + secdebug("rvc", "builder %p, done with OCSP fetches for cert: %ld", orvc->builder, orvc->certIX); + self.context = nil; + [session invalidateAndCancel]; + SecORVCUpdatePVC(orvc); + if (0 == SecPathBuilderDecrementAsyncJobCount(orvc->builder)) { + /* We're the last async job to finish, jump back into the state machine */ + secdebug("rvc", "builder %p, done with all async jobs", orvc->builder); + dispatch_async(SecPathBuilderGetQueue(orvc->builder), ^{ + SecPathBuilderStep(orvc->builder); + }); + } + } +} + +- (NSURLRequest *)createNextRequest:(NSURL *)uri { + SecORVCRef orvc = (SecORVCRef)self.context; + CFDataRef ocspDER = CFRetainSafe(SecOCSPRequestGetDER(orvc->ocspRequest)); + NSData *nsOcspDER = CFBridgingRelease(ocspDER); + NSString *ocspBase64 = [nsOcspDER base64EncodedStringWithOptions:0]; + + /* Ensure that we percent-encode specific characters in the base64 path + which are defined as delimiters in RFC 3986 [2.2]. + */ + static NSMutableCharacterSet *allowedSet = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + allowedSet = [[NSCharacterSet URLPathAllowedCharacterSet] mutableCopy]; + [allowedSet removeCharactersInString:@":/?#[]@!$&'()*+,;="]; + }); + NSString *escapedRequest = [ocspBase64 stringByAddingPercentEncodingWithAllowedCharacters:allowedSet]; + NSURLRequest *request = nil; + + /* Interesting tidbit from rfc5019 + When sending requests that are less than or equal to 255 bytes in + total (after encoding) including the scheme and delimiters (http://), + server name and base64-encoded OCSPRequest structure, clients MUST + use the GET method (to enable OCSP response caching). OCSP requests + larger than 255 bytes SHOULD be submitted using the POST method. + */ + if (([[uri absoluteString] length] + 1 + [escapedRequest length]) < 256) { + /* Use a GET */ + NSString *requestString = [NSString stringWithFormat:@"%@/%@", [uri absoluteString], escapedRequest]; + NSURL *requestURL = [NSURL URLWithString:requestString]; + request = [NSURLRequest requestWithURL:requestURL]; + } else { + /* Use a POST */ + NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:uri]; + mutableRequest.HTTPMethod = @"POST"; + mutableRequest.HTTPBody = nsOcspDER; + request = mutableRequest; + } + + return request; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)taskMetrics { + secdebug("rvc", "got metrics with task interval %f", taskMetrics.taskInterval.duration); + SecORVCRef orvc = (SecORVCRef)self.context; + if (orvc && orvc->builder) { + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(orvc->builder); + if (analytics) { + analytics->ocsp_fetch_time += (uint64_t)(taskMetrics.taskInterval.duration * NSEC_PER_SEC); + } + } +} +@end + +bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert) { + @autoreleasepool { + CFArrayRef ocspResponders = CFRetainSafe(SecCertificateGetOCSPResponders(cert)); + NSArray *nsResponders = CFBridgingRelease(ocspResponders); + + NSInteger count = [nsResponders count]; + if (count > OCSP_REQUEST_THRESHOLD) { + secnotice("rvc", "too may OCSP responder entries (%ld)", (long)count); + orvc->done = true; + return true; + } + + NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + config.timeoutIntervalForResource = TrustURLSessionGetResourceTimeout(); + config.HTTPAdditionalHeaders = @{@"User-Agent" : @"com.apple.trustd/2.0"}; + + NSData *auditToken = CFBridgingRelease(SecPathBuilderCopyClientAuditToken(orvc->builder)); + if (auditToken) { + config._sourceApplicationAuditTokenData = auditToken; + } + + OCSPFetchDelegate *delegate = [[OCSPFetchDelegate alloc] init]; + delegate.context = orvc; + delegate.URIs = nsResponders; + delegate.URIix = 0; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; + secdebug("rvc", "created URLSession for %@", cert); + + bool result = false; + if ((result = [delegate fetchNext:session])) { + /* no fetch scheduled, close the session */ + [session invalidateAndCancel]; + } + return result; + } +} diff --git a/trust/trustd/SecRevocationServer.c b/trust/trustd/SecRevocationServer.c new file mode 100644 index 00000000..266bdba3 --- /dev/null +++ b/trust/trustd/SecRevocationServer.c @@ -0,0 +1,1042 @@ +/* + * Copyright (c) 2008-2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecRevocationServer.c - Engine for evaluating certificate revocation. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecRevocationNetworking.h" + +#include "trust/trustd/SecRevocationServer.h" + +// MARK: SecORVCRef +/******************************************************** + ****************** OCSP RVC Functions ****************** + ********************************************************/ +const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0; +const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0; +#define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC) + +static void SecORVCFinish(SecORVCRef orvc) { + secdebug("alloc", "finish orvc %p", orvc); + if (orvc->ocspRequest) { + SecOCSPRequestFinalize(orvc->ocspRequest); + orvc->ocspRequest = NULL; + } + if (orvc->ocspResponse) { + SecOCSPResponseFinalize(orvc->ocspResponse); + orvc->ocspResponse = NULL; + if (orvc->ocspSingleResponse) { + SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse); + orvc->ocspSingleResponse = NULL; + } + } + memset(orvc, 0, sizeof(struct OpaqueSecORVC)); +} + +/* Process a verified ocsp response for a given cert. Return true if the + certificate status was obtained. */ +static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this, + SecORVCRef rvc) { + bool processed; + switch (this->certStatus) { + case CS_Good: + secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX); + /* @@@ Mark cert as valid until a given date (nextUpdate if we have one) + in the info dictionary. */ + //cert.revokeCheckGood(true); + rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate; + processed = true; + break; + case CS_Revoked: + secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX); + /* @@@ Mark cert as revoked (with reason) at revocation date in + the info dictionary, or perhaps we should use a different key per + reason? That way a client using exceptions can ignore some but + not all reasons. */ + SInt32 reason = this->crlReason; + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true); + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + if (path) { + SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); + } + CFRelease(cfreason); + processed = true; + break; + case CS_Unknown: + /* not an error, no per-cert status, nothing here */ + secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX); + processed = false; + break; + default: + secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex, + (int)this->certStatus, rvc->certIX); + processed = false; + break; + } + + return processed; +} + +void SecORVCUpdatePVC(SecORVCRef rvc) { + if (rvc->ocspSingleResponse) { + SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc); + } + if (rvc->ocspResponse) { + rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse); + } +} + +typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr); + +static void +SecOCSPEvaluateCompleted(const void *userData, + CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, + SecTrustResultType result) { + SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData; + evaluated(result); + Block_release(evaluated); + +} + +static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) { + __block bool evaluated = false; + bool trusted = false; + if (!signers || !issuers) { + return trusted; + } + + /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */ + const void *ocspSigner = SecPolicyCreateOCSPSigner(); + CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault, + &ocspSigner, 1, &kCFTypeArrayCallBacks); + CFRelease(ocspSigner); + + SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) { + if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) { + evaluated = true; + } + }); + + CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder); + SecPathBuilderRef oBuilder = SecPathBuilderCreate(NULL, clientAuditToken, + signers, issuers, true, false, + policies, NULL, NULL, NULL, + verifyTime, NULL, NULL, + SecOCSPEvaluateCompleted, completed); + /* disable network access to avoid recursion */ + SecPathBuilderSetCanAccessNetwork(oBuilder, false); + + /* Build the chain(s), evaluate them, call the completed block, free the block and builder */ + SecPathBuilderStep(oBuilder); + CFReleaseNull(clientAuditToken); + CFReleaseNull(policies); + + /* verify the public key of the issuer signed the OCSP signer */ + if (evaluated) { + SecCertificateRef issuer = NULL, signer = NULL; + SecKeyRef issuerPubKey = NULL; + + issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0); + signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0); + + if (issuer) { + issuerPubKey = SecCertificateCopyKey(issuer); + } + if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) { + trusted = true; + } else { + secnotice("ocsp", "ocsp signer cert not signed by issuer"); + } + CFReleaseNull(issuerPubKey); + } + + return trusted; +} + +static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) { + bool trusted; + SecCertificatePathVCRef issuers = SecCertificatePathVCCopyFromParent(SecPathBuilderGetPath(rvc->builder), rvc->certIX + 1); + SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathVCGetCertificateAtIndex(issuers, 0)) : NULL; + CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse); + SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer); + + if (signer && signers) { + if (issuer && CFEqual(signer, issuer)) { + /* We already know we trust issuer since it's the issuer of the + * cert we are verifying. */ + secinfo("ocsp", "ocsp responder: %@ response signed by issuer", + rvc->responder); + trusted = true; + } else { + secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer", + rvc->responder); + CFMutableArrayRef signerCerts = NULL; + CFArrayRef issuerCerts = NULL; + + /* Ensure the signer cert is the 0th cert for trust evaluation */ + signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(signerCerts, signer); + CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers))); + + if (issuers) { + issuerCerts = SecCertificatePathVCCopyCertificates(issuers); + } + + if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) { + secdebug("ocsp", "response satisfies ocspSigner policy (%@)", + rvc->responder); + trusted = true; + } else { + /* @@@ We don't trust the cert so don't use this response. */ + secnotice("ocsp", "ocsp response signed by certificate which " + "does not satisfy ocspSigner policy"); + trusted = false; + } + CFReleaseNull(signerCerts); + CFReleaseNull(issuerCerts); + } + } else { + /* @@@ No signer found for this ocsp response, discard it. */ + secnotice("ocsp", "ocsp responder: %@ no signer found for response", + rvc->responder); + trusted = false; + } + +#if DUMP_OCSPRESPONSES + char buf[40]; + snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der", + rvc->certIX, (trusted ? "t" : "u")); + secdumpdata(ocspResponse->data, buf); +#endif + CFReleaseNull(issuers); + CFReleaseNull(issuer); + CFReleaseNull(signers); + CFReleaseNull(signer); + return trusted; +} + +void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, + CFTimeInterval maxAge, bool updateCache, bool fromCache) { + SecOCSPSingleResponseRef sr = NULL; + require_quiet(ocspResponse, errOut); + SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse); + require_action_quiet(orStatus == kSecOCSPSuccess, errOut, + secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus)); + require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut, + secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder)); + // Check if this response is fresher than any (cached) response we might still have in the rvc. + require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut); + + CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent(); +#if TARGET_OS_IPHONE + /* Check the OCSP response signature and verify the response if not pulled from the cache. + * Performance optimization since we don't write invalid responses to the cache. */ + if (!fromCache) { + require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, + sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); + } +#else + /* Always check the OCSP response signature and verify the response (since the cache is user-modifiable). */ + require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, + sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); +#endif + + // If we get here, we have a properly signed ocsp response + // but we haven't checked dates yet. + + bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime); + if (sr->certStatus == CS_Good) { + // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime + require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut); + } else if (sr->certStatus == CS_Revoked) { + // Expire revoked responses when the subject certificate itself expires. + ocspResponse->expireTime = SecCertificateNotValidAfter(SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX)); + } + + // Ok we like the new response, let's toss the old one. + if (updateCache) + SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime); + + if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse); + rvc->ocspResponse = ocspResponse; + ocspResponse = NULL; + + if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse); + rvc->ocspSingleResponse = sr; + sr = NULL; + + rvc->done = sr_valid; + +errOut: + if (sr) SecOCSPSingleResponseDestroy(sr); + if (ocspResponse) SecOCSPResponseFinalize(ocspResponse); +} + +static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { + SecORVCRef orvc = NULL; + orvc = malloc(sizeof(struct OpaqueSecORVC)); + secdebug("alloc", "orvc %p", orvc); + if (orvc) { + memset(orvc, 0, sizeof(struct OpaqueSecORVC)); + orvc->builder = builder; + orvc->rvc = rvc; + orvc->certIX = certIX; + + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(builder, certIX); + if (SecPathBuilderGetCertificateCount(builder) > (certIX + 1)) { + SecCertificateRef issuer = SecPathBuilderGetCertificateAtIndex(builder, certIX + 1); + orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer); + } + } + return orvc; +} + +static void SecORVCProcessStapledResponses(SecORVCRef rvc) { + /* Get stapled OCSP responses */ + CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->builder); + + if(ocspResponsesData) { + secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX); + CFArrayForEach(ocspResponsesData, ^(const void *value) { + SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); + SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false, false); + }); + CFRelease(ocspResponsesData); + } +} + +void SecRVCDelete(SecRVCRef rvc) { + secdebug("alloc", "delete rvc %p", rvc); + if (rvc->orvc) { + SecORVCFinish(rvc->orvc); + free(rvc->orvc); + rvc->orvc = NULL; + } + if (rvc->valid_info) { + CFReleaseNull(rvc->valid_info); + } +} + +// Forward declaration +static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc); + +static void SecRVCInit(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { + secdebug("alloc", "rvc %p", rvc); + rvc->builder = builder; + rvc->certIX = certIX; + rvc->orvc = SecORVCCreate(rvc, builder, certIX); + if (!rvc->orvc) { + SecRVCDelete(rvc); + SecRVCSetFinishedWithoutNetwork(rvc); + } else { + rvc->done = false; + } +} + +static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { + return true; +} + +static bool SecRVCPolicyConstraintsPermitPolicy(SecValidPolicy *constraints, CFIndex count, SecPolicyRef policy) { + if (!constraints || !policy) { + return true; /* nothing to constrain */ + } + SecValidPolicy policyType = kSecValidPolicyAny; + CFStringRef policyName = SecPolicyGetName(policy); + /* determine if the policy is a candidate for being constrained */ + if (CFEqualSafe(policyName, kSecPolicyNameSSLServer) || + CFEqualSafe(policyName, kSecPolicyNameEAPServer) || + CFEqualSafe(policyName, kSecPolicyNameIPSecServer)) { + policyType = kSecValidPolicyServerAuthentication; + } else if (CFEqualSafe(policyName, kSecPolicyNameSSLClient) || + CFEqualSafe(policyName, kSecPolicyNameEAPClient) || + CFEqualSafe(policyName, kSecPolicyNameIPSecClient)) { + policyType = kSecValidPolicyClientAuthentication; + } else if (CFEqualSafe(policyName, kSecPolicyNameSMIME)) { + policyType = kSecValidPolicyEmailProtection; + } else if (CFEqualSafe(policyName, kSecPolicyNameCodeSigning)) { + policyType = kSecValidPolicyCodeSigning; + } else if (CFEqualSafe(policyName, kSecPolicyNameTimeStamping)) { + policyType = kSecValidPolicyTimeStamping; + } + if (policyType == kSecValidPolicyAny) { + return true; /* policy not subject to constraint */ + } + /* policy is subject to constraint; do the constraints allow it? */ + bool result = false; + for (CFIndex ix = 0; ix < count; ix++) { + SecValidPolicy allowedPolicy = constraints[ix]; + if (allowedPolicy == kSecValidPolicyAny || + allowedPolicy == policyType) { + result = true; + break; + } + } + if (!result) { + secnotice("rvc", "%@ not allowed by policy constraints on issuing CA", policyName); + } + return result; +} + +static bool SecRVCGetPolicyConstraints(CFDataRef data, SecValidPolicy **constraints, CFIndex *count) { + /* Sanity-check the input policy constraints data, returning pointer and + * count values in output arguments. Function result is true if successful. + * + * The first byte of the policy constraints data contains the number of entries, + * followed by an array of 0..n policy constraint values of type SecValidPolicy. + * The maximum number of defined policies is not expected to approach 127, i.e. + * the largest value which can be expressed in a signed byte. + */ + bool result = false; + CFIndex length = 0; + SecValidPolicy *p = NULL; + if (data) { + length = CFDataGetLength(data); + p = (SecValidPolicy *)CFDataGetBytePtr(data); + } + /* Verify that count is 0 or greater, and equal to remaining number of bytes */ + CFIndex c = (length > 0) ? *p++ : -1; + if (c < 0 || c != (length - 1)) { + secerror("invalid policy constraints array"); + } else { + if (constraints) { + *constraints = p; + } + if (count) { + *count = c; + } + result = true; + } + return result; +} + +static void SecRVCProcessValidPolicyConstraints(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info || !rvc->builder) { + return; + } + if (!rvc->valid_info->hasPolicyConstraints) { + return; + } + CFIndex count = 0; + SecValidPolicy *constraints = NULL; + if (!SecRVCGetPolicyConstraints(rvc->valid_info->policyConstraints, &constraints, &count)) { + return; + } + secdebug("rvc", "found policy constraints for cert at index %ld", rvc->certIX); + + /* check that policies being verified are permitted by the policy constraints */ + bool policyDeniedByConstraints = false; + CFIndex ix, initialPVCCount = SecPathBuilderGetPVCCount(rvc->builder); + for (ix = 0; ix < initialPVCCount; ix++) { + SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, ix); + CFArrayRef policies = CFRetainSafe(pvc->policies); + CFIndex policyCount = (policies) ? CFArrayGetCount(policies) : 0; + for (CFIndex policyIX = 0; policyIX < policyCount; policyIX++) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + if (!SecRVCPolicyConstraintsPermitPolicy(constraints, count, policy)) { + policyDeniedByConstraints = true; + SecPVCSetResultForced(pvc, kSecPolicyCheckIssuerPolicyConstraints, rvc->certIX, + kCFBooleanFalse, true); + pvc->result = kSecTrustResultRecoverableTrustFailure; + if (!rvc->valid_info->overridable) { + /* error for this check should be non-recoverable */ + pvc->result = kSecTrustResultFatalTrustFailure; + } + } + } + CFReleaseSafe(policies); + } + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); + if (analytics) { + TAValidStatus status = (policyDeniedByConstraints) ? TAValidPolicyConstrainedDenied : TAValidPolicyConstrainedOK; + analytics->valid_status |= status; + } +} + +static void SecRVCProcessValidDateConstraints(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info || !rvc->builder) { + return; + } + if (!rvc->valid_info->hasDateConstraints) { + return; + } + SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + if (!certificate) { + return; + } + CFAbsoluteTime certIssued = SecCertificateNotValidBefore(certificate); + CFAbsoluteTime caNotBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */ + CFAbsoluteTime caNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */ + if (rvc->valid_info->notBeforeDate) { + caNotBefore = CFDateGetAbsoluteTime(rvc->valid_info->notBeforeDate); + } + if (rvc->valid_info->notAfterDate) { + caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate); + /* per the Valid specification, if this date is in the past, we need to check CT. */ + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + if (caNotAfter < now) { + rvc->valid_info->requireCT = true; + } + } + if ((certIssued < caNotBefore) && (rvc->certIX > 0)) { + /* not-before constraint is only applied to leaf certificate, for now. */ + return; + } + + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); + if ((certIssued < caNotBefore) || (certIssued > caNotAfter)) { + /* We are outside the constrained validity period. */ + secnotice("rvc", "certificate issuance date not within the allowed range for this CA%s", + (rvc->valid_info->overridable) ? "" : " (non-recoverable error)"); + if (analytics) { + analytics->valid_status |= TAValidDateConstrainedRevoked; + } + if (rvc->valid_info->overridable) { + /* error is recoverable, treat certificate as untrusted + (note this date check is different from kSecPolicyCheckTemporalValidity) */ + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedKey, rvc->certIX, + kCFBooleanFalse, true); + } else { + /* error is non-overridable, treat certificate as revoked */ + SInt32 reason = 0; /* unspecified reason code */ + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true); + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + if (path) { + SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); + } + CFReleaseNull(cfreason); + } + } else if (analytics) { + analytics->valid_status |= TAValidDateConstrainedOK; + } +} + +bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info) { + return false; + } + SecValidInfoRef info = rvc->valid_info; + /* outcomes as defined in Valid server specification */ + if (info->format == kSecValidInfoFormatSerial || + info->format == kSecValidInfoFormatSHA256) { + if (info->noCACheck || info->complete || info->isOnList) { + return true; + } + } else { /* info->format == kSecValidInfoFormatNto1 */ + if (info->noCACheck || (info->complete && !info->isOnList)) { + return true; + } + } + return false; +} + +bool SecRVCHasRevokedValidInfo(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info) { + return false; + } + SecValidInfoRef info = rvc->valid_info; + /* either not present on an allowlist, or present on a blocklist */ + return (!info->isOnList && info->valid) || (info->isOnList && !info->valid); +} + +void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info || !rvc->builder) { + return; + } + if (rvc->valid_info->overridable) { + /* error is recoverable, treat certificate as untrusted */ + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedLeaf, rvc->certIX, + kCFBooleanFalse, true); + return; + } + /* error is fatal at this point */ + if (!SecRVCHasRevokedValidInfo(rvc) || rvc->valid_info->noCACheck) { + /* result key should indicate blocked instead of revoked, + * but result must be non-recoverable */ + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckBlackListedLeaf, rvc->certIX, + kCFBooleanFalse, true); + return; + } + SInt32 reason = 0; /* unspecified, since the Valid db doesn't tell us */ + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true); + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + if (path) { + SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason); + } + CFReleaseNull(cfreason); +} + +static void SecRVCProcessValidInfoResults(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info || !rvc->builder) { + return; + } + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + SecValidInfoRef info = rvc->valid_info; + + bool definitive = SecRVCHasDefinitiveValidInfo(rvc); + bool revoked = SecRVCHasRevokedValidInfo(rvc); + + /* set analytics */ + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); + if (analytics) { + if (revoked) { + analytics->valid_status |= definitive ? TAValidDefinitelyRevoked : TAValidProbablyRevoked; + } else { + analytics->valid_status |= definitive ? TAValidDefinitelyOK : TAValidProbablyOK; + } + analytics->valid_require_ct |= info->requireCT; + analytics->valid_known_intermediates_only |= info->knownOnly; + } + + /* Handle no-ca cases */ + if (info->noCACheck) { + bool allowed = (info->valid && info->complete && info->isOnList); + if (revoked) { + /* definitely revoked */ + SecRVCSetValidDeterminedErrorResult(rvc); + } else if (allowed) { + /* definitely not revoked (allowlisted) */ + SecCertificatePathVCSetIsAllowlisted(path, true); + } + /* no-ca is definitive; no need to check further. */ + secdebug("validupdate", "rvc: definitely %s cert %" PRIdCFIndex, + (allowed) ? "allowed" : "revoked", rvc->certIX); + rvc->done = true; + return; + } + + /* Handle policy constraints, if present. */ + SecRVCProcessValidPolicyConstraints(rvc); + + /* Handle date constraints, if present. + * Note: a not-after date may set the CT requirement, + * so check requireCT after this function is called. */ + SecRVCProcessValidDateConstraints(rvc); + + /* Set CT requirement on path, if present. */ + if (info->requireCT) { + SecPathCTPolicy ctp = kSecPathCTRequired; + if (info->overridable) { + ctp = kSecPathCTRequiredOverridable; + } + SecCertificatePathVCSetRequiresCT(path, ctp); + } + + /* Trigger OCSP for any non-definitive or revoked cases */ + if (!definitive || revoked) { + info->checkOCSP = true; + } + + if (info->checkOCSP) { + CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); + CFIndex issuerIX = rvc->certIX + 1; + if (issuerIX >= count) { + /* cannot perform a revocation check on the last cert in the + chain, since we don't have its issuer. */ + return; + } + secdebug("validupdate", "rvc: %s%s cert %" PRIdCFIndex " (will check OCSP)", + (info->complete) ? "" : "possibly ", (info->valid) ? "allowed" : "revoked", + rvc->certIX); + SecPathBuilderSetRevocationMethod(rvc->builder, kSecPolicyCheckRevocationAny); + if (analytics) { + /* Valid DB results caused us to do OCSP */ + analytics->valid_trigger_ocsp = true; + } + } +} + +static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) { + /* Skip checking for OCSP Signer verification */ + if (SecPathBuilderGetPVCCount(rvc->builder) == 1) { + SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, 0); + if (!pvc) { return false; } + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); + CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL; + if (policyName && CFEqual(policyName, CFSTR("OCSPSigner"))) { + return false; + } + } + + /* Make sure revocation db info is up-to-date. + * We don't care if the builder is allowed to access the network because + * the network fetching does not block the trust evaluation. */ + SecRevocationDbCheckNextUpdate(); + + /* Check whether we have valid db info for this cert, + given the cert and its issuer */ + SecValidInfoRef info = NULL; + CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); + if (count) { + bool isSelfSigned = false; + SecCertificateRef cert = NULL; + SecCertificateRef issuer = NULL; + CFIndex issuerIX = rvc->certIX + 1; + if (count > issuerIX) { + issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, issuerIX); + } else if (count == issuerIX) { + CFIndex rootIX = SecCertificatePathVCSelfSignedIndex(SecPathBuilderGetPath(rvc->builder)); + if (rootIX == rvc->certIX) { + issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, rootIX); + isSelfSigned = true; + } + } + cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + if (!isSelfSigned) { + /* skip revocation db check for self-signed certificates [33137065] */ + info = SecRevocationDbCopyMatching(cert, issuer); + } + SecValidInfoSetAnchor(info, SecPathBuilderGetCertificateAtIndex(rvc->builder, count-1)); + } + if (info) { + SecValidInfoRef old_info = rvc->valid_info; + rvc->valid_info = info; + if (old_info) { + CFReleaseNull(old_info); + } + return true; + } + return false; +} + +static void SecRVCCheckRevocationCaches(SecRVCRef rvc) { + /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */ + if (SecRVCShouldCheckOCSP(rvc) && (rvc->orvc->ocspRequest)) { + secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX); + SecOCSPResponseRef response = NULL; + if (SecPathBuilderGetCheckRevocationOnline(rvc->builder)) { + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL); + } else { + response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL); + } + SecORVCConsumeOCSPResponse(rvc->orvc, response, NULL_TIME, false, true); + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); + if (rvc->orvc->done && analytics) { + /* We found a valid OCSP response in the cache */ + analytics->ocsp_cache_hit = true; + } + } +} + +static void SecRVCUpdatePVC(SecRVCRef rvc) { + SecRVCProcessValidInfoResults(rvc); /* restore the results we got from Valid */ + if (rvc->orvc) { SecORVCUpdatePVC(rvc->orvc); } +} + +static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc) { + rvc->done = true; + SecRVCUpdatePVC(rvc); + (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); +} + +static bool SecRVCFetchNext(SecRVCRef rvc) { + bool OCSP_fetch_finished = true; + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder); + /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */ + if (SecRVCShouldCheckOCSP(rvc)) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX); + OCSP_fetch_finished = SecORVCBeginFetches(rvc->orvc, cert); + if (analytics && !OCSP_fetch_finished) { + /* We did a network OCSP fetch, set report appropriately */ + analytics->ocsp_network = true; + } + } + if (OCSP_fetch_finished) { + /* we didn't start an OCSP background job for this cert */ + (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); + } + return OCSP_fetch_finished; +} + +/* The SecPathBuilder state machine calls SecPathBuilderCheckRevocation twice -- + * once in the ValidatePath state, and again in the ComputeDetails state. In the + * ValidatePath state we've not yet run the path checks, so for callers who set + * kSecRevocationCheckIfTrusted, we don't do any networking on that first call. + * Here, if we've already done revocation before (so we're in ComputeDetails now), + * we need to recheck (and enable networking) for trusted chains and + * kSecRevocationCheckIfTrusted. Otherwise, we skip the checks to save on the processing + * but update the PVCs with the revocation results from the last check. */ +static bool SecRevocationDidCheckRevocation(SecPathBuilderRef builder, bool *first_check_done) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); + if (!SecCertificatePathVCIsRevocationDone(path)) { + return false; + } + if (first_check_done) { + *first_check_done = true; + } + + SecPVCRef resultPVC = SecPathBuilderGetResultPVC(builder); + bool recheck = false; + if (SecPathBuilderGetCheckRevocationIfTrusted(builder) && SecPVCIsOkResult(resultPVC)) { + recheck = true; + secdebug("rvc", "Rechecking revocation because network now allowed"); + } else { + secdebug("rvc", "Not rechecking revocation"); + } + + if (recheck) { + // reset the RVCs for the second pass + SecCertificatePathVCDeleteRVCs(path); + } else { + CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder); + for (certIX = 0; certIX < certCount; ++certIX) { + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); + if (rvc) { + SecRVCUpdatePVC(rvc); + } + } + } + + return !recheck; +} + +static bool SecRevocationCanAccessNetwork(SecPathBuilderRef builder, bool first_check_done) { + /* CheckRevocationIfTrusted overrides NoNetworkAccess for revocation */ + if (SecPathBuilderGetCheckRevocationIfTrusted(builder)) { + if (first_check_done) { + /* We're on the second pass. We need to now allow networking for revocation. + * SecRevocationDidCheckRevocation takes care of not running a second pass + * if the chain isn't trusted. */ + return true; + } else { + /* We're on the first pass of the revocation checks, where we aren't + * supposed to do networking because we don't know if the chain + * is trusted yet. */ + return false; + } + } + return SecPathBuilderCanAccessNetwork(builder); +} + +void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); + if (!path) { + return; + } + /* only perform this check once per path! */ + CFIndex certIX = kCFNotFound; + if (SecCertificatePathVCCheckedIssuers(path)) { + certIX = SecCertificatePathVCUnknownCAIndex(path); + goto checkedIssuers; + } + /* check full path: start with anchor and decrement to leaf */ + bool parentConstrained = false; + CFIndex certCount = SecPathBuilderGetCertificateCount(builder); + for (certIX = certCount - 1; certIX >= 0; --certIX) { + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); + if (!rvc) { + continue; + } + if (parentConstrained && !rvc->valid_info) { + /* Parent had the known-only constraint, but our issuer is unknown. + Bump index to point back at the issuer since it fails the constraint. */ + certIX++; + break; + } + parentConstrained = (rvc->valid_info && rvc->valid_info->knownOnly); + if (parentConstrained) { + secdebug("validupdate", "Valid db found a known-intermediate constraint on %@ (index=%ld)", + rvc->valid_info->issuerHash, certIX+1); + if (certIX == 0) { + /* check special case: unknown constrained CA in leaf position */ + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, certIX); + if (cert && SecCertificateIsCA(cert) && !SecRevocationDbContainsIssuer(cert)) { + /* leaf is a CA which violates the constraint */ + break; + } + } + } + } + /* At this point, certIX will either be -1, indicating no CA was found + which failed a known-intermediates-only constraint on its parent, or it + will be the index of the first unknown CA which fails the constraint. */ + if (certIX >= 0) { + secnotice("validupdate", "CA at index %ld violates known-intermediate constraint", certIX); + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + if (analytics) { + analytics->valid_unknown_intermediate = true; + } + } + SecCertificatePathVCSetUnknownCAIndex(path, certIX); + SecCertificatePathVCSetCheckedIssuers(path, true); + +checkedIssuers: + if (certIX >= 0) { + /* Error is set on CA certificate which failed the constraint. */ + SecRVCSetValidDeterminedErrorResult(SecCertificatePathVCGetRVCAtIndex(path, certIX)); + } +} + +bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) { + secdebug("rvc", "checking revocation"); + CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder); + SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); + if (certCount <= 1) { + /* Can't verify without an issuer; we're done */ + return true; + } + + bool first_check_done = false; + if (SecRevocationDidCheckRevocation(builder, &first_check_done)) { + return true; + } + + /* Setup things so we check revocation status of all certs. */ + SecCertificatePathVCAllocateRVCs(path, certCount); + + /* Note that if we are multi threaded and a job completes after it + is started but before we return from this function, we don't want + a callback to decrement asyncJobCount to zero before we finish issuing + all the jobs. To avoid this we pretend we issued certCount async jobs, + and decrement pvc->asyncJobCount for each cert that we don't start a + background fetch for. We include the root, even though we'll never start + an async job for it so that we count all active threads for this eval. */ + SecPathBuilderSetAsyncJobCount(builder, (unsigned int)(certCount)); + + /* Loop though certificates again and issue an ocsp fetch if the + revocation status checking isn't done yet (and we have an issuer!) */ + for (certIX = 0; certIX < certCount; ++certIX) { + secdebug("rvc", "checking revocation for cert: %ld", certIX); + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); + if (!rvc) { + continue; + } + + SecRVCInit(rvc, builder, certIX); + + /* RFC 6960: id-pkix-ocsp-nocheck extension says that we shouldn't check revocation. */ + if (SecCertificateHasOCSPNoCheckMarkerExtension(SecCertificatePathVCGetCertificateAtIndex(path, certIX))) + { + secdebug("rvc", "skipping revocation checks for no-check cert: %ld", certIX); + TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder); + if (analytics) { + /* This certificate has OCSP No-Check, so add to reporting analytics */ + analytics->ocsp_no_check = true; + } + SecRVCSetFinishedWithoutNetwork(rvc); + } + + if (rvc->done) { + continue; + } + +#if !TARGET_OS_BRIDGE + /* Check valid database first (separate from OCSP response cache) */ + if (SecRVCCheckValidInfoDatabase(rvc)) { + SecRVCProcessValidInfoResults(rvc); + } +#endif + /* Any other revocation method requires an issuer certificate to verify the response; + * skip the last cert in the chain since it doesn't have one. */ + if (certIX + 1 >= certCount) { + continue; + } + + /* Ignore stapled OCSP responses only if CRLs are enabled and the + * policy specifically requested CRLs only. */ + if (SecRVCShouldCheckOCSP(rvc)) { + /* If we have any OCSP stapled responses, check those first */ + SecORVCProcessStapledResponses(rvc->orvc); + } + +#if TARGET_OS_BRIDGE + /* The bridge has no writeable storage and no network. Nothing else we can + * do here. */ + SecRVCSetFinishedWithoutNetwork(rvc); + continue; +#else // !TARGET_OS_BRIDGE + /* Then check the caches for revocation results. */ + SecRVCCheckRevocationCaches(rvc); + + /* The check is done if we found cached responses from either method. */ + if (rvc->done || rvc->orvc->done) { + secdebug("rvc", "found cached response for cert: %ld", certIX); + SecRVCSetFinishedWithoutNetwork(rvc); + continue; + } + + /* If we got a cached response that is no longer valid (which can only be true for + * revoked responses), let's try to get a fresher response even if no one asked. + * This check resolves unrevocation events after the nextUpdate time. */ + bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse); + + /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an + async http request for this cert's revocation status, unless we already successfully checked + the revocation status of this cert based on the cache or stapled responses. */ + bool allow_fetch = SecRevocationCanAccessNetwork(builder, first_check_done) && + (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) || + SecPathBuilderGetRevocationMethod(builder) || old_cached_response); + if (rvc->done || !allow_fetch) { + /* We got a cache hit or we aren't allowed to access the network */ + SecRVCUpdatePVC(rvc); + /* We didn't really start any background jobs for this cert. */ + (void)SecPathBuilderDecrementAsyncJobCount(builder); + } else { + (void)SecRVCFetchNext(rvc); + } +#endif // !TARGET_OS_BRIDGE + } + + /* Return false if there are still async jobs running. */ + /* builder->asyncJobCount is atomic, so we know that if the job count is 0, all other + * threads are finished. If the job count is > 0, other threads will decrement the job + * count and SecPathBuilderStep to crank the state machine when the job count is 0. */ + return (SecPathBuilderDecrementAsyncJobCount(builder) == 0); +} + +CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) { + CFAbsoluteTime enu = NULL_TIME; + if (!rvc || !rvc->orvc) { return enu; } + enu = rvc->orvc->nextUpdate; + return enu; +} diff --git a/trust/trustd/SecRevocationServer.h b/trust/trustd/SecRevocationServer.h new file mode 100644 index 00000000..b3f7a090 --- /dev/null +++ b/trust/trustd/SecRevocationServer.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecRevocationServer + The functions provided in SecRevocationServer.h provide an interface to + the trust evaluation engine for dealing with certificate revocation. + */ + +#ifndef _SECURITY_SECREVOCATIONSERVER_H_ +#define _SECURITY_SECREVOCATIONSERVER_H_ + +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" + +typedef struct OpaqueSecORVC *SecORVCRef; + +/* Revocation verification context. */ +struct OpaqueSecRVC { + /* Pointer to the builder for this revocation check */ + SecPathBuilderRef builder; + + /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ + CFIndex certIX; + + /* The OCSP Revocation verification context */ + SecORVCRef orvc; + + /* Valid database info for this revocation check */ + SecValidInfoRef valid_info; + + bool done; +}; +typedef struct OpaqueSecRVC *SecRVCRef; + +/* OCSP Revocation verification context. */ +struct OpaqueSecORVC { + /* Pointer to the builder for this revocation check. */ + SecPathBuilderRef builder; + + /* Pointer to the generic rvc for this revocation check */ + SecRVCRef rvc; + + /* The ocsp request we send to each responder. */ + SecOCSPRequestRef ocspRequest; + + /* The freshest response we received so far, from stapling or cache or responder. */ + SecOCSPResponseRef ocspResponse; + + /* The best validated candidate single response we received so far, from stapling or cache or responder. */ + SecOCSPSingleResponseRef ocspSingleResponse; + + /* Index of cert in builder that this RVC is for 0 = leaf, etc. */ + CFIndex certIX; + + /* Date until which this revocation status is valid. */ + CFAbsoluteTime nextUpdate; + + /* URL of current responder. For logging purposes. */ + CFURLRef responder; + + bool done; +}; + +bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder); +void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder); +CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc); +void SecRVCDelete(SecRVCRef rvc); +bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc); +bool SecRVCHasRevokedValidInfo(SecRVCRef rvc); +void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc); + +/* OCSP verification callbacks */ +void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, + CFTimeInterval maxAge, bool updateCache, bool fromCache); +void SecORVCUpdatePVC(SecORVCRef rvc); + + +#endif /* _SECURITY_SECREVOCATIONSERVER_H_ */ diff --git a/trust/trustd/SecTrustExceptionResetCount.h b/trust/trustd/SecTrustExceptionResetCount.h new file mode 100644 index 00000000..c9cd2dbb --- /dev/null +++ b/trust/trustd/SecTrustExceptionResetCount.h @@ -0,0 +1,14 @@ +// +// SecTrustExceptionResetCount.h +// Security +// + +#ifndef SecTrustExceptionResetCount_h +#define SecTrustExceptionResetCount_h + +#include + +bool SecTrustServerIncrementExceptionResetCount(CFErrorRef *error); +uint64_t SecTrustServerGetExceptionResetCount(CFErrorRef *error); + +#endif /* SecTrustExceptionResetCount_h */ diff --git a/trust/trustd/SecTrustExceptionResetCount.m b/trust/trustd/SecTrustExceptionResetCount.m new file mode 100644 index 00000000..4552f3ce --- /dev/null +++ b/trust/trustd/SecTrustExceptionResetCount.m @@ -0,0 +1,194 @@ +// +// SecTrustExceptionResetCount.m +// Security_ios +// + +#import +#import "SecTrustExceptionResetCount.h" + +#import +#import + +static NSString *kExceptionResetCountKey = @"ExceptionResetCount"; +static NSString *exceptionResetCounterFile = @"com.apple.security.exception_reset_counter.plist"; + +/* Returns the path to the, existing or internally-created, 'exceptionResetCounterFile' file. */ +static NSString *SecPlistFileExistsInKeychainDirectory(CFErrorRef *error) { + NSString *status = NULL; + + NSString *path = [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)exceptionResetCounterFile) path]; + if (!path) { + secerror("Unable to address permanent storage for '%{public}@'.", exceptionResetCounterFile); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOENT, NULL); + } + return status; + } + secinfo("trust", "'%{public}@' is at '%{public}@'.", exceptionResetCounterFile, path); + + NSFileManager *fm = [NSFileManager defaultManager]; + if (!fm) { + secerror("Failed to initialize the file manager in '%{public}s'.", __func__); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOMEM, NULL); + } + return status; + } + + BOOL isDir = false; + bool fileExists = [fm fileExistsAtPath:path isDirectory:&isDir]; + if (isDir) { + secerror("'%{public}@' is a directory. (not a file)", path); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EISDIR, NULL); + } + return status; + } + if (fileExists) { + secdebug("trust", "'%{public}@' already exists.", path); + status = path; + return status; + } + + if (![fm createFileAtPath:path contents:nil attributes:nil]) { + secerror("Failed to create permanent storage at '%{public}@'.", path); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); + } + return status; + } + secinfo("trust", "'%{public}@' has been created.", path); + status = path; + + return status; +} + +static uint64_t SecReadPlistFromFileInKeychainDirectory(CFErrorRef *error) { + uint64_t value = 0; + + CFErrorRef localError = NULL; + NSString *path = SecPlistFileExistsInKeychainDirectory(&localError); + if (localError) { + if (error) { + *error = localError; + } + secerror("Permanent storage for the exceptions epoch is unavailable."); + return value; + } + if (!path) { + secinfo("trust", "Permanent storage for the exceptions epoch is missing. Defaulting to value %llu.", value); + return value; + } + + NSMutableDictionary *plDict = [NSMutableDictionary dictionaryWithContentsOfFile:path]; + if (!plDict) { + secerror("Failed to read from permanent storage at '%{public}@' or the data is bad. Defaulting to value %llu.", path, value); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENXIO, NULL); + } + return value; + } + + id valueObject = [plDict objectForKey:kExceptionResetCountKey]; + if (!valueObject) { + secinfo("trust", "Could not find key '%{public}@'. Defaulting to value %llu.", kExceptionResetCountKey, value); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENXIO, NULL); + } + return value; + } + if (![valueObject isKindOfClass:[NSNumber class]]) { + secerror("The value for key '%{public}@' is not a number.", kExceptionResetCountKey); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EDOM, NULL); + } + return value; + } + + value = [valueObject unsignedIntValue]; + + secinfo("trust", "'%{public}@' is %llu.", kExceptionResetCountKey, value); + return value; +} + +static bool SecWritePlistToFileInKeychainDirectory(uint64_t exceptionResetCount, CFErrorRef *error) { + bool status = false; + + CFErrorRef localError = NULL; + SecPlistFileExistsInKeychainDirectory(&localError); + if (localError) { + if (error) { + *error = localError; + } + secerror("Permanent storage for the exceptions epoch is unavailable."); + return status; + } + + NSString *path = [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)exceptionResetCounterFile) path]; + if (!path) { + secerror("Unable to address permanent storage for '%{public}@'.", exceptionResetCounterFile); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); + } + return status; + } + + NSMutableDictionary *dataToSave = [NSMutableDictionary new]; + if (!dataToSave) { + secerror("Failed to allocate memory for the exceptions epoch structure."); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ENOMEM, NULL); + } + return status; + } + dataToSave[@"Version"] = [NSNumber numberWithUnsignedInteger:1]; + dataToSave[kExceptionResetCountKey] = [NSNumber numberWithUnsignedInteger:exceptionResetCount]; + + status = [dataToSave writeToFile:path atomically:YES]; + if (!status) { + secerror("Failed to write to permanent storage at '%{public}@'.", path); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, EIO, NULL); + } + return status; + } + + secinfo("trust", "'%{public}@' has been committed to permanent storage at '%{public}@'.", kExceptionResetCountKey, path); + return status; +} + +uint64_t SecTrustServerGetExceptionResetCount(CFErrorRef *error) { + CFErrorRef localError = NULL; + uint64_t exceptionResetCount = SecReadPlistFromFileInKeychainDirectory(&localError); + /* Treat ENXIO as a transient error; I/O seems to be working but we have failed to read the current epoch. + * That's expected when epoch is still 0 and there is nothing to store in permanent storage. (and later read) + */ + if (localError && CFEqualSafe(CFErrorGetDomain(localError), kCFErrorDomainPOSIX) && CFErrorGetCode(localError) == ENXIO) { + CFRelease(localError); + localError = NULL; + } + if (error && localError) { + *error = localError; + } + secinfo("trust", "exceptionResetCount: %llu (%s)", exceptionResetCount, error ? (*error ? "Error" : "OK") : "N/A"); + return exceptionResetCount; +} + +bool SecTrustServerIncrementExceptionResetCount(CFErrorRef *error) { + bool status = false; + + uint64_t currentExceptionResetCount = SecTrustServerGetExceptionResetCount(error); + if (error && *error) { + secerror("Failed to increment the extensions epoch."); + return status; + } + if (currentExceptionResetCount >= INT64_MAX) { + secerror("Current exceptions epoch value is too large. (%llu) Won't increment.", currentExceptionResetCount); + if (error) { + *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ERANGE, NULL); + } + return status; + } + + return SecWritePlistToFileInKeychainDirectory(currentExceptionResetCount + 1, error); +} diff --git a/trust/trustd/SecTrustLoggingServer.h b/trust/trustd/SecTrustLoggingServer.h new file mode 100644 index 00000000..5b15b9a4 --- /dev/null +++ b/trust/trustd/SecTrustLoggingServer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecTrustLoggingServer.h - logging for certificate trust evaluation engine + * + */ + +#ifndef _SECURITY_SECTRUSTLOGGINGSERVER_H_ +#define _SECURITY_SECTRUSTLOGGINGSERVER_H_ + + +void DisableLocalization(void); + +#endif /* _SECURITY_SECTRUSTLOGGINGSERVER_H_ */ diff --git a/trust/trustd/SecTrustLoggingServer.m b/trust/trustd/SecTrustLoggingServer.m new file mode 100644 index 00000000..e9dabba3 --- /dev/null +++ b/trust/trustd/SecTrustLoggingServer.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecTrustLoggingServer.c - logging for certificate trust evaluation engine + * + */ + +#include +#include "SecTrustLoggingServer.h" + diff --git a/trust/trustd/SecTrustServer.c b/trust/trustd/SecTrustServer.c new file mode 100644 index 00000000..1227f246 --- /dev/null +++ b/trust/trustd/SecTrustServer.c @@ -0,0 +1,1402 @@ +/* + * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecTrustServer.c - certificate trust evaluation engine + * + * + */ + +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include "trust/trustd/SecRevocationServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecPinningDb.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SecRSAKey.h" +#include +#include +#include +#include +#include +#include +#include "OTATrustUtilities.h" +#include "personalization.h" +#include +#include +#include + +#if TARGET_OS_OSX +#include +#endif + +#define MAX_CHAIN_LENGTH 15 +#define MAX_NUM_CHAINS 100 +#define ACCEPT_PATH_SCORE 10000000 + +/* Forward declaration for use in SecCertificateSource. */ +static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents); + +// MARK: - +// MARK: SecPathBuilder +/******************************************************** + *************** SecPathBuilder object ****************** + ********************************************************/ +struct SecPathBuilder { + dispatch_queue_t queue; + uint64_t startTime; + CFDataRef clientAuditToken; + SecCertificateSourceRef certificateSource; + SecCertificateSourceRef itemCertificateSource; + SecCertificateSourceRef anchorSource; + SecCertificateSourceRef appleAnchorSource; + CFMutableArrayRef anchorSources; + CFIndex nextParentSource; + CFMutableArrayRef parentSources; + CFArrayRef ocspResponses; // Stapled OCSP responses + CFArrayRef signedCertificateTimestamps; // Stapled SCTs + CFDictionaryRef trustedLogs; // Trusted CT logs + CFAbsoluteTime verifyTime; + CFArrayRef exceptions; + + /* Hashed set of all paths we've constructed so far, used to prevent + re-considering a path that was already constructed once before. + Note that this is the only container in which certificatePath + objects are retained. + Every certificatePath being considered is always in allPaths and in at + least one of partialPaths, rejectedPaths, or candidatePath, + all of which don't retain their values. */ + CFMutableSetRef allPaths; + + /* No trusted anchor, satisfies the linking to intermediates for all + policies (unless considerRejected is true). */ + CFMutableArrayRef partialPaths; + /* No trusted anchor, does not satisfy linking to intermediates for all + policies. */ + CFMutableArrayRef rejectedPaths; + /* Trusted anchor, satisfies the policies so far. */ + CFMutableArrayRef candidatePaths; + + CFIndex partialIX; + + bool considerRejected; + bool considerPartials; + bool canAccessNetwork; + + SecPVCRef * pvcs; + CFIndex pvcCount; + + SecCertificatePathVCRef path; + _Atomic unsigned int asyncJobCount; + bool online_revocation; + bool trusted_revocation; + CFStringRef revocation_check_method; + + SecCertificatePathVCRef bestPath; + CFMutableDictionaryRef info; + + CFIndex activations; + bool (*state)(SecPathBuilderRef); + SecPathBuilderCompleted completed; + const void *context; + TrustAnalyticsBuilder * analyticsData; +}; + +/* State functions. Return false if a async job was scheduled, return + true to execute the next state. */ +static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder); +static bool SecPathBuilderGetNext(SecPathBuilderRef builder); +static bool SecPathBuilderValidatePath(SecPathBuilderRef builder); +static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder); +static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder); +static bool SecPathBuilderReportResult(SecPathBuilderRef builder); + +/* Forward declarations. */ +static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, + SecCertificateRef certificate, SecCertificateSourceRef *foundInSource); +static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path); + +static void SecPathBuilderInit(SecPathBuilderRef builder, dispatch_queue_t builderQueue, + CFDataRef clientAuditToken, CFArrayRef certificates, + CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, + CFArrayRef policies, CFArrayRef ocspResponses, + CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, + SecPathBuilderCompleted completed, const void *context) { + secdebug("alloc", "builder %p", builder); + CFAllocatorRef allocator = kCFAllocatorDefault; + + builder->analyticsData = calloc(1, sizeof(TrustAnalyticsBuilder)); + builder->analyticsData->start_time = mach_absolute_time(); + + builder->clientAuditToken = (CFDataRef) + ((clientAuditToken) ? CFRetain(clientAuditToken) : NULL); + + if (!builderQueue) { + /* make our own queue if caller fails to provide one */ + builder->queue = dispatch_queue_create("com.apple.trustd.evaluation.builder", DISPATCH_QUEUE_SERIAL); + } else { + dispatch_retain_safe(builderQueue); + builder->queue = builderQueue; + } + + builder->nextParentSource = 1; +#if !TARGET_OS_WATCH + /* */ + builder->canAccessNetwork = true; +#endif + atomic_init(&builder->asyncJobCount, 0); + + builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL); + builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL); + + builder->allPaths = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); + builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. + builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. + builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL); // Does not retain, allPaths retains members. See declaration. + + /* Init the policy verification context. */ + builder->pvcs = malloc(sizeof(SecPVCRef)); + builder->pvcs[0] = malloc(sizeof(struct OpaqueSecPVC)); + SecPVCInit(builder->pvcs[0], builder, policies); + builder->pvcCount = 1; + builder->verifyTime = verifyTime; + builder->exceptions = CFRetainSafe(exceptions); + + /* Let's create all the certificate sources we might want to use. */ + builder->certificateSource = + SecMemoryCertificateSourceCreate(certificates); + if (anchors) { + builder->anchorSource = SecMemoryCertificateSourceCreate(anchors); + } + + bool allowNonProduction = false; + builder->appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(allowNonProduction)); + + + /** Parent Sources + ** The order here avoids the most expensive methods if the cheaper methods + ** produce an acceptable chain: client-provided, keychains, network-fetched. + **/ +#if !TARGET_OS_BRIDGE + CFArrayAppendValue(builder->parentSources, builder->certificateSource); + builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups); + if (keychainsAllowed) { + CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource); + #if TARGET_OS_OSX + /* On OS X, need additional parent source to search legacy keychain files. */ + if (kSecLegacyCertificateSource->contains && kSecLegacyCertificateSource->copyParents) { + CFArrayAppendValue(builder->parentSources, kSecLegacyCertificateSource); + } + #endif + } + if (anchorsOnly) { + /* Add the Apple, system, and user anchor certificate db to the search list + if we don't explicitly trust them. */ + CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource); + CFArrayAppendValue(builder->parentSources, kSecSystemAnchorSource); + #if TARGET_OS_IPHONE + CFArrayAppendValue(builder->parentSources, kSecUserAnchorSource); + #endif + } + if (keychainsAllowed && builder->canAccessNetwork) { + CFArrayAppendValue(builder->parentSources, kSecCAIssuerSource); + } +#else /* TARGET_OS_BRIDGE */ + /* Bridge can only access memory sources. */ + CFArrayAppendValue(builder->parentSources, builder->certificateSource); + if (anchorsOnly) { + /* Add the Apple, system, and user anchor certificate db to the search list + if we don't explicitly trust them. */ + CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource); + } +#endif /* !TARGET_OS_BRIDGE */ + + /** Anchor Sources + ** The order here allows a client-provided anchor to overrule + ** a user or admin trust setting which can overrule the system anchors. + ** Apple's anchors cannot be overriden by a trust setting. + **/ +#if !TARGET_OS_BRIDGE + if (builder->anchorSource) { + CFArrayAppendValue(builder->anchorSources, builder->anchorSource); + } + if (!anchorsOnly) { + /* Only add the system and user anchor certificate db to the + anchorSources if we are supposed to trust them. */ + CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource); + if (keychainsAllowed) { +#if TARGET_OS_IPHONE + CFArrayAppendValue(builder->anchorSources, kSecUserAnchorSource); +#else /* TARGET_OS_OSX */ + if (kSecLegacyAnchorSource->contains && kSecLegacyAnchorSource->copyParents) { + CFArrayAppendValue(builder->anchorSources, kSecLegacyAnchorSource); + } +#endif + } + CFArrayAppendValue(builder->anchorSources, kSecSystemAnchorSource); + } +#else /* TARGET_OS_BRIDGE */ + /* Bridge can only access memory sources. */ + if (builder->anchorSource) { + CFArrayAppendValue(builder->anchorSources, builder->anchorSource); + } + if (!anchorsOnly) { + CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource); + } +#endif /* !TARGET_OS_BRIDGE */ + + builder->ocspResponses = CFRetainSafe(ocspResponses); + builder->signedCertificateTimestamps = CFRetainSafe(signedCertificateTimestamps); + + if(trustedLogs) { + builder->trustedLogs = SecOTAPKICreateTrustedCTLogsDictionaryFromArray(trustedLogs); + } + + /* Now let's get the leaf cert and turn it into a path. */ + SecCertificateRef leaf = + (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0); + SecCertificatePathVCRef path = SecCertificatePathVCCreate(NULL, leaf, NULL); + CFSetAddValue(builder->allPaths, path); + CFArrayAppendValue(builder->partialPaths, path); + + builder->path = CFRetainSafe(path); + SecPathBuilderSetPath(builder, path); + CFRelease(path); + + /* Next step is to process the leaf. We do that work on the builder queue + * to avoid blocking the main thread with database lookups. */ + builder->state = SecPathBuilderProcessLeaf; + builder->completed = completed; + builder->context = context; +} + +SecPathBuilderRef SecPathBuilderCreate(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, + CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, + bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponses, + CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, + SecPathBuilderCompleted completed, const void *context) { + SecPathBuilderRef builder = malloc(sizeof(*builder)); + memset(builder, 0, sizeof(*builder)); + SecPathBuilderInit(builder, builderQueue, clientAuditToken, certificates, + anchors, anchorsOnly, keychainsAllowed, policies, ocspResponses, + signedCertificateTimestamps, trustedLogs, verifyTime, + accessGroups, exceptions, completed, context); + return builder; +} + +/* Don't use this if you're going to modify the PVC array in the operation. */ +static void SecPathBuilderForEachPVC(SecPathBuilderRef builder,void (^operation)(SecPVCRef pvc, bool *stop)) { + if (!builder->pvcs) { return; } + bool stop = false; + CFIndex ix; + for (ix = 0; ix < builder->pvcCount; ix++) { + if (!builder->pvcs[ix]) { continue; } + operation(builder->pvcs[ix], &stop); + if (stop) { break; } + } +} + +static void SecPathBuilderDestroy(SecPathBuilderRef builder) { + secdebug("alloc", "destroy builder %p", builder); + dispatch_release_null(builder->queue); + if (builder->anchorSource) { + SecMemoryCertificateSourceDestroy(builder->anchorSource); + builder->anchorSource = NULL; + } + if (builder->certificateSource) { + SecMemoryCertificateSourceDestroy(builder->certificateSource); + builder->certificateSource = NULL; + } + if (builder->itemCertificateSource) { + SecItemCertificateSourceDestroy(builder->itemCertificateSource); + builder->itemCertificateSource = NULL; + } + if (builder->appleAnchorSource) { + SecMemoryCertificateSourceDestroy(builder->appleAnchorSource); + builder->appleAnchorSource = NULL; + } + CFReleaseNull(builder->clientAuditToken); + CFReleaseNull(builder->anchorSources); + CFReleaseNull(builder->parentSources); + CFReleaseNull(builder->allPaths); + CFReleaseNull(builder->partialPaths); + CFReleaseNull(builder->rejectedPaths); + CFReleaseNull(builder->candidatePaths); + CFReleaseNull(builder->ocspResponses); + CFReleaseNull(builder->signedCertificateTimestamps); + CFReleaseNull(builder->trustedLogs); + CFReleaseNull(builder->path); + CFReleaseNull(builder->revocation_check_method); + CFReleaseNull(builder->info); + CFReleaseNull(builder->exceptions); + + free(builder->analyticsData); + builder->analyticsData = NULL; + + if (builder->pvcs) { + CFIndex ix; + for (ix = 0; ix < builder->pvcCount; ix++) { + if (builder->pvcs[ix]) { + SecPVCDelete(builder->pvcs[ix]); + free(builder->pvcs[ix]); + } + } + free(builder->pvcs); + builder->pvcs = NULL; + } +} + +static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path) { + bool samePath = ((!path && !builder->path) || (path && builder->path && CFEqual(path, builder->path))); + if (!samePath) { + CFRetainAssign(builder->path, path); + } + CFReleaseNull(builder->info); + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCSetPath(pvc, path); + }); +} + + +bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) { + return builder->canAccessNetwork; +} + +void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) { + if (builder->canAccessNetwork != allow) { + builder->canAccessNetwork = allow; + if (allow) { +#if !TARGET_OS_WATCH + secinfo("http", "network access re-enabled by policy"); + /* re-enabling network_access re-adds kSecCAIssuerSource as + a parent source. */ + CFArrayAppendValue(builder->parentSources, kSecCAIssuerSource); +#else + /* */ + secnotice("http", "network access not allowed on WatchOS"); + builder->canAccessNetwork = false; +#endif + } else { + secinfo("http", "network access disabled by policy"); + /* disabling network_access removes kSecCAIssuerSource from + the list of parent sources. */ + CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources, + CFRangeMake(0, CFArrayGetCount(builder->parentSources)), + kSecCAIssuerSource); + if (ix >= 0) + CFArrayRemoveValueAtIndex(builder->parentSources, ix); + } + } +} + +CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder) +{ + return CFRetainSafe(builder->ocspResponses); +} + +CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef builder) +{ + return CFRetainSafe(builder->signedCertificateTimestamps); +} + +CFDictionaryRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder) +{ + return CFRetainSafe(builder->trustedLogs); +} + +SecCertificateSourceRef SecPathBuilderGetAppAnchorSource(SecPathBuilderRef builder) +{ + return builder->anchorSource; +} + +CFSetRef SecPathBuilderGetAllPaths(SecPathBuilderRef builder) +{ + return builder->allPaths; +} + +TrustAnalyticsBuilder *SecPathBuilderGetAnalyticsData(SecPathBuilderRef builder) +{ + return builder->analyticsData; +} + +SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder) +{ + return builder->bestPath; +} + +SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder) { + return builder->path; +} + +CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder) { + return builder->verifyTime; +} + +bool SecPathBuilderHasTemporalParentChecks(SecPathBuilderRef builder) { + __block bool validIntermediates = false; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool *stop) { + CFArrayForEach(pvc->policies, ^(const void *value) { + SecPolicyRef policy = (SecPolicyRef)value; + if (CFDictionaryContainsKey(policy->_options, kSecPolicyCheckTemporalValidity)) { + validIntermediates = true; + *stop = true; + } + }); + }); + return validIntermediates; +} + +CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder) { + return SecCertificatePathVCGetCount(builder->path); +} + +SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix) { + return SecCertificatePathVCGetCertificateAtIndex(builder->path, ix); +} + +bool SecPathBuilderIsAnchored(SecPathBuilderRef builder) { + return SecCertificatePathVCIsAnchored(builder->path); +} + +unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder) { + unsigned int result = atomic_fetch_sub(&builder->asyncJobCount, 1); + secdebug("rvc", "%p: decrement asyncJobCount from %d", builder, result); + /* atomic_fetch_sub returns the original value, but we want this function to return the + * value after the operation. */ + return --result; +} + +void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount) { + atomic_store(&builder->asyncJobCount, jobCount); + secdebug("rvc", "%p: set asyncJobCount to %d", builder, jobCount); +} + +unsigned int SecPathBuilderGetAsyncJobCount(SecPathBuilderRef builder) { + unsigned int count = atomic_load(&builder->asyncJobCount); + secdebug("rvc", "%p: current asyncJobCount is %d", builder, count); + return count; +} + +CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder) { + return builder->info; +} + +CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder) { + return builder->revocation_check_method; +} + +void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method) { + CFRetainAssign(builder->revocation_check_method, method); + secdebug("rvc", "deferred revocation checking enabled using %@ method", method); +} + +bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder) { + return builder->online_revocation; +} + +void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder) { + builder->online_revocation = true; + secdebug("rvc", "revocation force online check"); +} + +bool SecPathBuilderGetCheckRevocationIfTrusted(SecPathBuilderRef builder) { + return builder->trusted_revocation; +} + +void SecPathBuilderSetCheckRevocationIfTrusted(SecPathBuilderRef builder) { + builder->trusted_revocation = true; + secdebug("rvc", "revocation check only if trusted"); +} + +CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder) { + return builder->exceptions; +} + +CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder) { + return builder->pvcCount; +} + +SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix) { + if (ix > (builder->pvcCount - 1)) { + return NULL; + } + return builder->pvcs[ix]; +} + +void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, + CFIndex ix, CFTypeRef result, bool force) { + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCSetResultForced(pvc, key, ix, result, force); + }); +} + +static bool SecPathBuilderIsOkResult(SecPathBuilderRef builder) { + /* If any of the PVCs passed, we accept the path. */ + __block bool acceptPath = false; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + acceptPath |= SecPVCIsOkResult(pvc); + }); + return acceptPath; +} + +SecPVCRef SecPathBuilderGetResultPVC(SecPathBuilderRef builder) { + /* Return the first PVC that passed */ + __block SecPVCRef resultPVC = NULL; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool *stop) { + if (SecPVCIsOkResult(pvc)) { + resultPVC = pvc; + *stop = true; + } + }); + if (resultPVC) { return resultPVC; } + + /* If we didn't return a passing PVC, return the first PVC. */ + return builder->pvcs[0]; +} + +/* This function assumes that the input source is an anchor source */ +static bool SecPathBuilderIsAnchorPerConstraints(SecPathBuilderRef builder, SecCertificateSourceRef source, + SecCertificateRef certificate) { + + /* Get the trust settings result for the PVCs. Only one PVC need match to + * trigger the anchor behavior -- policy validation will handle whether the + * path is truly anchored for that PVC. */ + __block bool result = false; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + if (SecPVCIsAnchorPerConstraints(pvc, source, certificate)) { + result = true; + *stop = true; + } + }); + + return result; +} + +/* Source returned in foundInSource has the same lifetime as the builder. */ +static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, + SecCertificateRef certificate, SecCertificateSourceRef *foundInSource) { + /* We look through the anchor sources in order. They are ordered in + SecPathBuilderInit so that process anchors override user anchors which + override system anchors. */ + CFIndex count = CFArrayGetCount(builder->anchorSources); + CFIndex ix; + for (ix = 0; ix < count; ++ix) { + SecCertificateSourceRef source = (SecCertificateSourceRef) + CFArrayGetValueAtIndex(builder->anchorSources, ix); + if (SecCertificateSourceContains(source, certificate)) { + if (foundInSource) + *foundInSource = source; + if (SecPathBuilderIsAnchorPerConstraints(builder, source, certificate)) { + return true; + } + } + } + return false; +} + +bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source) { + CFIndex anchorCount = CFArrayGetCount(builder->anchorSources); + return CFArrayContainsValue(builder->anchorSources, CFRangeMake(0,anchorCount), source); +} + +/* Return false if path is not a partial, if path was a valid candidate it + will have been added to builder->candidatePaths, if path was rejected + by the parent certificate checks (because it's expired or some other + static chaining check failed) it will have been added to rejectedPaths. + Return true path if path is a partial. */ +static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, + SecCertificatePathVCRef path) { + SecPathBuilderSetPath(builder, path); + __block bool parentChecksFail = true; + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + /* The parent checks aren't actually PVC-dependent, so theoretically, + * we only need to run this once per path, but we want to set the + * results in all PVCs. */ + parentChecksFail &= !SecPVCParentCertificateChecks(pvc, + SecCertificatePathVCGetCount(path) - 1); + }); + + if (!builder->considerRejected && parentChecksFail) { + secdebug("trust", "Found rejected path %@", path); + CFArrayAppendValue(builder->rejectedPaths, path); + return false; + } + + SecPathVerifyStatus vstatus = SecCertificatePathVCVerify(path); + /* Candidate paths with failed signatures are discarded. */ + if (vstatus == kSecPathVerifyFailed) { + secdebug("trust", "Verify failed for path %@", path); + return false; + } + + if (vstatus == kSecPathVerifySuccess) { + /* The signature chain verified successfully, now let's find + out if we have an anchor for path. */ + if (SecCertificatePathVCIsAnchored(path)) { + secdebug("trust", "Adding candidate %@", path); + CFArrayAppendValue(builder->candidatePaths, path); + } + /* The path is not partial if the last cert is self-signed. + * The path is also not partial if the issuer of the last cert was the subject + * of a previous cert in the chain, indicating a cycle in the graph. See . */ + if (((SecCertificatePathVCSelfSignedIndex(path) >= 0) && + (SecCertificatePathVCSelfSignedIndex(path) == SecCertificatePathVCGetCount(path)-1)) || + SecCertificatePathVCIsCycleInGraph(path)) { + if (!builder->considerRejected) { + secdebug("trust", "Adding non-partial non-anchored reject %@", path); + CFArrayAppendValue(builder->rejectedPaths, path); + } else { + /* This path was previously rejected as unanchored non-partial, but now that + * we're considering rejected paths, this is a candidate. */ + secdebug("trust", "Adding non-partial non-anchored candidate %@", path); + CFArrayAppendValue(builder->candidatePaths, path); + } + return false; + } + } + + return true; +} + +static void addOptionsToPolicy(SecPolicyRef policy, CFDictionaryRef newOptions) { + __block CFMutableDictionaryRef oldOptions = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options); + CFDictionaryForEach(newOptions, ^(const void *key, const void *value) { + CFDictionaryAddValue(oldOptions, key, value); + }); + CFAssignRetained(policy->_options, oldOptions); +} + +static void SecPathBuilderAddPinningPolicies(SecPathBuilderRef builder) { + CFIndex ix, initialPVCCount = builder->pvcCount; + for (ix = 0; ix < initialPVCCount; ix++) { + CFArrayRef policies = CFRetainSafe(builder->pvcs[ix]->policies); + CFIndex policyIX; + for (policyIX = 0; policyIX < CFArrayGetCount(policies); policyIX++) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + CFStringRef policyName = SecPolicyGetName(policy); + CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); + if (!hostname) { continue; } //No hostname to look up; probably not an SSL policy, skip + + /* Query the pinning database for this policy */ + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(query, kSecPinningDbKeyPolicyName, policyName); + CFDictionaryAddValue(query, kSecPinningDbKeyHostname, hostname); + CFDictionaryRef results = SecPinningDbCopyMatching(query); + CFReleaseNull(query); + if (!results) { continue; } //No rules for this hostname or policyName + + /* Found pinning policies. Apply them to the path builder. */ + CFArrayRef newRules = CFDictionaryGetValue(results, kSecPinningDbKeyRules); + CFStringRef dbPolicyName = CFDictionaryGetValue(results, kSecPinningDbKeyPolicyName); + secinfo("SecPinningDb", "found pinning %lu %@ policies for hostname %@, policyName %@", + (unsigned long)CFArrayGetCount(newRules), dbPolicyName, hostname, policyName); + CFIndex newRulesIX; + for (newRulesIX = 0; newRulesIX < CFArrayGetCount(newRules); newRulesIX++) { + if (!isDictionary(CFArrayGetValueAtIndex(newRules, newRulesIX))) { + continue; + } + + /* Create the new policies with pinning rules (preserving other ANDed policies). */ + CFDictionaryRef newOptions = (CFDictionaryRef)CFArrayGetValueAtIndex(newRules, newRulesIX); + SecPolicyRef newPolicy = SecPolicyCreateSSL(true, hostname); + if (!newPolicy) { continue; } + addOptionsToPolicy(newPolicy, newOptions); + SecPolicySetName(newPolicy, dbPolicyName); + CFMutableArrayRef newPolicies = CFArrayCreateMutableCopy(NULL, 0, policies); + if (!newPolicies) { CFReleaseNull(newPolicy); continue; } + CFArrayReplaceValues(newPolicies, CFRangeMake(policyIX, 1), (const void **)&newPolicy, 1); + + if (newRulesIX == 0) { + /* For the first set of pinning rules, replace this PVC's policies */ + CFRetainAssign(builder->pvcs[ix]->policies, newPolicies); + } else { + /* If there were two or more dictionaries of rules, we need to treat them as an "OR". + * Create another PVC for this dicitionary. */ + builder->pvcs = realloc(builder->pvcs, (builder->pvcCount + 1) * sizeof(SecPVCRef)); + builder->pvcs[builder->pvcCount] = malloc(sizeof(struct OpaqueSecPVC)); + SecPVCInit(builder->pvcs[builder->pvcCount], builder, newPolicies); + builder->pvcCount++; + } + CFReleaseNull(newPolicy); + CFReleaseNull(newPolicies); + } + CFReleaseNull(results); + } + CFReleaseNull(policies); + } +} + +static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder) { + SecPathBuilderAddPinningPolicies(builder); + + /* We need to find and set constraints on the leaf-only path */ + SecCertificatePathVCRef path = builder->path; + SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0); + + SecCertificateSourceRef source = NULL; + bool isAnchor = false; + CFArrayRef constraints = NULL; + if (SecPathBuilderIsAnchor(builder, leaf, &source)) { + isAnchor = true; + } + if (source) { + constraints = SecCertificateSourceCopyUsageConstraints(source, leaf); + } + SecCertificatePathVCSetUsageConstraintsAtIndex(path, constraints, 0); + CFReleaseSafe(constraints); + if (isAnchor) { + SecCertificatePathVCSetIsAnchored(path); + CFArrayAppendValue(builder->candidatePaths, path); + } + + __block bool leafChecksFail = true; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCLeafChecks(pvc); + leafChecksFail &= !SecPVCIsOkResult(pvc); + }); + builder->considerRejected = leafChecksFail; + + builder->state = SecPathBuilderGetNext; + return true; +} + +/* Given the builder, a partial chain partial and the parents array, construct + a SecCertificatePath for each parent. After discarding previously + considered paths and paths with cycles, sort out which array each path + should go in, if any. */ +static void SecPathBuilderProcessParents(SecPathBuilderRef builder, + SecCertificatePathVCRef partial, CFArrayRef parents) { + CFIndex rootIX = SecCertificatePathVCGetCount(partial) - 1; + CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0; + CFIndex parentIX; + for (parentIX = 0; parentIX < num_parents; ++parentIX) { + SecCertificateRef parent = (SecCertificateRef) + CFArrayGetValueAtIndex(parents, parentIX); + CFIndex ixOfParent = SecCertificatePathVCGetIndexOfCertificate(partial, + parent); + if (ixOfParent != kCFNotFound) { + /* partial already contains parent. Let's not add the same + certificate again. */ + if (ixOfParent == rootIX) { + /* parent is equal to the root of the partial, so partial + looks to be self issued. */ + SecCertificatePathVCSetSelfIssued(partial); + } + continue; + } + + /* FIXME Add more sanity checks to see that parent really can be + a parent of partial_root. subjectKeyID == authorityKeyID, + signature algorithm matches public key algorithm, etc. */ + SecCertificateSourceRef source = NULL; + bool is_anchor = SecPathBuilderIsAnchor(builder, parent, &source); + CFArrayRef constraints = (source) ? SecCertificateSourceCopyUsageConstraints(source, parent) : NULL; + SecCertificatePathVCRef path = SecCertificatePathVCCreate(partial, parent, constraints); + CFReleaseSafe(constraints); + if (!path) + continue; + if (!CFSetContainsValue(builder->allPaths, path)) { + CFSetAddValue(builder->allPaths, path); + if (is_anchor) + SecCertificatePathVCSetIsAnchored(path); + if (SecPathBuilderIsPartial(builder, path)) { + /* Insert path right at the current position since it's a new + candiate partial. */ + CFArrayInsertValueAtIndex(builder->partialPaths, + ++builder->partialIX, path); + secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@", + parentIX + 1, num_parents, path); + } + secdebug("trust", "found new path %@", path); + } + CFRelease(path); + } +} + +/* Callback for the SecPathBuilderGetNext() functions call to + SecCertificateSourceCopyParents(). */ +static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) { + SecPathBuilderRef builder = (SecPathBuilderRef)context; + SecCertificatePathVCRef partial = (SecCertificatePathVCRef) + CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); + secdebug("async", "%@ parents %@", partial, parents); + SecPathBuilderProcessParents(builder, partial, parents); + + builder->state = SecPathBuilderGetNext; + SecPathBuilderStep(builder); +} + +static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { + /* If we have any candidates left to go return those first. */ + if (CFArrayGetCount(builder->candidatePaths)) { + SecCertificatePathVCRef path = (SecCertificatePathVCRef) + CFArrayGetValueAtIndex(builder->candidatePaths, 0); + CFArrayRemoveValueAtIndex(builder->candidatePaths, 0); + secdebug("trust", "SecPathBuilderGetNext returning candidate %@", + path); + SecPathBuilderSetPath(builder, path); + builder->state = SecPathBuilderValidatePath; + return true; + } + + /* If we are considering rejected chains we check each rejected path + with SecPathBuilderIsPartial() which checks the signature chain and + either drops the path if it's not properly signed, add it as a + candidate if it has a trusted anchor, or adds it as a partial + to be considered once we finish considering all the rejects. */ + if (builder->considerRejected) { + CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths); + if (rejectedIX) { + rejectedIX--; + SecCertificatePathVCRef path = (SecCertificatePathVCRef) + CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX); + if (SecPathBuilderIsPartial(builder, path)) { + CFArrayInsertValueAtIndex(builder->partialPaths, + ++builder->partialIX, path); + } + CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX); + + /* Keep going until we have moved all rejected partials into + the regular partials or candidates array. */ + return true; + } + } + + /* If builder->partialIX is < 0 we have considered all partial chains + this block must ensure partialIX >= 0 if execution continues past + it's end. */ + if (builder->partialIX < 0) { + CFIndex num_sources = CFArrayGetCount(builder->parentSources); + if (builder->nextParentSource < num_sources) { + builder->nextParentSource++; + secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources", + builder->nextParentSource, num_sources); + } else { + /* We've run out of new sources to consider so let's look at + rejected chains and after that even consider partials + directly. + FIXME we might not want to consider partial paths that + are subsets of other partial paths, or not consider them + at all if we already have an (unpreferred) accept or anchored reject */ + if (!builder->considerRejected) { + builder->considerRejected = true; + secdebug("trust", "considering rejected paths"); + } else if (!builder->considerPartials) { + builder->considerPartials = true; + secdebug("trust", "considering partials"); + } else { + /* We're all out of options, so we can't produce any more + candidates. Let's calculate details and return the best + path we found. */ + builder->state = SecPathBuilderComputeDetails; + return true; + } + } + builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1; + secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1); + return true; + } + + /* We know builder->partialIX >= 0 if we get here. */ + SecCertificatePathVCRef partial = (SecCertificatePathVCRef) + CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); + /* Don't try to extend partials anymore once we are in the considerPartials + state, since at this point every partial has been extended with every + possible parentSource already. */ + if (builder->considerPartials) { + --builder->partialIX; + SecPathBuilderSetPath(builder, partial); + builder->state = SecPathBuilderValidatePath; + return true; + } + + /* Don't try to extend partials anymore if we already have too many chains. */ + if (CFSetGetCount(builder->allPaths) > MAX_NUM_CHAINS) { + secnotice("trust", "not building any more paths, already have %" PRIdCFIndex, + CFSetGetCount(builder->allPaths)); + builder->partialIX = -1; + return true; + } + + /* Attempt to extend this partial path with another certificate. This + should give us a list of potential parents to consider. */ + secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@", + builder->partialIX + 1, CFArrayGetCount(builder->partialPaths), + partial); + + /* Attempt to extend partial, leaving all possible extended versions + of partial in builder->extendedPaths. */ + CFIndex sourceIX = SecCertificatePathVCGetNextSourceIndex(partial); + CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources); + if (sourceIX < num_anchor_sources + builder->nextParentSource) { + SecCertificateSourceRef source; + if (sourceIX < num_anchor_sources) { + source = (SecCertificateSourceRef) + CFArrayGetValueAtIndex(builder->anchorSources, sourceIX); + secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1, + num_anchor_sources); + } else { + CFIndex parentIX = sourceIX - num_anchor_sources; + source = (SecCertificateSourceRef) + CFArrayGetValueAtIndex(builder->parentSources, parentIX); + secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1, + builder->nextParentSource); + } + SecCertificatePathVCSetNextSourceIndex(partial, sourceIX + 1); + SecCertificateRef root = SecCertificatePathVCGetRoot(partial); + return SecCertificateSourceCopyParents(source, root, + builder, SecPathBuilderExtendPaths); + } else { + --builder->partialIX; + } + + return true; +} + +/* One or more of the policies did not accept the candidate path. */ +static void SecPathBuilderReject(SecPathBuilderRef builder) { + check(builder); + + builder->state = SecPathBuilderGetNext; + + bool bestPathIsEV = SecCertificatePathVCIsEV(builder->bestPath); + bool isEV = SecCertificatePathVCIsEV(builder->path); + + if (bestPathIsEV && !isEV) { + /* We never replace an ev reject with a non ev reject. */ + return; + } + + CFIndex bestPathScore = SecCertificatePathVCGetScore(builder->bestPath); + CFIndex score = SecCertificatePathVCScore(builder->path, builder->verifyTime); + SecCertificatePathVCSetScore(builder->path, score); + + /* The current chain is valid for EV, but revocation checking failed. We + replace any previously accepted or rejected non EV chains with the + current one. */ + if (isEV && !bestPathIsEV) { + bestPathScore = 0; + } + if (!builder->bestPath || score > bestPathScore) { + if (builder->bestPath) { + secinfo("reject", + "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", + (bestPathIsEV ? "" : "non "), + (bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), + bestPathScore, + (isEV ? "" : "non "), (long)score, builder->path); + } else { + secinfo("reject", "%sev score: %" PRIdCFIndex " %@", + (isEV ? "" : "non "), score, builder->path); + } + + builder->bestPath = builder->path; + } else { + secinfo("reject", "%sev score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@", + (isEV ? "" : "non "), score, bestPathScore, builder->path); + } +} + +/* All policies accepted the candidate path. */ +static void SecPathBuilderAccept(SecPathBuilderRef builder) { + if (!builder) { return; } + bool isSHA2 = !SecCertificatePathVCHasWeakHash(builder->path); + bool isOptionallySHA2 = !SecCertificateIsWeakHash(SecPathBuilderGetCertificateAtIndex(builder, 0)); + bool isEV = SecCertificatePathVCIsEV(builder->path); + bool isOptionallyEV = SecCertificatePathVCIsOptionallyEV(builder->path); + CFIndex bestScore = SecCertificatePathVCGetScore(builder->bestPath); + /* Score this path. Note that all points awarded or deducted in + * SecCertificatePathScore are < 100,000 */ + CFIndex currScore = (SecCertificatePathVCScore(builder->path, builder->verifyTime) + + ACCEPT_PATH_SCORE + // 10,000,000 points for accepting + (isEV ? 1000000 : 0)); //1,000,000 points for EV + SecCertificatePathVCSetScore(builder->path, currScore); + if (currScore > bestScore) { + // current path is better than existing best path + secinfo("accept", "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", + (SecCertificatePathVCIsEV(builder->bestPath) ? "" : "non "), + (bestScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), + bestScore, + (isEV ? "" : "non "), (long)currScore, builder->path); + + builder->bestPath = builder->path; + } + + /* If we found the best accept we can, we want to switch directly to the + SecPathBuilderComputeDetails state here, since we're done. */ + if ((isEV || !isOptionallyEV) && (isSHA2 || !isOptionallySHA2)) + builder->state = SecPathBuilderComputeDetails; + else + builder->state = SecPathBuilderGetNext; +} + +/* Return true iff a given path satisfies all the specified policies at + verifyTime. */ +static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) { + + if (builder->considerRejected) { + SecPathBuilderReject(builder); + return true; + } + + builder->state = SecPathBuilderDidValidatePath; + + /* Revocation checking is now done before path checks, to ensure that + we have OCSP responses for CT checking and that isAllowlisted is + appropriately set for other checks. */ + bool completed = SecPathBuilderCheckRevocation(builder); + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathChecks(pvc); + }); + + return completed; +} + +static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) { + /* We perform the revocation required policy checks here because + * this is the state we call back into once all the asynchronous + * revocation check calls are done. */ + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathCheckRevocationResponsesReceived(pvc); + }); + + if (SecPathBuilderIsOkResult(builder)) { + SecPathBuilderAccept(builder); + } else { + SecPathBuilderReject(builder); + } + assert(builder->state != SecPathBuilderDidValidatePath); + return true; +} + +static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) { + /* We have to re-do all the checks so that the results get set in the + * PVC for the best path, as the last path checked may not have been the best. */ + SecPathBuilderSetPath(builder, builder->bestPath); + __block CFIndex ix, pathLength = SecCertificatePathVCGetCount(builder->bestPath); + + __block bool completed = true; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCComputeDetails(pvc, builder->bestPath); + completed &= SecPathBuilderCheckRevocation(builder); + for (ix = 1; ix < pathLength; ++ix) { + SecPVCParentCertificateChecks(pvc, ix); + } + SecPVCPathChecks(pvc); + }); + + builder->state = SecPathBuilderReportResult; + + /* Check revocation responses. */ + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathCheckRevocationResponsesReceived(pvc); + }); + + /* Reject the certificate if it was accepted before but we failed it now. (Should not happen anymore.) */ + if (SecCertificatePathVCGetScore(builder->bestPath) > ACCEPT_PATH_SCORE && !SecPathBuilderIsOkResult(builder)) { + SecCertificatePathVCResetScore(builder->bestPath); + secwarning("In ComputeDetails, we got a reject after an accept in DidValidatePath."); + } + + return completed; +} + +static bool SecPathBuilderReportResult(SecPathBuilderRef builder) { + builder->info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + + /* isEV is not set unless also CT verified. Here, we need to check that we + * got a revocation response as well. */ + if (builder->info && SecCertificatePathVCIsEV(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { +#if !TARGET_OS_WATCH + if (SecCertificatePathVCIsRevocationDone(builder->bestPath)) { + CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); + if (nextUpdate != 0) { +#else + /* We don't do networking on watchOS, so we can't require OCSP for EV */ + { + { +#endif + /* Successful revocation check, so this cert is EV */ + CFDictionarySetValue(builder->info, kSecTrustInfoExtendedValidationKey, + kCFBooleanTrue); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustExtendedValidation, + kCFBooleanTrue); /* unified API key */ + SecCertificateRef leaf = SecPathBuilderGetCertificateAtIndex(builder, 0); + CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf); + if (leafCompanyName) { + CFDictionarySetValue(builder->info, kSecTrustInfoCompanyNameKey, + leafCompanyName); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustOrganizationName, + leafCompanyName); /* unified API key */ + CFRelease(leafCompanyName); + } + } + } + } + + if (builder->info && SecPathBuilderIsOkResult(builder) && SecCertificatePathVCIsRevocationDone(builder->bestPath)) { + CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); + if (nextUpdate != 0) { + /* always populate revocation info for successful revocation check */ + CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate); + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationValidUntilKey, + validUntil); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustRevocationValidUntilDate, + validUntil); /* unified API key */ + CFRelease(validUntil); + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, + kCFBooleanTrue); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, + kCFBooleanTrue); /* unified API key */ + } else if (SecCertificatePathVCIsEV(builder->bestPath)) { + /* populate revocation info for failed revocation check with EV */ + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, + kCFBooleanFalse); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, + kCFBooleanFalse); /* unified API key */ + } + } + + /* If revoked, set the revocation reason */ + if (builder->info && !SecPathBuilderIsOkResult(builder) && SecCertificatePathVCIsRevocationDone(builder->bestPath) + && SecCertificatePathVCGetRevocationReason(builder->bestPath)) { + CFNumberRef reason = SecCertificatePathVCGetRevocationReason(builder->bestPath); + CFDictionarySetValue(builder->info, kSecTrustRevocationReason, reason); + } + + /* Set CT marker in the info */ + if (builder->info && SecCertificatePathVCIsCT(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { + CFDictionarySetValue(builder->info, kSecTrustInfoCertificateTransparencyKey, + kCFBooleanTrue); + } + + + /* This will trigger the outer step function to call the completion + function. */ + builder->state = NULL; + return false; +} + +/* @function SecPathBuilderStep + @summary This is the core of the async engine. + @description Return false iff job is complete, true if a network request + is pending. + builder->state is a function pointer which is to be invoked. + If you call this function from within a builder->state invocation it + immediately returns true. + Otherwise the following steps are repeated endlessly (unless a step returns) + builder->state is invoked. If it returns true and builder->state is still + non NULL this proccess is repeated. + If a state returns false, SecPathBuilder will return true + if builder->state is non NULL. + If builder->state is NULL then regardless of what the state function returns + the completion callback will be invoked and the builder will be deallocated. + */ +bool SecPathBuilderStep(SecPathBuilderRef builder) { + secdebug("async", "step builder %p", builder); + if (builder->activations) { + secdebug("async", "activations: %lu returning true", + builder->activations); + return true; + } + + secdebug("async", "activations: %lu", builder->activations); + builder->activations++; + while (builder->state && builder->state(builder)); + --builder->activations; + + if (builder->state) { + secdebug("async", "waiting for async reply, exiting"); + /* A state returned false, it's waiting for network traffic. Let's + return. */ + return true; + } + + if (builder->activations) { + /* There is still at least one other running instance of this builder + somewhere on the stack, we let that instance take care of sending + the client a response. */ + return false; + } + + SecPVCRef pvc = SecPathBuilderGetResultPVC(builder); + SecTrustResultType result = pvc->result; + + if (builder->exceptions && pvc->result == kSecTrustResultUnspecified) { + result = kSecTrustResultProceed; + } + + secinfo("trust", "completed: %@ details: %@ result: %d", + builder->bestPath, pvc->details, result); + + if (builder->completed) { + /* We want to retain just the data we need to return to our caller + * and free the rest of the builder before doing the callback. + * Since the callback may end an XPC transaction that made us active, we + * want to retain as little residual memory as possible. */ + CFArrayRef resultPath = SecCertificatePathVCCopyCertificates(builder->bestPath); + CFDictionaryRef info = CFRetainSafe(builder->info); + CFArrayRef details = CFRetainSafe(pvc->details); + const void *context = builder->context; + SecPathBuilderCompleted completed = builder->completed; + + secdebug("async", "free builder"); + SecPathBuilderDestroy(builder); + free(builder); + + secdebug("async", "returning to caller"); + completed(context, resultPath, details, info, result); + CFReleaseNull(resultPath); + CFReleaseNull(info); + CFReleaseNull(details); + } else { + SecPathBuilderDestroy(builder); + free(builder); + } + + return false; +} + +dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) { + return (builder) ? builder->queue : NULL; +} + +CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder) { + return (builder) ? (CFDataRef)CFRetainSafe(builder->clientAuditToken) : NULL; +} + +// MARK: - +// MARK: SecTrustServer +/******************************************************** + ****************** SecTrustServer ********************** + ********************************************************/ + +typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error); + +static void +SecTrustServerEvaluateCompleted(const void *userData, + CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, + SecTrustResultType result) { + SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData; + TrustdHealthAnalyticsLogEvaluationCompleted(); + evaluated(result, details, info, chain, NULL); + Block_release(evaluated); +} + +void +SecTrustServerEvaluateBlock(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error)) { + /* We need an array containing at least one certificate to proceed. */ + if (!isArray(certificates) || !(CFArrayGetCount(certificates) > 0)) { + CFErrorRef certError = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL); + evaluated(kSecTrustResultInvalid, NULL, NULL, NULL, certError); + CFReleaseSafe(certError); + return; + } + SecTrustServerEvaluationCompleted userData = Block_copy(evaluated); + /* Call the actual evaluator function. */ + SecPathBuilderRef builder = SecPathBuilderCreate(builderQueue, clientAuditToken, + certificates, anchors, + anchorsOnly, keychainsAllowed, policies, + responses, SCTs, trustedLogs, + verifyTime, accessGroups, exceptions, + SecTrustServerEvaluateCompleted, userData); + SecPathBuilderStep(builder); +} + + +// NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly +SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *pdetails, CFDictionaryRef *pinfo, CFArrayRef *pchain, CFErrorRef *perror) { + dispatch_semaphore_t done = dispatch_semaphore_create(0); + __block SecTrustResultType result = kSecTrustResultInvalid; + __block dispatch_queue_t queue = dispatch_queue_create("com.apple.trustd.evaluation.recursive", DISPATCH_QUEUE_SERIAL); + + /* We need to use the async call with the semaphore here instead of a synchronous call because we may return from + * SecPathBuilderStep while waiting for an asynchronous network call in order to complete the evaluation. That return + * is necessary in the XPC interface in order to free up the workloop for other trust evaluations while we wait for + * the networking to complete, but here, we need to make sure we wait for the network call (which will async back + * onto our queue) to complete and signal us before we return to the "inline" caller. */ + dispatch_async(queue, ^{ + SecTrustServerEvaluateBlock(queue, NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, exceptions, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error) { + result = tr; + if (tr == kSecTrustResultInvalid) { + if (perror) { + *perror = error; + CFRetainSafe(error); + } + } else { + if (pdetails) { + *pdetails = details; + CFRetainSafe(details); + } + if (pinfo) { + *pinfo = info; + CFRetainSafe(info); + } + if (pchain) { + *pchain = chain; + CFRetainSafe(chain); + } + } + dispatch_semaphore_signal(done); + }); + }); + dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER); + dispatch_release(done); + dispatch_release_null(queue); + + return result; +} diff --git a/trust/trustd/SecTrustServer.h b/trust/trustd/SecTrustServer.h new file mode 100644 index 00000000..531ba549 --- /dev/null +++ b/trust/trustd/SecTrustServer.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2008-2009,2012-2014,2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * SecTrustServer.h - certificate trust evaluation engine + * + * + */ + +#ifndef _SECURITY_SECTRUSTSERVER_H_ +#define _SECURITY_SECTRUSTSERVER_H_ + +#include + +#include +#include /* For errSecWaitForCallback. */ +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include + +__BEGIN_DECLS + +typedef struct SecPathBuilder *SecPathBuilderRef; + +typedef struct OpaqueSecPVC *SecPVCRef; + +struct OpaqueSecPVC { + SecPathBuilderRef builder; + CFArrayRef policies; + CFDictionaryRef callbacks; + CFIndex policyIX; + bool require_revocation_response; + + CFArrayRef leafDetails; + SecTrustResultType leafResult; + + CFArrayRef details; + SecTrustResultType result; +}; + +/* Completion callback. */ +typedef void(*SecPathBuilderCompleted)(const void *userData, + CFArrayRef chain, CFArrayRef details, CFDictionaryRef info, + SecTrustResultType result); + +/* Returns a new trust path builder and policy evaluation engine instance. */ +SecPathBuilderRef SecPathBuilderCreate(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, + CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, + bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponse, + CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, + SecPathBuilderCompleted completed, const void *userData); + +/* Returns true if it's ok to perform network operations for this builder. */ +bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder); + +/* Disable or enable network access for this builder if allow is false + network access will be disabled. */ +void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow); + +/* Get the stapled SCTs */ +CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef builder); +CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder); +CFDictionaryRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder); + +CFSetRef SecPathBuilderGetAllPaths(SecPathBuilderRef builder); +SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder); +SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder); +CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder); +CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder); +SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix); +CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder); +bool SecPathBuilderHasTemporalParentChecks(SecPathBuilderRef builder); + +/* Returns the isAnchored status of the path. The path builder sets isAnchored + * based solely on whether the terminating cert has some sort of trust setting + * on it. This check does NOT reflect whether that anchor is actually trusted, + * as trust in an anchor is contextual to the policy being validated. */ +bool SecPathBuilderIsAnchored(SecPathBuilderRef builder); +bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source); +SecCertificateSourceRef SecPathBuilderGetAppAnchorSource(SecPathBuilderRef builder); + +CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder); +SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix); + +/* Returns the first PVC that passed */ +SecPVCRef SecPathBuilderGetResultPVC(SecPathBuilderRef builder); + +void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, + CFIndex ix, CFTypeRef result, bool force); + +/* This is an atomic pre-decrement operation */ +unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder); +void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount); +unsigned int SecPathBuilderGetAsyncJobCount(SecPathBuilderRef builder); + +CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder); + +/* Enable revocation checking if the rest of the policy checks succeed. */ +CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder); +void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method); + +/* Require a online revocation response for the chain. */ +bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder); +void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder); + +/* Only do networking for revocation if the chain is trusted */ +bool SecPathBuilderGetCheckRevocationIfTrusted(SecPathBuilderRef builder); +void SecPathBuilderSetCheckRevocationIfTrusted(SecPathBuilderRef builder); + +/* Core of the trust evaluation engine, this will invoke the completed + callback and return false if the evaluation completed, or return true if + the evaluation is still waiting for some external event (usually the + network). */ +bool SecPathBuilderStep(SecPathBuilderRef builder); + +/* Return the dispatch queue to be used by this builder. */ +dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder); + +/* Return the client audit token associated with this path builder, + which caller must release, or NULL if there is no external client. */ +CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder); + +/* Evaluate trust and call evaluated when done. */ +void SecTrustServerEvaluateBlock(dispatch_queue_t builderQueue, CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error)); + +/* Synchronously invoke SecTrustServerEvaluateBlock. */ +SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *details, CFDictionaryRef *info, CFArrayRef *chain, CFErrorRef *error); + +/* TrustAnalytics builder types */ +typedef CF_OPTIONS(uint8_t, TA_SCTSource) { + TA_SCTEmbedded = 1 << 0, + TA_SCT_OCSP = 1 << 1, + TA_SCT_TLS = 1 << 2, +}; + +typedef CF_ENUM(uint8_t, TA_CTFailureReason) { + TA_CTNoFailure = 0, + TA_CTNoSCTs = 1, + TA_CTMissingLogs = 2, + TA_CTNoCurrentSCTsUnknownLog = 3, + TA_CTNoCurrentSCTsDisqualifiedLog = 4, + TA_CTPresentedNotEnoughUnknown = 5, + TA_CTPresentedNotEnoughDisqualified = 6, + TA_CTPresentedNotEnough = 7, + TA_CTEmbeddedNotEnoughUnknown = 8, + TA_CTEmbeddedNotEnoughDisqualified = 9, + TA_CTEmbeddedNotEnough = 10, +}; + +typedef CF_OPTIONS(uint8_t, TAValidStatus) { + TAValidDefinitelyOK = 1 << 0, + TAValidProbablyOK = 1 << 1, + TAValidProbablyRevoked = 1 << 2, + TAValidDefinitelyRevoked = 1 << 3, + TAValidDateConstrainedOK = 1 << 4, + TAValidDateConstrainedRevoked = 1 << 5, + TAValidPolicyConstrainedOK = 1 << 6, + TAValidPolicyConstrainedDenied = 1 << 7, +}; + +typedef struct { + uint64_t start_time; + // Certificate Transparency + TA_SCTSource sct_sources; + uint32_t number_scts; + uint32_t number_trusted_scts; + TA_CTFailureReason ct_failure_reason; + bool ct_one_current; + // CAIssuer + bool ca_issuer_cache_hit; + bool ca_issuer_network; + uint32_t ca_issuer_fetches; + uint64_t ca_issuer_fetch_time; + uint32_t ca_issuer_fetch_failed; + bool ca_issuer_unsupported_data; + bool ca_issuer_multiple_certs; + // OCSP + bool ocsp_no_check; + bool ocsp_cache_hit; + bool ocsp_network; + uint32_t ocsp_fetches; + uint64_t ocsp_fetch_time; + uint32_t ocsp_fetch_failed; + bool ocsp_validation_failed; + // Valid + TAValidStatus valid_status; + bool valid_trigger_ocsp; + bool valid_require_ct; + bool valid_known_intermediates_only; + bool valid_unknown_intermediate; +} TrustAnalyticsBuilder; + +TrustAnalyticsBuilder *SecPathBuilderGetAnalyticsData(SecPathBuilderRef builder); + +__END_DECLS + +#endif /* !_SECURITY_SECTRUSTSERVER_H_ */ diff --git a/trust/trustd/SecTrustStoreServer.c b/trust/trustd/SecTrustStoreServer.c new file mode 100644 index 00000000..88de9d23 --- /dev/null +++ b/trust/trustd/SecTrustStoreServer.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2007-2010,2012-2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecTrustStoreServer.c - CertificateSource API to a system root certificate store + */ +#include "SecTrustStoreServer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "trust/trustd/SecTrustStoreServer.h" +#include "utilities/sqlutils.h" +#include "utilities/SecDb.h" +#include +#include "utilities/SecFileLocations.h" +#include +#include "trust/trustd/SecTrustLoggingServer.h" +#include +#include +#include +#include + +/* uid of the _securityd user. */ +#define SECURTYD_UID 64 + +static dispatch_once_t kSecTrustStoreUserOnce; +static SecTrustStoreRef kSecTrustStoreUser = NULL; + +static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?"; +static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?"; +static const char insertSQL[] = "INSERT OR REPLACE INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)"; +static const char deleteSQL[] = "DELETE FROM tsettings WHERE sha1=?"; +static const char deleteAllSQL[] = "BEGIN EXCLUSIVE TRANSACTION; DELETE from tsettings; COMMIT TRANSACTION; VACUUM;"; +static const char copyAllSQL[] = "SELECT data,tset FROM tsettings ORDER BY sha1"; +static const char countAllSQL[] = "SELECT COUNT(*) FROM tsettings"; + +#define kSecTrustStoreName CFSTR("TrustStore") +#define kSecTrustStoreDbExtension CFSTR("sqlite3") + +#define kTrustStoreFileName CFSTR("TrustStore.sqlite3") + + +struct __SecTrustStore { + dispatch_queue_t queue; + sqlite3 *s3h; + sqlite3_stmt *copyParents; + sqlite3_stmt *contains; + bool readOnly; + bool containsSettings; // For optimization of high-use calls. +}; + +// MARK: - +// MARK: Corporate Root functions + +// MARK: - +// MARK: Trust store functions + +static int sec_create_path(const char *path) +{ + char pathbuf[PATH_MAX]; + size_t pos, len = strlen(path); + if (len == 0 || len > PATH_MAX) + return SQLITE_CANTOPEN; + memcpy(pathbuf, path, len); + for (pos = len-1; pos > 0; --pos) + { + /* Search backwards for trailing '/'. */ + if (pathbuf[pos] == '/') + { + pathbuf[pos] = '\0'; + /* Attempt to create parent directories of the database. */ + if (!mkdir(pathbuf, 0777)) + break; + else + { + int err = errno; + if (err == EEXIST) + return 0; + if (err == ENOTDIR) + return SQLITE_CANTOPEN; + if (err == EROFS) + return SQLITE_READONLY; + if (err == EACCES) + return SQLITE_PERM; + if (err == ENOSPC || err == EDQUOT) + return SQLITE_FULL; + if (err == EIO) + return SQLITE_IOERR; + + /* EFAULT || ELOOP | ENAMETOOLONG || something else */ + return SQLITE_INTERNAL; + } + } + } + return SQLITE_OK; +} + +static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h, + bool create_path) +{ + int s3e; + s3e = sqlite3_open(db_name, s3h); + if (s3e == SQLITE_CANTOPEN && create_path) { + /* Make sure the path to db_name exists and is writable, then + try again. */ + s3e = sec_create_path(db_name); + if (!s3e) + s3e = sqlite3_open(db_name, s3h); + } + + return s3e; +} + +static int64_t SecTrustStoreCountAll(SecTrustStoreRef ts) { + __block int64_t result = -1; + require_quiet(ts, errOutNotLocked); + dispatch_sync(ts->queue, ^{ + sqlite3_stmt *countAllStmt = NULL; + int s3e = sqlite3_prepare_v2(ts->s3h, countAllSQL, sizeof(countAllSQL), + &countAllStmt, NULL); + if (s3e == SQLITE_OK) { + s3e = sqlite3_step(countAllStmt); + if (s3e == SQLITE_ROW) { + result = sqlite3_column_int64(countAllStmt, 0); + } + } + + if (countAllStmt) { + verify_noerr(sqlite3_finalize(countAllStmt)); + } + }); + +errOutNotLocked: + return result; +} + +static SecTrustStoreRef SecTrustStoreCreate(const char *db_name, + bool create) { + SecTrustStoreRef ts; + int s3e = SQLITE_OK; + + require(ts = (SecTrustStoreRef)malloc(sizeof(struct __SecTrustStore)), errOut); + ts->queue = dispatch_queue_create("truststore", DISPATCH_QUEUE_SERIAL); + require_noerr(s3e = sec_sqlite3_open(db_name, &ts->s3h, create), errOut); + + s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), + SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL); + if (create && s3e == SQLITE_ERROR) { + /* sqlite3_prepare returns SQLITE_ERROR if the table we are + compiling this statement for doesn't exist. */ + char *errmsg = NULL; + s3e = sqlite3_exec(ts->s3h, + "CREATE TABLE tsettings(" + "sha1 BLOB NOT NULL DEFAULT ''," + "subj BLOB NOT NULL DEFAULT ''," + "tset BLOB," + "data BLOB," + "PRIMARY KEY(sha1)" + ");" + "CREATE INDEX isubj ON tsettings(subj);" + , NULL, NULL, &errmsg); + if (errmsg) { + secwarning("CREATE TABLE cert: %s", errmsg); + sqlite3_free(errmsg); + } + require_noerr(s3e, errOut); + s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), + SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL); + } + require_noerr(s3e, errOut); + require_noerr(s3e = sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT, + &ts->contains, NULL), errOut); + + if (SecTrustStoreCountAll(ts) == 0) { + ts->containsSettings = false; + } else { + /* In the error case where SecTrustStoreCountAll returns a negative result, + * we'll pretend there are contents in the trust store so that we still do + * DB operations */ + ts->containsSettings = true; + } + + + return ts; + +errOut: + if (ts) { + sqlite3_close(ts->s3h); + dispatch_release_safe(ts->queue); + free(ts); + } + secerror("Failed to create trust store database: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationCreate, TAFatalError, s3e); + + return NULL; +} + +static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file, UInt8 *buffer, CFIndex maxBufLen) +{ + bool translated = false; + CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(file); + + if (fileURL && CFURLGetFileSystemRepresentation(fileURL, false, buffer, maxBufLen)) + translated = true; + CFReleaseSafe(fileURL); + + return translated; +} + +static void SecTrustStoreInitUser(void) { + const char path[MAXPATHLEN]; + + if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName, (UInt8*) path, (CFIndex) sizeof(path))) + { + kSecTrustStoreUser = SecTrustStoreCreate(path, true); + if (kSecTrustStoreUser) + kSecTrustStoreUser->readOnly = false; + } +} + +/* AUDIT[securityd](done): + domainName (ok) is a caller provided string of any length (might be 0), only + its cf type has been checked. + */ +SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) { + if (CFEqual(CFSTR("user"), domainName)) { + dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); }); + return kSecTrustStoreUser; + } else { + SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName); + return NULL; + } +} + +/* AUDIT[securityd](done): + ts (ok) might be NULL. + certificate (ok) is a valid SecCertificateRef. + trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either + NULL, a dictionary or an array, but its contents have not been checked. + */ +bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, + SecCertificateRef certificate, + CFTypeRef tsdoa, CFErrorRef *error) { + __block bool ok; + require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("truststore is NULL"))); + require_action_quiet(!ts->readOnly, errOutNotLocked, ok = SecError(errSecReadOnly, error, CFSTR("truststore is readOnly"))); + dispatch_sync(ts->queue, ^{ + CFTypeRef trustSettingsDictOrArray = tsdoa; + sqlite3_stmt *insert = NULL; + CFDataRef xmlData = NULL; + CFArrayRef array = NULL; + + CFDataRef subject; + require_action_quiet(subject = SecCertificateGetNormalizedSubjectContent(certificate), + errOut, ok = SecError(errSecParam, error, CFSTR("get normalized subject failed"))); + CFDataRef digest; + require_action_quiet(digest = SecCertificateGetSHA1Digest(certificate), errOut, ok = SecError(errSecParam, error, CFSTR("get sha1 digest failed"))); + + /* Do some basic checks on the trust settings passed in. */ + if (trustSettingsDictOrArray == NULL) { + require_action_quiet(array = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), errOut, ok = SecError(errSecAllocate, error, CFSTR("CFArrayCreate failed"))); + trustSettingsDictOrArray = array; + } + else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) { + /* array-ize it */ + array = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1, + &kCFTypeArrayCallBacks); + trustSettingsDictOrArray = array; + } + else { + require_action_quiet(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID(), errOut, ok = SecError(errSecParam, error, CFSTR("trustSettingsDictOrArray neither dict nor array"))); + } + + require_action_quiet(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault, + trustSettingsDictOrArray), errOut, ok = SecError(errSecParam, error, CFSTR("xml encode failed"))); + + int s3e = sqlite3_exec(ts->s3h, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL); + require_action_quiet(s3e == SQLITE_OK, errOut, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + + /* Parameter order is sha1,subj,tset,data. */ + require_noerr_action_quiet(s3e = sqlite3_prepare_v2(ts->s3h, insertSQL, sizeof(insertSQL), + &insert, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 1, + CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), + errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 2, + CFDataGetBytePtr(subject), CFDataGetLength(subject), + SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 3, + CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), + SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 4, + SecCertificateGetBytePtr(certificate), + SecCertificateGetLength(certificate), SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + s3e = sqlite3_step(insert); + if (s3e == SQLITE_DONE) { + /* Great the insert worked. */ + ok = true; + ts->containsSettings = true; + } else { + require_noerr_action_quiet(s3e, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e)); + ok = true; + } + + errOutSql: + if (insert) { + s3e = sqlite3_finalize(insert); + } + + if (ok && s3e == SQLITE_OK) { + s3e = sqlite3_exec(ts->s3h, "COMMIT TRANSACTION", NULL, NULL, NULL); + } + + if (!ok || s3e != SQLITE_OK) { + secerror("Failed to update trust store: (%d) %@", s3e, error ? *error : NULL); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); + sqlite3_exec(ts->s3h, "ROLLBACK TRANSACTION", NULL, NULL, NULL); + if (ok) { + ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e); + } + } + + errOut: + CFReleaseSafe(xmlData); + CFReleaseSafe(array); + }); +errOutNotLocked: + return ok; +} + +/* AUDIT[securityd](done): + ts (ok) might be NULL. + digest (ok) is a data of any length (might be 0). + */ +bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts, + CFDataRef digest, CFErrorRef *error) { + require_quiet(ts, errOutNotLocked); + require(!ts->readOnly, errOutNotLocked); + dispatch_sync(ts->queue, ^{ + int s3e = SQLITE_OK; + sqlite3_stmt *deleteStmt = NULL; + + require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, deleteSQL, sizeof(deleteSQL), + &deleteStmt, NULL), errOut); + require_noerr(s3e = sqlite3_bind_blob_wrapper(deleteStmt, 1, + CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), + errOut); + s3e = sqlite3_step(deleteStmt); + + errOut: + if (deleteStmt) { + verify_noerr(sqlite3_finalize(deleteStmt)); + } + if (s3e != SQLITE_OK && s3e != SQLITE_DONE) { + secerror("Removal of certificate from trust store failed: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); + } + }); +errOutNotLocked: + return true; +} + +bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error) +{ + __block bool removed_all = false; + require(ts, errOutNotLocked); + require(!ts->readOnly, errOutNotLocked); + dispatch_sync(ts->queue, ^{ + int s3e =sqlite3_exec(ts->s3h, deleteAllSQL, NULL, NULL, NULL); + if (s3e == SQLITE_OK) { + removed_all = true; + ts->containsSettings = false; + } else { + secerror("Clearing of trust store failed: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e); + } + + /* prepared statements become unusable after deleteAllSQL, reset them */ + if (ts->copyParents) + sqlite3_finalize(ts->copyParents); + sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), SQLITE_PREPARE_PERSISTENT, + &ts->copyParents, NULL); + if (ts->contains) + sqlite3_finalize(ts->contains); + sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT, + &ts->contains, NULL); + }); +errOutNotLocked: + return removed_all; +} + +CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts, + SecCertificateRef certificate, CFErrorRef *error) { + __block CFMutableArrayRef parents = NULL; + require(ts, errOutNotLocked); + dispatch_sync(ts->queue, ^{ + int s3e = SQLITE_OK; + CFDataRef issuer = NULL; + require(issuer = SecCertificateGetNormalizedIssuerContent(certificate), + errOut); + require_quiet(ts->containsSettings, ok); + /* @@@ Might have to use SQLITE_TRANSIENT */ + require_noerr(s3e = sqlite3_bind_blob_wrapper(ts->copyParents, 1, + CFDataGetBytePtr(issuer), CFDataGetLength(issuer), + SQLITE_STATIC), errOut); + + require(parents = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks), errOut); + for (;;) { + s3e = sqlite3_step(ts->copyParents); + if (s3e == SQLITE_ROW) { + SecCertificateRef cert; + require(cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, + sqlite3_column_blob(ts->copyParents, 0), + sqlite3_column_bytes(ts->copyParents, 0)), errOut); + CFArrayAppendValue(parents, cert); + CFRelease(cert); + } else { + require(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut); + break; + } + } + + goto ok; + errOut: + secerror("Failed to read parents from trust store: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); + if (parents) { + CFRelease(parents); + parents = NULL; + } + ok: + verify_noerr(sqlite3_reset(ts->copyParents)); + verify_noerr(sqlite3_clear_bindings(ts->copyParents)); + }); +errOutNotLocked: + return parents; +} + +static bool SecTrustStoreQueryCertificateWithDigest(SecTrustStoreRef ts, + CFDataRef digest, bool *contains, CFArrayRef *usageConstraints, CFErrorRef *error) { + if (contains) + *contains = false; + __block bool ok = true; + require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL"))); + dispatch_sync(ts->queue, ^{ + CFDataRef xmlData = NULL; + CFPropertyListRef trustSettings = NULL; + int s3e = SQLITE_OK; + require_action_quiet(ts->containsSettings, errOut, ok = true); + require_noerr_action(s3e = sqlite3_bind_blob_wrapper(ts->contains, 1, + CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC), + errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_bind_blob failed"))); + s3e = sqlite3_step(ts->contains); + if (s3e == SQLITE_ROW) { + if (contains) + *contains = true; + if (usageConstraints) { + require_action(xmlData = CFDataCreate(NULL, + sqlite3_column_blob(ts->contains, 0), + sqlite3_column_bytes(ts->contains, 0)), errOut, ok = false); + require_action(trustSettings = CFPropertyListCreateWithData(NULL, + xmlData, + kCFPropertyListImmutable, + NULL, error), errOut, ok = false); + require_action(CFGetTypeID(trustSettings) == CFArrayGetTypeID(), errOut, ok = false); + *usageConstraints = CFRetain(trustSettings); + } + } else { + require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut, + ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_step failed"))); + } + + errOut: + if (!ok) { + secerror("Failed to query for cert in trust store: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); + } + verify_noerr(sqlite3_reset(ts->contains)); + verify_noerr(sqlite3_clear_bindings(ts->contains)); + CFReleaseNull(xmlData); + CFReleaseNull(trustSettings); + }); +errOutNotLocked: + return ok; +} + +bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts, + CFDataRef digest, bool *contains, CFErrorRef *error) { + return SecTrustStoreQueryCertificateWithDigest(ts, digest, contains, NULL, error); +} + +bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, + CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error) { + return SecTrustStoreQueryCertificateWithDigest(ts, digest, NULL, usageConstraints, error); +} + +bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error) { + __block bool ok = true; + __block CFMutableArrayRef CertsAndSettings = NULL; + require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL"))); + require_action_quiet(trustStoreContents, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("trustStoreContents is NULL"))); + dispatch_sync(ts->queue, ^{ + sqlite3_stmt *copyAllStmt = NULL; + CFDataRef cert = NULL; + CFDataRef xmlData = NULL; + CFPropertyListRef trustSettings = NULL; + CFArrayRef certSettingsPair = NULL; + int s3e = SQLITE_OK; + require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, copyAllSQL, sizeof(copyAllSQL), + ©AllStmt, NULL), errOut); + require(CertsAndSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut); + for(;;) { + s3e = sqlite3_step(copyAllStmt); + if (s3e == SQLITE_ROW) { + require(cert = CFDataCreate(kCFAllocatorDefault, + sqlite3_column_blob(copyAllStmt, 0), + sqlite3_column_bytes(copyAllStmt, 0)), errOut); + require(xmlData = CFDataCreate(NULL, + sqlite3_column_blob(copyAllStmt, 1), + sqlite3_column_bytes(copyAllStmt, 1)), errOut); + require(trustSettings = CFPropertyListCreateWithData(NULL, + xmlData, + kCFPropertyListImmutable, + NULL, error), errOut); + const void *pair[] = { cert , trustSettings }; + require(certSettingsPair = CFArrayCreate(NULL, pair, 2, &kCFTypeArrayCallBacks), errOut); + CFArrayAppendValue(CertsAndSettings, certSettingsPair); + + CFReleaseNull(cert); + CFReleaseNull(xmlData); + CFReleaseNull(trustSettings); + CFReleaseNull(certSettingsPair); + } else { + require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut, ok = SecDbErrorWithStmt(s3e, copyAllStmt, error, CFSTR("sqlite3_step failed"))); + break; + } + } + goto ok; + + errOut: + secerror("Failed to query for all certs in trust store: %d", s3e); + TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e); + CFReleaseNull(cert); + CFReleaseNull(xmlData); + CFReleaseNull(trustSettings); + CFReleaseNull(certSettingsPair); + ok: + if (copyAllStmt) { + verify_noerr(sqlite3_finalize(copyAllStmt)); + } + if (CertsAndSettings) { + *trustStoreContents = CertsAndSettings; + } + }); +errOutNotLocked: + return ok; +} diff --git a/trust/trustd/SecTrustStoreServer.h b/trust/trustd/SecTrustStoreServer.h new file mode 100644 index 00000000..41444de1 --- /dev/null +++ b/trust/trustd/SecTrustStoreServer.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecTrustStoreServer + CertificateSource API to a system root certificate store +*/ + +#ifndef _SECURITY_SECTRUSTSTORESERVER_H_ +#define _SECURITY_SECTRUSTSTORESERVER_H_ + +#include "Security/SecTrustStore.h" +#include +#include + +__BEGIN_DECLS + +SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error); + +bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, + SecCertificateRef certificate, + CFTypeRef trustSettingsDictOrArray, CFErrorRef *error); + +bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts, CFDataRef digest, CFErrorRef *error); + +bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error); + +CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts, + SecCertificateRef certificate, CFErrorRef *error); + +bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef source, CFDataRef digest, bool *contains, CFErrorRef *error); + +bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error); + +bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error); + +bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error); +CF_RETURNS_RETAINED CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error); + +__END_DECLS + +#endif /* !_SECURITY_SECTRUSTSTORESERVER_H_ */ diff --git a/trust/trustd/SecTrustStoreServer.m b/trust/trustd/SecTrustStoreServer.m new file mode 100644 index 00000000..acb0fb48 --- /dev/null +++ b/trust/trustd/SecTrustStoreServer.m @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#import +#include +#include +#include +#include +#include +#include +#include +#import "OTATrustUtilities.h" +#include "SecTrustStoreServer.h" + +typedef bool(*exceptionsArrayValueChecker)(id _Nonnull obj); + +static bool checkDomainsValuesCompliance(id _Nonnull obj) { + if (![obj isKindOfClass:[NSString class]]) { + return false; + } + if (SecDNSIsTLD((__bridge CFStringRef)obj)) { + return false; + } + return true; +} + +static bool checkCAsValuesCompliance(id _Nonnull obj) { + if (![obj isKindOfClass:[NSDictionary class]]) { + return false; + } + if (2 != [(NSDictionary*)obj count]) { + return false; + } + if (nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] || + nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]) { + return false; + } + if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isKindOfClass:[NSString class]] || + ![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey] isKindOfClass:[NSData class]]) { + return false; + } + if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isEqualToString:@"sha256"]) { + return false; + } + return true; +} + +static bool checkExceptionsValues(NSString *key, id value, exceptionsArrayValueChecker checker, CFErrorRef *error) { + if (![value isKindOfClass:[NSArray class]]) { + return SecError(errSecParam, error, CFSTR("value for %@ is not an array in exceptions dictionary"), key); + } + + __block bool result = true; + [(NSArray*)value enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (!checker(obj)) { + result = SecError(errSecParam, error, CFSTR("value %lu for %@ is not the expected type"), (unsigned long)idx, key); + *stop = true; + } + }]; + return result; +} + +static bool checkInputExceptionsAndSetAppExceptions(NSDictionary *inExceptions, NSMutableDictionary *appExceptions, CFErrorRef *error) { + __block bool result = true; + [inExceptions enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsDomainsKey]) { + if (!checkExceptionsValues(key, obj, checkDomainsValuesCompliance, error)) { + *stop = YES; + result = false; + return; + } + } else if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsCAsKey]) { + if (!checkExceptionsValues(key, obj, checkCAsValuesCompliance, error)) { + *stop = YES; + result = false; + return; + } + } else { + result = SecError(errSecParam, error, CFSTR("unknown key (%@) in exceptions dictionary"), key); + *stop = YES; + result = false; + return; + } + if ([(NSArray*)obj count] == 0) { + [appExceptions removeObjectForKey:key]; + } else { + appExceptions[key] = obj; + } + }]; + return result; +} + +static _Atomic bool gHasCTExceptions = false; +#define kSecCTExceptionsChanged "com.apple.trustd.ct.exceptions-changed" + +static NSURL *CTExceptionsFileURL() { + return CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(CFSTR("CTExceptions.plist"))); +} + +static NSDictionary *readExceptionsFromDisk(NSError **error) { + secdebug("ct", "reading CT exceptions from disk"); + NSDictionary *allExceptions = [NSDictionary dictionaryWithContentsOfURL:CTExceptionsFileURL() + error:error]; + return allExceptions; +} + +bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error) { + if (!SecOTAPKIIsSystemTrustd()) { + secerror("Unable to write CT exceptions from user agent"); + return SecError(errSecWrPerm, error, CFSTR("Unable to write CT exceptions from user agent")); + } + + if (!appID) { + secerror("application-identifier required to set exceptions"); + return SecError(errSecParam, error, CFSTR("application-identifier required to set exceptions")); + } + + @autoreleasepool { + NSError *nserror = nil; + NSMutableDictionary *allExceptions = [readExceptionsFromDisk(&nserror) mutableCopy]; + NSMutableDictionary *appExceptions = NULL; + if (allExceptions && allExceptions[(__bridge NSString*)appID]) { + appExceptions = [allExceptions[(__bridge NSString*)appID] mutableCopy]; + } else { + appExceptions = [NSMutableDictionary dictionary]; + if (!allExceptions) { + allExceptions = [NSMutableDictionary dictionary]; + } + } + + if (exceptions && (CFDictionaryGetCount(exceptions) > 0)) { + NSDictionary *inExceptions = (__bridge NSDictionary*)exceptions; + if (!checkInputExceptionsAndSetAppExceptions(inExceptions, appExceptions, error)) { + secerror("input exceptions have error: %@", error ? *error : nil); + return false; + } + } + + if (!exceptions || [appExceptions count] == 0) { + [allExceptions removeObjectForKey:(__bridge NSString*)appID]; + } else { + allExceptions[(__bridge NSString*)appID] = appExceptions; + } + + if (![allExceptions writeToURL:CTExceptionsFileURL() error:&nserror]) { + secerror("failed to write CT exceptions: %@", nserror); + if (error) { + *error = CFRetainSafe((__bridge CFErrorRef)nserror); + } + return false; + } + secnotice("ct", "wrote %lu CT exceptions", (unsigned long)[allExceptions count]); + atomic_store(&gHasCTExceptions, [allExceptions count] != 0); + notify_post(kSecCTExceptionsChanged); + return true; + } +} + +CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error) { + @autoreleasepool { + /* Set us up for not reading the disk when there are never exceptions */ + static int notify_token = 0; + int check = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + /* initialize gHashCTExceptions cache */ + NSError *read_error = nil; + NSDictionary *allExceptions = readExceptionsFromDisk(&read_error); + if (!allExceptions || [allExceptions count] == 0) { + secnotice("ct", "skipping further reads. no CT exceptions found: %@", read_error); + atomic_store(&gHasCTExceptions, false); + } else { + secnotice("ct", "have CT exceptions. will need to read."); + atomic_store(&gHasCTExceptions, true); + } + + /* read-only trustds register for notfications from the read-write trustd */ + if (!SecOTAPKIIsSystemTrustd()) { + uint32_t status = notify_register_check(kSecCTExceptionsChanged, ¬ify_token); + if (status == NOTIFY_STATUS_OK) { + status = notify_check(notify_token, NULL); + } + if (status != NOTIFY_STATUS_OK) { + secerror("failed to establish notification for CT exceptions: %ud", status); + notify_cancel(notify_token); + notify_token = 0; + } + } + }); + + /* Read the negative cached value as to whether there are any exceptions to read */ + if (!SecOTAPKIIsSystemTrustd()) { + /* Check whether we got a notification. If we didn't, and there are no exceptions set, return NULL. + * Otherwise, we need to read from disk */ + uint32_t check_status = notify_check(notify_token, &check); + if (check_status == NOTIFY_STATUS_OK && check == 0 && !atomic_load(&gHasCTExceptions)) { + return NULL; + } + } else if (!atomic_load(&gHasCTExceptions)) { + return NULL; + } + + /* We need to read the exceptions from disk */ + NSError *read_error = nil; + NSDictionary *allExceptions = readExceptionsFromDisk(&read_error); + if (!allExceptions || [allExceptions count] == 0) { + secnotice("ct", "skipping further reads. no CT exceptions found: %@", read_error); + atomic_store(&gHasCTExceptions, false); + return NULL; + } + + /* If the caller specified an appID, return only the exceptions for that appID */ + if (appID) { + return CFBridgingRetain(allExceptions[(__bridge NSString*)appID]); + } + + /* Otherwise, combine all the exceptions into one array */ + NSMutableArray *domainExceptions = [NSMutableArray array]; + NSMutableArray *caExceptions = [NSMutableArray array]; + [allExceptions enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull __unused key, NSDictionary * _Nonnull appExceptions, + BOOL * _Nonnull __unused stop) { + if (appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] && + checkExceptionsValues((__bridge NSString*)kSecCTExceptionsDomainsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey], + checkDomainsValuesCompliance, error)) { + [domainExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey]]; + } + if (appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] && + checkExceptionsValues((__bridge NSString*)kSecCTExceptionsCAsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey], + checkCAsValuesCompliance, error)) { + [caExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey]]; + } + }]; + NSMutableDictionary *exceptions = [NSMutableDictionary dictionaryWithCapacity:2]; + if ([domainExceptions count] > 0) { + exceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] = domainExceptions; + } + if ([caExceptions count] > 0) { + exceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] = caExceptions; + } + if ([exceptions count] > 0) { + secdebug("ct", "found %lu CT exceptions on disk", (unsigned long)[exceptions count]); + atomic_store(&gHasCTExceptions, true); + return CFBridgingRetain(exceptions); + } + return NULL; + } +} diff --git a/trust/trustd/TrustURLSessionDelegate.h b/trust/trustd/TrustURLSessionDelegate.h new file mode 100644 index 00000000..ff9d4a02 --- /dev/null +++ b/trust/trustd/TrustURLSessionDelegate.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +#ifndef _SECURITY_TRUSTURLSESSIONDELEGATE_H_ +#define _SECURITY_TRUSTURLSESSIONDELEGATE_H_ + +#if __OBJC__ +#include + +NS_ASSUME_NONNULL_BEGIN +/* This is our abstract NSURLSessionDelegate that handles the elements common to + * fetching data over the network during a trust evaluation */ +@interface TrustURLSessionDelegate : NSObject +@property (assign, nullable) void *context; +@property NSArray *URIs; +@property NSUInteger URIix; +@property (nullable) NSMutableData *response; +@property NSTimeInterval expiration; +@property NSUInteger numTasks; + +- (BOOL)fetchNext:(NSURLSession *)session; +- (NSURLRequest *)createNextRequest:(NSURL *)uri; +@end + +NSTimeInterval TrustURLSessionGetResourceTimeout(void); + +NS_ASSUME_NONNULL_END +#endif // __OBJC__ + +#endif /* _SECURITY_TRUSTURLSESSIONDELEGATE_H_ */ diff --git a/trust/trustd/TrustURLSessionDelegate.m b/trust/trustd/TrustURLSessionDelegate.m new file mode 100644 index 00000000..6698130a --- /dev/null +++ b/trust/trustd/TrustURLSessionDelegate.m @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + */ + +#import +#import +#include +#include +#include +#include "TrustURLSessionDelegate.h" + +#define MAX_TASKS 3 + +/* There has got to be an easier way to do this. For now we based this code + on CFNetwork/Connection/URLResponse.cpp. */ +static CFStringRef copyParseMaxAge(CFStringRef cacheControlHeader) { + if (!cacheControlHeader) { return NULL; } + + /* The format of the cache control header is a comma-separated list, but + each list element could be a key-value pair, with the value quoted and + possibly containing a comma. */ + CFStringInlineBuffer inlineBuf = {}; + CFRange componentRange; + CFIndex length = CFStringGetLength(cacheControlHeader); + bool done = false; + CFCharacterSetRef whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace); + CFStringRef maxAgeValue = NULL; + + CFStringInitInlineBuffer(cacheControlHeader, &inlineBuf, CFRangeMake(0, length)); + componentRange.location = 0; + + while (!done) { + bool inQuotes = false; + bool foundComponentStart = false; + CFIndex charIndex = componentRange.location; + CFIndex componentEnd = -1; + CFRange maxAgeRg; + componentRange.length = 0; + + while (charIndex < length) { + UniChar ch = CFStringGetCharacterFromInlineBuffer(&inlineBuf, charIndex); + if (!inQuotes && ch == ',') { + componentRange.length = charIndex - componentRange.location; + break; + } + if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { + if (!foundComponentStart) { + foundComponentStart = true; + componentRange.location = charIndex; + } else { + componentEnd = charIndex; + } + if (ch == '\"') { + inQuotes = (inQuotes == false); + } + } + charIndex ++; + } + + if (componentEnd == -1) { + componentRange.length = charIndex - componentRange.location; + } else { + componentRange.length = componentEnd - componentRange.location + 1; + } + + if (charIndex == length) { + /* Fell off the end; this is the last component. */ + done = true; + } + + /* componentRange should now contain the range of the current + component; trimmed of any whitespace. */ + + /* We want to look for a max-age value. */ + if (!maxAgeValue && CFStringFindWithOptions(cacheControlHeader, CFSTR("max-age"), componentRange, kCFCompareCaseInsensitive | kCFCompareAnchored, &maxAgeRg)) { + CFIndex equalIdx; + CFIndex maxCompRg = componentRange.location + componentRange.length; + for (equalIdx = maxAgeRg.location + maxAgeRg.length; equalIdx < maxCompRg; equalIdx ++) { + UniChar equalCh = CFStringGetCharacterFromInlineBuffer(&inlineBuf, equalIdx); + if (equalCh == '=') { + // Parse out max-age value + equalIdx ++; + while (equalIdx < maxCompRg && CFCharacterSetIsCharacterMember(whitespaceSet, CFStringGetCharacterAtIndex(cacheControlHeader, equalIdx))) { + equalIdx ++; + } + if (equalIdx < maxCompRg) { + CFReleaseNull(maxAgeValue); + maxAgeValue = CFStringCreateWithSubstring(kCFAllocatorDefault, cacheControlHeader, CFRangeMake(equalIdx, maxCompRg-equalIdx)); + } + } else if (!CFCharacterSetIsCharacterMember(whitespaceSet, equalCh)) { + // Not a valid max-age header; break out doing nothing + break; + } + } + } + + if (!done && maxAgeValue) { + done = true; + } + if (!done) { + /* Advance to the next component; + 1 to get past the comma. */ + componentRange.location = charIndex + 1; + } + } + + return maxAgeValue; +} + +@implementation TrustURLSessionDelegate +- (id)init { + /* Protect future developers from themselves */ + if ([self class] == [TrustURLSessionDelegate class]) { + NSException *e = [NSException exceptionWithName:@"AbstractClassException" + reason:@"This is an abstract class. To use it, please subclass." + userInfo:nil]; + @throw e; + } else { + return [super init]; + } +} + +- (NSURLRequest *)createNextRequest:(NSURL *)uri { + return [NSURLRequest requestWithURL:uri]; +} + +- (BOOL)fetchNext:(NSURLSession *)session { + if (self.numTasks >= MAX_TASKS) { + secnotice("http", "Too many fetch %@ requests for this cert", [self class]); + return true; + } + + for (NSUInteger ix = self.URIix; ix < [self.URIs count]; ix++) { + NSURL *uri = self.URIs[ix]; + if ([[uri scheme] isEqualToString:@"http"]) { + self.URIix = ix + 1; // Next time we'll start with the next index + self.numTasks++; + NSURLSessionTask *task = [session dataTaskWithRequest:[self createNextRequest:uri]]; + [task resume]; + secinfo("http", "request for uri: %@", uri); + return false; // we scheduled a job + } else { + secnotice("http", "skipping unsupported scheme %@", [uri scheme]); + } + } + + /* No more issuers left to try, we're done. Report that no async jobs were started. */ + secdebug("http", "no request issued"); + return true; +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + /* Append the data to the response data*/ + if (!_response) { + _response = [NSMutableData data]; + } + [_response appendData:data]; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + /* Protect future developers from themselves */ + if ([self class] == [TrustURLSessionDelegate class]) { + NSException *e = [NSException exceptionWithName:@"AbstractClassException" + reason:@"This is an abstract class. To use it, please subclass and override didCompleteWithError." + userInfo:nil]; + @throw e; + } else { + _expiration = 60.0 * 60.0 * 24.0 * 7; /* Default is 7 days */ + if ([_response length] > 0 && [[task response] isKindOfClass:[NSHTTPURLResponse class]]) { + NSString *cacheControl = [[(NSHTTPURLResponse *)[task response] allHeaderFields] objectForKey:@"cache-control"]; + NSString *maxAge = CFBridgingRelease(copyParseMaxAge((__bridge CFStringRef)cacheControl)); + if (maxAge && [maxAge doubleValue] > _expiration) { + _expiration = [maxAge doubleValue]; + } + } + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + /* The old code didn't allow re-direction, so we won't either. */ + secnotice("http", "failed redirection for %@", task.originalRequest.URL); + [task cancel]; +} +@end + +NSTimeInterval TrustURLSessionGetResourceTimeout(void) { + return (NSTimeInterval)3.0; +} diff --git a/trust/trustd/com.apple.trustd.asl b/trust/trustd/com.apple.trustd.asl new file mode 100644 index 00000000..f1a68ebe --- /dev/null +++ b/trust/trustd/com.apple.trustd.asl @@ -0,0 +1,4 @@ +? [= Sender authd] claim only +* file /var/log/authd.log mode=0640 compress format=bsd rotate=seq file_max=5M all_max=20M +? [<= Level error] file /var/log/system.log +? [<= Level error] store diff --git a/trust/trustd/iOS/AppleCorporateRootCA.cer b/trust/trustd/iOS/AppleCorporateRootCA.cer new file mode 100644 index 00000000..c23d1c46 Binary files /dev/null and b/trust/trustd/iOS/AppleCorporateRootCA.cer differ diff --git a/trust/trustd/iOS/AppleCorporateRootCA2.cer b/trust/trustd/iOS/AppleCorporateRootCA2.cer new file mode 100644 index 00000000..e16cc0fb Binary files /dev/null and b/trust/trustd/iOS/AppleCorporateRootCA2.cer differ diff --git a/trust/trustd/iOS/com.apple.trustd.plist b/trust/trustd/iOS/com.apple.trustd.plist new file mode 100644 index 00000000..fa838619 --- /dev/null +++ b/trust/trustd/iOS/com.apple.trustd.plist @@ -0,0 +1,38 @@ + + + + + EnablePressuredExit + + EnableTransactions + + EnvironmentVariables + + DEBUGSCOPE + -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well, ringSigning + WAIT4DEBUGGER + NO + + GroupName + _securityd + Label + com.apple.trustd + MachServices + + com.apple.trustd + + + ProgramArguments + + /usr/libexec/trustd + + Umask + 54 + UserName + _securityd + POSIXSpawnType + Adaptive + MinimalBootProfile + + + diff --git a/trust/trustd/iOS/entitlements.plist b/trust/trustd/iOS/entitlements.plist new file mode 100644 index 00000000..dc6f6d2e --- /dev/null +++ b/trust/trustd/iOS/entitlements.plist @@ -0,0 +1,27 @@ + + + + + application-identifier + com.apple.trustd + com.apple.application-identifier + com.apple.trustd + com.apple.private.necp.match + + com.apple.private.network.socket-delegate + + com.apple.private.network.delegation-whitelist + + com.apple.private.keychain.certificates + + com.apple.private.assets.accessible-asset-types + + com.apple.MobileAsset.PKITrustSupplementals + com.apple.MobileAsset.SecExperimentAssets + + seatbelt-profiles + + trustd + + + diff --git a/trust/trustd/macOS/SecTrustOSXEntryPoints.h b/trust/trustd/macOS/SecTrustOSXEntryPoints.h new file mode 100644 index 00000000..142b62e5 --- /dev/null +++ b/trust/trustd/macOS/SecTrustOSXEntryPoints.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecTrustOSXEntryPoints - Interface for unified SecTrust into OS X Security + * Framework. + */ + +#ifndef _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ +#define _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ + +#include +#include + +__BEGIN_DECLS + +void SecTrustLegacySourcesListenForKeychainEvents(void); + +__END_DECLS + +#endif /* _SECURITY_SECTRUST_OSX_ENTRY_POINTS_H_ */ diff --git a/trust/trustd/macOS/com.apple.trustd.agent.plist b/trust/trustd/macOS/com.apple.trustd.agent.plist new file mode 100644 index 00000000..8b315af2 --- /dev/null +++ b/trust/trustd/macOS/com.apple.trustd.agent.plist @@ -0,0 +1,39 @@ + + + + + EnablePressuredExit + + EnableTransactions + + EnvironmentVariables + + DEBUGSCOPE + -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well + WAIT4DEBUGGER + NO + + Label + com.apple.trustd.agent + LimitLoadToSessionType + + Aqua + Background + LoginWindow + + MachServices + + com.apple.trustd.agent + + + POSIXSpawnType + Adaptive + ProgramArguments + + /usr/libexec/trustd + --agent + + Umask + 54 + + diff --git a/trust/trustd/macOS/com.apple.trustd.plist b/trust/trustd/macOS/com.apple.trustd.plist new file mode 100644 index 00000000..fac729cb --- /dev/null +++ b/trust/trustd/macOS/com.apple.trustd.plist @@ -0,0 +1,30 @@ + + + + + EnablePressuredExit + + EnableTransactions + + EnvironmentVariables + + DEBUGSCOPE + -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well + WAIT4DEBUGGER + NO + + Label + com.apple.trustd + MachServices + + com.apple.trustd + + + POSIXSpawnType + Adaptive + ProgramArguments + + /usr/libexec/trustd + + + diff --git a/trust/trustd/macOS/com.apple.trustd.sb b/trust/trustd/macOS/com.apple.trustd.sb new file mode 100644 index 00000000..f13684b1 --- /dev/null +++ b/trust/trustd/macOS/com.apple.trustd.sb @@ -0,0 +1,72 @@ +(version 1) + +(deny default) +(deny file-map-executable iokit-get-properties process-info* nvram*) +(deny dynamic-code-generation) + +(import "system.sb") +(import "com.apple.corefoundation.sb") +(corefoundation) + +(allow process-info* (target self)) + +;; For resolving symlinks, realpath(3), and equivalents. +(allow file-read-metadata) + +;; For validating the entitlements of clients (for keychain and trust settings) +;; see 31353815 +(allow process-info-codesignature) +(allow process-info-pidinfo) +(allow file-read*) + +;; ${PRODUCT_NAME}’s preference domain. +(allow user-preference-read user-preference-write + (preference-domain "com.apple.trustd")) + +;; Global and security preferences +(allow user-preference-read + (preference-domain "com.apple.security") + (preference-domain ".GlobalPreferences") + (preference-domain "com.apple.MobileAsset")) + +;; Read/write access to a temporary directory. +(allow file-read* file-write* + (subpath (param "_TMPDIR")) + (subpath (param "_DARWIN_CACHE_DIR"))) + +;; Read/write access to keychains and caches +(allow file-read* file-write* + (subpath "/private/var/db/mds/") + (subpath "/private/var/db/crls/") + (subpath "/System/Library/Security/") + (subpath "/Library/Keychains/") + (subpath "/private/var/root/Library/Caches/com.apple.nsurlsessiond/")) + +(allow file-read* + (literal "/usr/libexec") + (literal "/usr/libexec/trustd") + (literal "/Library/Preferences/com.apple.security.plist") + (regex #"/.GlobalPreferences[^/]*\.plist") + (literal "/Library/Preferences/com.apple.SoftwareUpdate.plist") + (literal "/Library/Application Support/CrashReporter/SubmitDiagInfo.domains")) + +(allow file-map-executable + (regex #"/CoreServicesInternal") + (regex #"/csparser")) + +(allow mach-lookup + (global-name "com.apple.ocspd") + (global-name "com.apple.SecurityServer") + (global-name "com.apple.SystemConfiguration.configd") + (global-name "com.apple.mobileassetd.v2") + (global-name "com.apple.securityd.xpc") + (global-name "com.apple.cfnetwork.cfnetworkagent") + (global-name "com.apple.nsurlsessiond") + (xpc-service-name "com.apple.powerlog.plxpclogger.xpc") + (global-name "com.apple.nesessionmanager.content-filter")) + +(allow ipc-posix-shm + (ipc-posix-name "com.apple.AppleDatabaseChanged")) + +(allow network-outbound) +(allow system-socket) diff --git a/trust/trustd/macOS/entitlements.plist b/trust/trustd/macOS/entitlements.plist new file mode 100644 index 00000000..efa5ea47 --- /dev/null +++ b/trust/trustd/macOS/entitlements.plist @@ -0,0 +1,23 @@ + + + + + application-identifier + com.apple.trustd + com.apple.application-identifier + com.apple.trustd + com.apple.private.necp.match + + com.apple.private.network.socket-delegate + + com.apple.private.network.delegation-whitelist + + com.apple.private.keychain.certificates + + com.apple.private.assets.accessible-asset-types + + com.apple.MobileAsset.PKITrustSupplementals + com.apple.MobileAsset.SecExperimentAssets + + + diff --git a/trust/trustd/macOS/trustd.8 b/trust/trustd/macOS/trustd.8 new file mode 100644 index 00000000..21914269 --- /dev/null +++ b/trust/trustd/macOS/trustd.8 @@ -0,0 +1,14 @@ +.Dd Sat Jan 14 2017 \" DATE +.Dt trustd 8 \" Program name and manual section number +.Os +.Sh NAME \" Section Header - required - don't modify +.Nm trustd +.Nd Daemon and LaunchAgent that performs trust evaluations +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Sh DESCRIPTION \" Section Header - required - don't modify +.Nm +provides services for evaluating trust in certificates for all processes on +the system. +.Pp +This command is not intended to be invoked directly. diff --git a/trust/trustd/nameconstraints.c b/trust/trustd/nameconstraints.c new file mode 100644 index 00000000..fb89ff2c --- /dev/null +++ b/trust/trustd/nameconstraints.c @@ -0,0 +1,660 @@ +/* + * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * nameconstraints.c - rfc5280 section 4.2.1.10 and later name constraints implementation. + */ + +#include "nameconstraints.h" +#include +#include +#include +#include "trust/trustd/SecPolicyServer.h" +#include +#include + +/* RFC 5280 Section 4.2.1.10: + DNS name restrictions are expressed as host.example.com. Any DNS + name that can be constructed by simply adding zero or more labels to + the left-hand side of the name satisfies the name constraint. For + example, www.host.example.com would satisfy the constraint but + host1.example.com would not. +*/ +static bool SecDNSNameConstraintsMatch(CFStringRef DNSName, CFStringRef constraint) { + CFIndex clength = CFStringGetLength(constraint); + CFIndex dlength = CFStringGetLength(DNSName); + + if (dlength < clength) return false; + + /* Ensure that character to the left of the constraint in the DNSName is a '.' + so that badexample.com does not match example.com, but good.example.com does. + */ + if ((dlength != clength) && ('.' != CFStringGetCharacterAtIndex(constraint, 0)) && + ('.' != CFStringGetCharacterAtIndex(DNSName, dlength - clength -1))) { + return false; + } + + CFRange compareRange = { dlength - clength, clength}; + + if (!CFStringCompareWithOptions(DNSName, constraint, compareRange, kCFCompareCaseInsensitive)) { + return true; + } + + return false; +} + +/* RFC 5280 Section 4.2.1.10: + For URIs, the constraint applies to the host part of the name. The + constraint MUST be specified as a fully qualified domain name and MAY + specify a host or a domain. Examples would be "host.example.com" and + ".example.com". When the constraint begins with a period, it MAY be + expanded with one or more labels. That is, the constraint + ".example.com" is satisfied by both host.example.com and + my.host.example.com. However, the constraint ".example.com" is not + satisfied by "example.com". When the constraint does not begin with + a period, it specifies a host. + */ +static bool SecURIMatch(CFStringRef URI, CFStringRef hostname) { + bool result = false; + CFStringRef URI_hostname = NULL; + CFCharacterSetRef port_or_path_separator = NULL; + /* URI must have scheme specified */ + CFRange URI_scheme = CFStringFind(URI, CFSTR("://"), 0); + require_quiet(URI_scheme.location != kCFNotFound, out); + + /* Remove scheme prefix and port or resource path suffix */ + CFRange URI_hostname_range = { URI_scheme.location + URI_scheme.length, + CFStringGetLength(URI) - URI_scheme.location - URI_scheme.length }; + port_or_path_separator = CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault, CFSTR(":/")); + CFRange separator = {kCFNotFound, 0}; + if(CFStringFindCharacterFromSet(URI, port_or_path_separator, URI_hostname_range, 0, &separator)) { + URI_hostname_range.length -= (CFStringGetLength(URI) - separator.location); + } + URI_hostname = CFStringCreateWithSubstring(kCFAllocatorDefault, URI, URI_hostname_range); + + /* Hostname in URI must not begin with '.' */ + require_quiet('.' != CFStringGetCharacterAtIndex(URI_hostname, 0), out); + + CFIndex ulength = CFStringGetLength(URI_hostname); + CFIndex hlength = CFStringGetLength(hostname); + require_quiet(ulength >= hlength, out); + CFRange compare_range = { 0, hlength }; + + /* Allow one or more preceding labels */ + if ('.' == CFStringGetCharacterAtIndex(hostname, 0)) { + compare_range.location = ulength - hlength; + } + + if(kCFCompareEqualTo == CFStringCompareWithOptions(URI_hostname, + hostname, + compare_range, + kCFCompareCaseInsensitive)) { + result = true; + } + +out: + CFReleaseNull(port_or_path_separator); + CFReleaseNull(URI_hostname); + return result; +} + +/* RFC 5280 Section 4.2.1.10: + A name constraint for Internet mail addresses MAY specify a + particular mailbox, all addresses at a particular host, or all + mailboxes in a domain. To indicate a particular mailbox, the + constraint is the complete mail address. For example, + "root@example.com" indicates the root mailbox on the host + "example.com". To indicate all Internet mail addresses on a + particular host, the constraint is specified as the host name. For + example, the constraint "example.com" is satisfied by any mail + address at the host "example.com". To specify any address within a + domain, the constraint is specified with a leading period (as with + URIs). + */ +static bool SecRFC822NameMatch(CFStringRef emailAddress, CFStringRef constraint) { + CFRange mailbox_range = CFStringFind(constraint,CFSTR("@"),0); + + /* Constraint specifies a particular mailbox. Perform full comparison. */ + if (mailbox_range.location != kCFNotFound) { + if (!CFStringCompare(emailAddress, constraint, kCFCompareCaseInsensitive)) { + return true; + } + else return false; + } + + mailbox_range = CFStringFind(emailAddress, CFSTR("@"), 0); + require_quiet(mailbox_range.location != kCFNotFound, out); + CFRange hostname_range = {mailbox_range.location + 1, + CFStringGetLength(emailAddress) - mailbox_range.location - 1 }; + + /* Constraint specificies a particular host. Compare hostname of address. */ + if ('.' != CFStringGetCharacterAtIndex(constraint, 0)) { + if (!CFStringCompareWithOptions(emailAddress, constraint, hostname_range, kCFCompareCaseInsensitive)) { + return true; + } + else return false; + } + + /* Constraint specificies a domain. Match hostname of address to domain name. */ + require_quiet('.' != CFStringGetCharacterAtIndex(emailAddress, mailbox_range.location +1), out); + if (CFStringHasSuffix(emailAddress, constraint)) { + return true; + } + +out: + return false; +} + +static bool nc_compare_directoryNames(const DERItem *certName, const DERItem *subtreeName) { + /* Get content of certificate name and subtree name */ + DERDecodedInfo certName_content; + require_noerr_quiet(DERDecodeItem(certName, &certName_content), out); + + DERDecodedInfo subtreeName_content; + require_noerr_quiet(DERDecodeItem(subtreeName, &subtreeName_content), out); + + if (certName->length > subtreeName->length) { + if(0 == memcmp(certName_content.content.data, + subtreeName_content.content.data, + subtreeName_content.content.length)) { + return true; + } + } + +out: + return false; +} + +static bool nc_compare_DNSNames(const DERItem *certName, const DERItem *subtreeName) { + bool result = false; + CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + certName->data, certName->length, + kCFStringEncodingUTF8, FALSE); + CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + subtreeName->data, subtreeName->length, + kCFStringEncodingUTF8, FALSE); + require_quiet(certName_str, out); + require_quiet(subtreeName_str, out); + + if (SecDNSNameConstraintsMatch(certName_str, subtreeName_str)) { + result = true; + } + +out: + CFReleaseNull(certName_str) ; + CFReleaseNull(subtreeName_str); + return result; +} + +static bool nc_compare_URIs(const DERItem *certName, const DERItem *subtreeName) { + bool result = false; + CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + certName->data, certName->length, + kCFStringEncodingUTF8, FALSE); + CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + subtreeName->data, subtreeName->length, + kCFStringEncodingUTF8, FALSE); + require_quiet(certName_str, out); + require_quiet(subtreeName_str, out); + + if (SecURIMatch(certName_str, subtreeName_str)) { + result = true; + } + +out: + CFReleaseNull(certName_str); + CFReleaseNull(subtreeName_str); + return result; +} + +static bool nc_compare_RFC822Names(const DERItem *certName, const DERItem *subtreeName) { + bool result = false; + CFStringRef certName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + certName->data, certName->length, + kCFStringEncodingUTF8, FALSE); + CFStringRef subtreeName_str = CFStringCreateWithBytes(kCFAllocatorDefault, + subtreeName->data, subtreeName->length, + kCFStringEncodingUTF8, FALSE); + require_quiet(certName_str, out); + require_quiet(subtreeName_str, out); + + if (SecRFC822NameMatch(certName_str, subtreeName_str)) { + result = true; + } + +out: + CFReleaseNull(certName_str); + CFReleaseNull(subtreeName_str); + return result; +} + +static bool nc_compare_IPAddresses(const DERItem *certAddr, const DERItem *subtreeAddr) { + bool result = false; + + /* Verify Subtree Address has correct number of bytes for IP and mask */ + require_quiet((subtreeAddr->length == 8) || (subtreeAddr->length == 32), out); + /* Verify Cert Address has correct number of bytes for IP */ + require_quiet((certAddr->length == 4) || (certAddr->length ==16), out); + /* Verify Subtree Address and Cert Address are the same version */ + require_quiet(subtreeAddr->length == 2*certAddr->length, out); + + DERByte * mask = subtreeAddr->data + certAddr->length; + for (DERSize i = 0; i < certAddr->length; i++) { + if((subtreeAddr->data[i] & mask[i]) != (certAddr->data[i] & mask[i])) { + return false; + } + } + return true; + +out: + return result; +} + +typedef struct { + bool present; + bool isMatch; +} match_t; + +typedef struct { + const SecCEGeneralNameType gnType; + const DERItem *cert_item; + match_t *match; +} nc_match_context_t; + +typedef struct { + const CFArrayRef subtrees; + match_t *match; + bool permit; +} nc_san_match_context_t; + +static OSStatus nc_compare_subtree(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { + nc_match_context_t *item_context = context; + if (item_context && gnType == item_context->gnType + && item_context->match && item_context->cert_item) { + + item_context->match->present = true; + /* + * We set isMatch such that if there are multiple subtrees of the same type, matching to any one + * of them is considered a match. + */ + switch (gnType) { + case GNT_DirectoryName: { + item_context->match->isMatch |= nc_compare_directoryNames(item_context->cert_item, generalName); + return errSecSuccess; + } + case GNT_DNSName: { + item_context->match->isMatch |= nc_compare_DNSNames(item_context->cert_item, generalName); + return errSecSuccess; + } + case GNT_URI: { + item_context->match->isMatch |= nc_compare_URIs(item_context->cert_item, generalName); + return errSecSuccess; + } + case GNT_RFC822Name: { + item_context->match->isMatch |= nc_compare_RFC822Names(item_context->cert_item, generalName); + return errSecSuccess; + } + case GNT_IPAddress: { + item_context->match->isMatch |= nc_compare_IPAddresses(item_context->cert_item, generalName); + return errSecSuccess; + } + default: { + /* If the name form is not supported, reject the certificate. */ + return errSecInvalidCertificate; + } + } + } + + return errSecInvalidCertificate; +} + +static void nc_decode_and_compare_subtree(const void *value, void *context) { + CFDataRef subtree = value; + nc_match_context_t *match_context = context; + if (subtree) { + /* convert subtree to DERItem */ + const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) }; + DERDecodedInfo general_name_content; + require_noerr_quiet(DERDecodeItem(&general_name, &general_name_content),out); + + OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, + &general_name_content.content, + match_context, + nc_compare_subtree); + if (status == errSecInvalidCertificate) { + secnotice("policy","can't parse general name or not a type we support"); + } + } +out: + return; +} + +static bool isEmptySubject(CFDataRef subject) { + const DERItem subject_der = { (unsigned char *)CFDataGetBytePtr(subject), CFDataGetLength(subject) }; + + /* Get content of certificate name */ + DERDecodedInfo subject_content; + require_noerr_quiet(DERDecodeItem(&subject_der, &subject_content), out); + if (subject_content.content.length) return false; + +out: + return true; +} + +/* + * We update match structs as follows: + * 'present' is true if there's any subtree of the same type as any Subject/SAN + * 'match' is false if the subtree(s) and Subject(s)/SAN(s) don't match. + * Note: the state of 'match' is meaningless without 'present' also being true. + */ +static void update_match(bool permit, match_t *input_match, match_t *output_match) { + if (!input_match || !output_match) { + return; + } + if (input_match->present) { + output_match->present = true; + if (permit) { + output_match->isMatch &= input_match->isMatch; + } else { + output_match->isMatch |= input_match->isMatch; + } + } +} + +static void nc_compare_RFC822Name_to_subtrees(const void *value, void *context) { + CFStringRef rfc822Name = (CFStringRef)value; + char *rfc822NameString = NULL; + nc_san_match_context_t *san_context = context; + CFArrayRef subtrees = NULL; + if (san_context) { + subtrees = san_context->subtrees; + } + if (subtrees) { + CFIndex num_trees = CFArrayGetCount(subtrees); + CFRange range = { 0, num_trees }; + match_t match = { false, false }; + rfc822NameString = CFStringToCString(rfc822Name); + if (!rfc822NameString) { return; } + const DERItem addr = { (unsigned char *)rfc822NameString, + CFStringGetLength(rfc822Name) }; + nc_match_context_t match_context = {GNT_RFC822Name, &addr, &match}; + CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &match_context); + free(rfc822NameString); + + update_match(san_context->permit, &match, san_context->match); + + } +} + +static void nc_compare_subject_to_subtrees(SecCertificateRef certificate, CFArrayRef subtrees, + bool permit, match_t *match) { + CFDataRef subject = SecCertificateCopySubjectSequence(certificate); + /* An empty subject name is considered not present */ + if (!subject || isEmptySubject(subject)) { + CFReleaseNull(subject); + return; + } + + /* Compare X.500 distinguished name constraints */ + CFIndex num_trees = CFArrayGetCount(subtrees); + CFRange range = { 0, num_trees }; + match_t x500_match = { false, false }; + const DERItem subject_der = { (unsigned char *)CFDataGetBytePtr(subject), CFDataGetLength(subject) }; + nc_match_context_t context = {GNT_DirectoryName, &subject_der, &x500_match}; + CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &context); + CFReleaseNull(subject); + update_match(permit, &x500_match, match); + + /* Compare RFC822 constraints to subject email address */ + match_t email_match = { false, permit }; + CFArrayRef rfc822Names = SecCertificateCopyRFC822NamesFromSubject(certificate); + if (rfc822Names) { + CFRange emailRange = { 0, CFArrayGetCount(rfc822Names) }; + nc_san_match_context_t emailContext = { subtrees, &email_match, permit }; + CFArrayApplyFunction(rfc822Names, emailRange, nc_compare_RFC822Name_to_subtrees, &emailContext); + } + CFReleaseNull(rfc822Names); + update_match(permit, &email_match, match); +} + +static OSStatus nc_compare_subjectAltName_to_subtrees(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) { + nc_san_match_context_t *san_context = context; + CFArrayRef subtrees = NULL; + if (san_context) { + subtrees = san_context->subtrees; + } + if (subtrees) { + CFIndex num_trees = CFArrayGetCount(subtrees); + CFRange range = { 0, num_trees }; + match_t match = { false, false }; + nc_match_context_t match_context = {gnType, generalName, &match}; + CFArrayApplyFunction(subtrees, range, nc_decode_and_compare_subtree, &match_context); + + update_match(san_context->permit, &match, san_context->match); + + return errSecSuccess; + } + + return errSecInvalidCertificate; +} + +OSStatus SecNameContraintsMatchSubtrees(SecCertificateRef certificate, CFArrayRef subtrees, bool *matched, bool permit) { + CFDataRef subject = NULL; + OSStatus status = errSecSuccess; + + require_action_quiet(subject = SecCertificateCopySubjectSequence(certificate), + out, + status = errSecInvalidCertificate); + const DERItem *subjectAltNames = SecCertificateGetSubjectAltName(certificate); + + /* Reject certificates with neither Subject Name nor SubjectAltName */ + require_action_quiet(!isEmptySubject(subject) || subjectAltNames, out, status = errSecInvalidCertificate); + + /* Verify that the subject name is within all of the subtrees */ + match_t subject_match = { false, permit }; + nc_compare_subject_to_subtrees(certificate, subtrees, permit, &subject_match); + + /* permit tells us whether to start with true or false. If we are looking at permitted + * subtrees, we are going to "and" the matching results because all present types must match + * to permit. For excluded subtrees, we are going to "or" the matching results because + * any matching present types causes exclusion. */ + match_t san_match = { false, permit }; + nc_san_match_context_t san_context = {subtrees, &san_match, permit}; + + /* And verify that each of the alternative names in the subjectAltName extension (critical or non-critical) + * is within any of the subtrees for that name type. */ + if (subjectAltNames) { + status = SecCertificateParseGeneralNames(subjectAltNames, + &san_context, + nc_compare_subjectAltName_to_subtrees); + /* If failed to parse */ + require_action_quiet(status == errSecSuccess, out, *matched = false); + } + + /* If we are excluding based on the subtrees, lack of names of the + same type is not a match. But if we are permitting, it is. + */ + if (subject_match.present) { + if (san_match.present && + ((subject_match.isMatch && !san_match.isMatch) || + (!subject_match.isMatch && san_match.isMatch))) { + /* If both san and subject types are present, but don't agree on match + * we should exclude on the basis of the match and not permit on the + * basis of the failed match. */ + *matched = permit ? false : true; + } + else { + /* If san type wasn't present or both had the same result, use the + * result from matching against the subject. */ + *matched = subject_match.isMatch; + } + } + else if (san_match.present) { + *matched = san_match.isMatch; + } + else { + /* Neither subject nor san had same type as subtrees, permit and don't + * exclude the cert. */ + *matched = permit ? true : false; + } + +out: + CFReleaseNull(subject); + return status; +} + +typedef struct { + CFMutableArrayRef existing_trees; + CFMutableArrayRef trees_to_add; +} nc_intersect_context_t; + +static SecCEGeneralNameType nc_gn_type_convert (DERTag tag) { + switch (tag) { + case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: + return GNT_OtherName; + case ASN1_CONTEXT_SPECIFIC | 1: + return GNT_RFC822Name; + case ASN1_CONTEXT_SPECIFIC | 2: + return GNT_DNSName; + case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: + return GNT_X400Address; + case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: + return GNT_DirectoryName; + case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: + return GNT_EdiPartyName; + case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: + case ASN1_CONTEXT_SPECIFIC | 6: + return GNT_URI; + case ASN1_CONTEXT_SPECIFIC | 7: + return GNT_IPAddress; + case ASN1_CONTEXT_SPECIFIC | 8: + return GNT_RegisteredID; + default: + return GNT_OtherName; + } +} + +/* The recommended processing algorithm states: + * If permittedSubtrees is present in the certificate, set the permitted_subtrees state variable to the intersection + * of its previous value and the value indicated in the extension field. + * However, in practice, certs are issued with permittedSubtrees whose intersection would be the empty set. For now, + * wherever a new permittedSubtree is a subset of an existing subtree, we'll replace the existing subtree; otherwise, + * we just append the new subtree. + */ +static void nc_intersect_tree_with_subtrees (const void *value, void *context) { + CFDataRef new_subtree = value; + nc_intersect_context_t *intersect_context = context; + CFMutableArrayRef existing_subtrees = intersect_context->existing_trees; + CFMutableArrayRef trees_to_append = intersect_context->trees_to_add; + + if (!new_subtree || !existing_subtrees) return; + + /* convert new subtree to DERItem */ + const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(new_subtree), CFDataGetLength(new_subtree) }; + DERDecodedInfo general_name_content; + if(DR_Success != DERDecodeItem(&general_name, &general_name_content)) return; + + SecCEGeneralNameType gnType; + DERItem *new_subtree_item = &general_name_content.content; + + /* Attempt to intersect if one of the supported types: DirectoryName and DNSName. + * Otherwise, just append the new tree. */ + gnType = nc_gn_type_convert(general_name_content.tag); + if (!(gnType == GNT_DirectoryName || gnType == GNT_DNSName)) { + CFArrayAppendValue(trees_to_append, new_subtree); + } + + CFIndex subtreeIX; + CFIndex num_existing_subtrees = CFArrayGetCount(existing_subtrees); + match_t match = { false, false }; + nc_match_context_t match_context = { gnType, new_subtree_item, &match}; + for (subtreeIX = 0; subtreeIX < num_existing_subtrees; subtreeIX++) { + CFDataRef candidate_subtree = CFArrayGetValueAtIndex(existing_subtrees, subtreeIX); + /* Convert candidate subtree to DERItem */ + const DERItem candidate = { (unsigned char *)CFDataGetBytePtr(candidate_subtree), CFDataGetLength(candidate_subtree) }; + DERDecodedInfo candidate_content; + /* We could probably just delete any subtrees in the array that don't decode */ + if(DR_Success != DERDecodeItem(&candidate, &candidate_content)) continue; + + /* first test whether new tree matches the existing tree */ + OSStatus status = SecCertificateParseGeneralNameContentProperty(candidate_content.tag, + &candidate_content.content, + &match_context, + nc_compare_subtree); + if((status == errSecSuccess) && match.present && match.isMatch) { + break; + } + + /* then test whether existing tree matches the new tree*/ + match_t local_match = { false , false }; + nc_match_context_t local_match_context = { nc_gn_type_convert(candidate_content.tag), + &candidate_content.content, + &local_match }; + status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag, + &general_name_content.content, + &local_match_context, + nc_compare_subtree); + if((status == errSecSuccess) && local_match.present && local_match.isMatch) { + break; + } + } + if (subtreeIX == num_existing_subtrees) { + /* No matches found. Append new subtree */ + CFArrayAppendValue(trees_to_append, new_subtree); + } + else if (match.present && match.isMatch) { + /* new subtree \subseteq existing subtree, replace existing tree */ + CFArraySetValueAtIndex(existing_subtrees, subtreeIX, new_subtree); + } + /* existing subtree \subset new subtree, drop the new tree so as not to broaden constraints*/ + return; + +} + +void SecNameConstraintsIntersectSubtrees(CFMutableArrayRef subtrees_state, CFArrayRef subtrees_new) { + assert(subtrees_state); + assert(subtrees_new); + + CFIndex num_new_trees = CFArrayGetCount(subtrees_new); + CFRange range = { 0, num_new_trees }; + + /* if existing subtrees state contains no subtrees, append new subtrees whole */ + if (!CFArrayGetCount(subtrees_state)) { + CFArrayAppendArray(subtrees_state, subtrees_new, range); + return; + } + + CFMutableArrayRef trees_to_append = NULL; + trees_to_append = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + nc_intersect_context_t context = { subtrees_state , trees_to_append }; + CFArrayApplyFunction(subtrees_new, range, nc_intersect_tree_with_subtrees, &context); + + /* don't append to the state until we've processed all the new trees */ + num_new_trees = CFArrayGetCount(trees_to_append); + if (trees_to_append && num_new_trees) { + range.length = num_new_trees; + CFArrayAppendArray(subtrees_state, trees_to_append, range); + } + + CFReleaseNull(trees_to_append); +} diff --git a/trust/trustd/nameconstraints.h b/trust/trustd/nameconstraints.h new file mode 100644 index 00000000..e0311a8b --- /dev/null +++ b/trust/trustd/nameconstraints.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header nameconstraints + The functions provided in nameconstraints.h provide an interface to + a name constraints implementation as specified in section 4.2.1.10 of rfc5280. + */ + +#ifndef _SECURITY_NAMECONSTRAINTS_H_ +#define _SECURITY_NAMECONSTRAINTS_H_ + +#include +#include +#include + +OSStatus SecNameContraintsMatchSubtrees(SecCertificateRef certificate, CFArrayRef subtrees, bool *matched, bool permit); + +void SecNameConstraintsIntersectSubtrees(CFMutableArrayRef subtrees_state, CFArrayRef subtrees_new); + +#endif /* SECURITY_NAMECONSTRAINTS_H */ diff --git a/trust/trustd/personalization.c b/trust/trustd/personalization.c new file mode 100644 index 00000000..05e42b9e --- /dev/null +++ b/trust/trustd/personalization.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "personalization.h" +#include +#include +#include +#include + diff --git a/trust/trustd/personalization.h b/trust/trustd/personalization.h new file mode 100644 index 00000000..6f6bf262 --- /dev/null +++ b/trust/trustd/personalization.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _SECURITY_PERSONALIZATION_H_ +#define _SECURITY_PERSONALIZATION_H_ + +#include +#include +#include + + +#endif /* _SECURITY_PERSONALIZATION_H_ */ diff --git a/trust/trustd/policytree.c b/trust/trustd/policytree.c new file mode 100644 index 00000000..2dacf7ef --- /dev/null +++ b/trust/trustd/policytree.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2009-2010,2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * policytree.c - rfc5280 section 6.1.2 and later policy_tree implementation. + */ + +#include "policytree.h" +#include + +#include + +#include + +#define DUMP_POLICY_TREE 0 + +#if !defined(DUMP_POLICY_TREE) +#include +#endif + +static policy_set_t policy_set_create(const oid_t *p_oid) { + policy_set_t policy_set = + (policy_set_t)malloc(sizeof(*policy_set)); + policy_set->oid_next = NULL; + policy_set->oid = *p_oid; + secdebug("policy-set", "%p", policy_set); + return policy_set; +} + +void policy_set_add(policy_set_t *policy_set, const oid_t *p_oid) { + policy_set_t node = (policy_set_t)malloc(sizeof(*node)); + node->oid_next = *policy_set; + node->oid = *p_oid; + *policy_set = node; + secdebug("policy-set", "%p -> %p", node, node->oid_next); +} + +void policy_set_free(policy_set_t node) { + while (node) { + policy_set_t next = node->oid_next; + secdebug("policy-set", "%p -> %p", node, next); + free(node); + node = next; + } +} + +bool policy_set_contains(policy_set_t node, const oid_t *oid) { + for (; node; node = node->oid_next) { + if (oid_equal(node->oid, *oid)) + return true; + } + return false; +} + +void policy_set_intersect(policy_set_t *policy_set, policy_set_t other_set) { + bool other_has_any = policy_set_contains(other_set, &oidAnyPolicy); + if (policy_set_contains(*policy_set, &oidAnyPolicy)) { + policy_set_t node = other_set; + if (other_has_any) { + /* Both sets contain anyPolicy so the intersection is anyPolicy + plus all oids in either set. */ + while (node) { + if (!policy_set_contains(*policy_set, &node->oid)) { + policy_set_add(policy_set, &node->oid); + } + } + } else { + /* The result set contains anyPolicy and other_set doesn't. The + result set should be a copy of other_set. */ + policy_set_free(*policy_set); + *policy_set = NULL; + while (node) { + policy_set_add(policy_set, &node->oid); + } + } + } else if (!other_has_any) { + /* Neither set contains any policy oid so remove any values from the + result set that aren't in other_set. */ + policy_set_t *pnode = policy_set; + while (*pnode) { + policy_set_t node = *pnode; + if (policy_set_contains(other_set, &node->oid)) { + pnode = &node->oid_next; + } else { + *pnode = node->oid_next; + node->oid_next = NULL; + policy_set_free(node); + } + } + } +} + +policy_tree_t policy_tree_create(const oid_t *p_oid, policy_qualifier_t p_q) { + policy_tree_t node = malloc(sizeof(*node)); + memset(node, 0, sizeof(*node)); + node->valid_policy = *p_oid; + node->qualifier_set = p_q; + node->expected_policy_set = policy_set_create(p_oid); + secdebug("policy-node", "%p", node); + return node; +} + +/* Walk the nodes in a tree at depth and invoke callback for each one. */ +bool policy_tree_walk_depth(policy_tree_t root, int depth, + bool(*callback)(policy_tree_t, void *), void *ctx) { + policy_tree_t *stack = (policy_tree_t *)malloc(sizeof(policy_tree_t) * (depth + 1)); + if (!stack) { + return false; + } + int stack_ix = 0; + stack[stack_ix] = root; + policy_tree_t node; + bool match = false; + bool child_visited = false; + while (stack_ix >= 0) { + /* stack[stack_ix - 1] is the parent of the current node. */ + node = stack[stack_ix]; + policy_tree_t child = node->children; + if (!child_visited && stack_ix < depth && child ) { + /* If we have a child and we haven't reached the + required depth yet, we go depth first and proccess it. */ + stack[++stack_ix] = child; + } else { + /* Get the sibling now in case we delete the node in the callback */ + policy_tree_t sibling = node->siblings; + if (stack_ix == depth) { + /* Proccess node. */ + match |= callback(node, ctx); + } + + /* Move on to sibling of node. */ + if (sibling) { + /* Replace current node with it's sibling. */ + stack[stack_ix] = sibling; + child_visited = false; + } else { + /* No more siblings left, so pop the stack and backtrack. */ + stack_ix--; + /* We've handled the top of the stack's child already so + just look at it's siblings. */ + child_visited = true; + } + } + } + free(stack); + return match; +} + +static void policy_tree_free_node(policy_tree_t node) { + secdebug("policy-node", "%p children: %p siblngs: %p", node, + node->children, node->siblings); + if (node->expected_policy_set) { + policy_set_free(node->expected_policy_set); + node->expected_policy_set = NULL; + } + free(node); +} + +void policy_tree_remove_node(policy_tree_t *node) { + /* Free node's children */ + policy_tree_t *child = &(*node)->children; + if (*child) + policy_tree_prune(child); + + /* Remove node from parent */ + policy_tree_t parent = (*node)->parent; + parent->children = (*node)->siblings; + + /* Free node */ + policy_tree_free_node(*node); + *node = NULL; +} + +/* Prune nodes from node down. */ +void policy_tree_prune(policy_tree_t *node) { + /* Free all our children and siblings. */ + policy_tree_t *child = &(*node)->children; + if (*child) + policy_tree_prune(child); + policy_tree_t *sibling = &(*node)->siblings; + if (*sibling) + policy_tree_prune(sibling); + policy_tree_free_node(*node); + *node = NULL; +} + +/* Prune childless nodes at depth. */ +void policy_tree_prune_childless(policy_tree_t *root, int depth) { + policy_tree_t *stack[depth + 1]; + int stack_ix = 0; + stack[stack_ix] = root; + bool child_visited = false; + while (stack_ix >= 0) { + policy_tree_t *node; + node = stack[stack_ix]; + policy_tree_t *child = &(*node)->children; + if (!child_visited && stack_ix < depth && *child) { + /* If we have a child and we haven't reached the + required depth yet, we go depth first and proccess it. */ + stack[++stack_ix] = child; + } else if (!*child) { + /* Childless node found, nuke it. */ +#if !defined(DUMP_POLICY_TREE) + printf("# prune /<%.08lx<\\ |%.08lx| >%.08lx> :%s: depth %d\n", + (intptr_t)node, (intptr_t)*node, (intptr_t)(*node)->siblings, + (child_visited ? "v" : " "), stack_ix); +#endif + + policy_tree_t next = (*node)->siblings; + (*node)->siblings = NULL; + policy_tree_free_node(*node); + *node = next; + if (next) { + /* stack[stack_ix] (node) already points to next now. */ + child_visited = false; + } else { + /* No more siblings left, so pop the stack and backtrack. */ + stack_ix--; + child_visited = true; + } + } else { + policy_tree_t *sibling = &(*node)->siblings; + if (*sibling) { + /* Replace current node with it's sibling. */ + stack[stack_ix] = sibling; + child_visited = false; + } else { + /* No more siblings left, so pop the stack and backtrack. */ + stack_ix--; + child_visited = true; + } + } + } +} + +/* Add a new child to the tree. */ +static void policy_tree_add_child_explicit(policy_tree_t parent, + const oid_t *p_oid, policy_qualifier_t p_q, policy_set_t p_expected) { + policy_tree_t child = malloc(sizeof(*child)); + memset(child, 0, sizeof(*child)); + child->valid_policy = *p_oid; + child->qualifier_set = p_q; + child->expected_policy_set = p_expected; + child->parent = parent; + +#if 0 + printf("# /%.08lx\\ |%.08lx| \\%.08lx/ >%.08lx> \\>%.08lx>/\n", + (intptr_t)parent, (intptr_t)child, (intptr_t)parent->children, + (intptr_t)parent->siblings, + (intptr_t)(parent->children ? parent->children->siblings : NULL)); +#endif + + /* Previous child becomes new child's first sibling. */ + child->siblings = parent->children; + /* New child becomes parent's first child. */ + parent->children = child; + + secdebug("policy-node", "%p siblngs: %p", child, child->siblings); +} + +/* Add a new child to the tree parent setting valid_policy to p_oid, + qualifier_set to p_q and expected_policy_set to a set containing + just p_oid. */ +void policy_tree_add_child(policy_tree_t parent, + const oid_t *p_oid, policy_qualifier_t p_q) { + policy_set_t policy_set = policy_set_create(p_oid); + policy_tree_add_child_explicit(parent, p_oid, p_q, policy_set); +} + +/* Add a new sibling to the tree setting valid_policy to p_oid, + qualifier set to p_q and expected_policy_set to p_expected */ +void policy_tree_add_sibling(policy_tree_t sibling, const oid_t *p_oid, + policy_qualifier_t p_q, policy_set_t p_expected) { + policy_tree_add_child_explicit(sibling->parent, p_oid, p_q, p_expected); +} + +void policy_tree_set_expected_policy(policy_tree_t node, + policy_set_t p_expected) { + if (node->expected_policy_set) + policy_set_free(node->expected_policy_set); + node->expected_policy_set = p_expected; +} + +#if !defined(DUMP_POLICY_TREE) +/* Dump a policy tree. */ +static void policy_tree_dump4(policy_tree_t node, policy_tree_t parent, + policy_tree_t prev_sibling, int depth) { + policy_tree_t child = node->children; + policy_tree_t sibling = node->siblings; + static const char *spaces = " "; + printf("# %.*s/%.08lx\\ |%.08lx| <%.08lx< >%.08lx> depth %d\n", + depth * 11, spaces, + (intptr_t)parent, (intptr_t)node, (intptr_t)prev_sibling, + (intptr_t)sibling, depth); + if (child) + policy_tree_dump4(child, node, NULL, depth + 1); + if (sibling) + policy_tree_dump4(sibling, parent, node, depth); +} +#endif /* !defined(DUMP_POLICY_TREE) */ + +void policy_tree_dump(policy_tree_t node) { +#if !defined(DUMP_POLICY_TREE) + policy_tree_dump4(node, NULL, NULL, 0); +#endif /* !defined(DUMP_POLICY_TREE) */ +} diff --git a/trust/trustd/policytree.h b/trust/trustd/policytree.h new file mode 100644 index 00000000..bbc07ebf --- /dev/null +++ b/trust/trustd/policytree.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header policytree + The functions provided in policytree.h provide an interface to + a policy_tree implementation as specified in section 6 of rfc5280. +*/ + +#ifndef _SECURITY_POLICYTREE_H_ +#define _SECURITY_POLICYTREE_H_ + +#include +#include +#include + +__BEGIN_DECLS + + +#define oid_equal(oid1, oid2) DEROidCompare(&oid1, &oid2) +typedef DERItem oid_t; +typedef DERItem der_t; + +typedef struct policy_set *policy_set_t; +struct policy_set { + oid_t oid; + policy_set_t oid_next; +}; + +typedef const DERItem *policy_qualifier_t; + +typedef struct policy_tree *policy_tree_t; +struct policy_tree { + oid_t valid_policy; + policy_qualifier_t qualifier_set; + policy_set_t expected_policy_set; + policy_tree_t children; + policy_tree_t siblings; + policy_tree_t parent; +}; + +void policy_set_add(policy_set_t *policy_set, const oid_t *p_oid); +void policy_set_intersect(policy_set_t *policy_set, policy_set_t other_set); +bool policy_set_contains(policy_set_t policy_set, const oid_t *oid); +void policy_set_free(policy_set_t policy_set); + +policy_tree_t policy_tree_create(const oid_t *p_oid, policy_qualifier_t p_q); + +bool policy_tree_walk_depth(policy_tree_t root, int depth, + bool(*callback)(policy_tree_t, void *), void *ctx); + +void policy_tree_remove_node(policy_tree_t *node); +void policy_tree_prune(policy_tree_t *node); +void policy_tree_prune_childless(policy_tree_t *root, int depth); +void policy_tree_add_child(policy_tree_t parent, + const oid_t *p_oid, policy_qualifier_t p_q); +void policy_tree_add_sibling(policy_tree_t sibling, const oid_t *p_oid, + policy_qualifier_t p_q, policy_set_t p_expected); +void policy_tree_set_expected_policy(policy_tree_t node, + policy_set_t p_expected); + +/* noop unless !defined NDEBUG */ +void policy_tree_dump(policy_tree_t node); + +__END_DECLS + +#endif /* !_SECURITY_POLICYTREE_H_ */ diff --git a/trust/trustd/trustd-Info.plist b/trust/trustd/trustd-Info.plist new file mode 100644 index 00000000..98f152cf --- /dev/null +++ b/trust/trustd/trustd-Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSHumanReadableCopyright + Copyright © 2015-2017 Apple. All rights reserved. + XPCService + + ServiceType + System + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + diff --git a/trust/trustd/trustd-Prefix.pch b/trust/trustd/trustd-Prefix.pch new file mode 100644 index 00000000..34946106 --- /dev/null +++ b/trust/trustd/trustd-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'security.auth' target in the 'security.auth' project +// + +#include "authtypes.h" +#include "object.h" + +#include +#include +#include +#include +#include +#include +#include diff --git a/trust/trustd/trustd.c b/trust/trustd/trustd.c new file mode 100644 index 00000000..02e9808a --- /dev/null +++ b/trust/trustd/trustd.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecPinningDb.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecTrustServer.h" +#include "keychain/securityd/spi.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#if TARGET_OS_IPHONE +#include "trust/trustd/SecTrustExceptionResetCount.h" +#endif + +#if TARGET_OS_OSX +#include +#include +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" +#endif + +#include "OTATrustUtilities.h" +#include "trustd_spi.h" + +static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) { + if (!path) + return true; + __block xpc_object_t xpc_chain = NULL; + require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed"))); + CFArrayForEach(path, ^(const void *value) { + SecCertificateRef cert = (SecCertificateRef)value; + if (xpc_chain && !SecCertificateAppendToXPCArray(cert, xpc_chain, error)) { + xpc_release(xpc_chain); + xpc_chain = NULL; + } + }); + +exit: + if (!xpc_chain) + return false; + + xpc_dictionary_set_value(message, key, xpc_chain); + xpc_release(xpc_chain); + return true; +} + +static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) { + size_t length = 0; + const void *bytes = xpc_dictionary_get_data(message, key, &length); + if (bytes) { + SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length); + if (certificate) + return certificate; + SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key); + } else { + SecError(errSecParam, error, CFSTR("object for key %s missing"), key); + } + return NULL; +} + +static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { + xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); + if (!xpc_certificates) + return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key); + *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); + return *certificates; +} + +static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { + xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); + if (!xpc_certificates) { + *certificates = NULL; + return true; + } + *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); + return *certificates; +} + +static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) { + xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key); + if (!xpc_policies) { + if (policies) + *policies = NULL; + return true; + } + *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error); + return *policies != NULL; +} + +// Returns error if entitlement isn't present. +static bool +EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error) +{ + if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) { + SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement); + return false; + } + return true; +} + +static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) { + SecTrustStoreRef ts = NULL; + CFStringRef domain = SecXPCDictionaryCopyString(message, key, error); + if (domain) { + ts = SecTrustStoreForDomainName(domain, error); + CFRelease(domain); + } + return ts; +} + +static bool SecXPCTrustStoreContains(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + bool contains; + if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) { + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains); + result = true; + } + CFReleaseNull(digest); + } + } + return result; +} + +static bool SecXPCTrustStoreSetTrustSettings(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool noError = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error); + if (certificate) { + CFTypeRef trustSettingsDictOrArray = NULL; + if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, error)) { + bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, error); + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + noError = true; + CFReleaseSafe(trustSettingsDictOrArray); + } + CFReleaseNull(certificate); + } + } + return noError; +} + +static bool SecXPCTrustStoreRemoveCertificate(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error); + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + CFReleaseNull(digest); + return true; + } + } + return false; +} + +static bool SecXPCTrustStoreCopyAll(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFArrayRef trustStoreContents = NULL; + if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) { + SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error); + CFReleaseNull(trustStoreContents); + return true; + } + } + return false; +} + +static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + CFArrayRef usageConstraints = NULL; + if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) { + SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error); + CFReleaseNull(usageConstraints); + result = true; + } + CFReleaseNull(digest); + } + } + return result; +} + +static bool SecXPC_OCSPCacheFlush(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t __unused reply, CFErrorRef *error) { + if(SecOCSPCacheFlush(error)) { + return true; + } + return false; +} + +static bool SecXPC_OTAPKI_GetCurrentTrustStoreVersion(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentTrustStoreVersion(error)); + return true; +} + +static bool SecXPC_OTAPKI_GetCurrentAssetVersion(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentAssetVersion(error)); + return true; +} + +static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType"); + CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error); + if (array) { + xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array); + xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array); + xpc_release(xpc_array); + result = true; + } + CFReleaseNull(array); + return result; +} + +static bool SecXPC_OTAPKI_GetNewAsset(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKISignalNewAsset(error)); + return true; +} + +static bool SecXPC_OTASecExperiment_GetNewAsset(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTASecExperimentGetNewAsset(error)); + return true; +} + +static bool SecXPC_OTASecExperiment_GetAsset(SecurityClient * __unused client, xpc_object_t __unused event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + CFDictionaryRef asset = SecOTASecExperimentCopyAsset(error); + if (asset) { + xpc_object_t xpc_dict = _CFXPCCreateXPCObjectFromCFObject(asset); + if (xpc_dict) { + xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dict); + xpc_release(xpc_dict); + result = true; + } + } + CFReleaseNull(asset); + return result; +} + +static bool SecXPC_OTAPKI_CopyTrustedCTLogs(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + CFDictionaryRef trustedLogs = SecOTAPKICopyCurrentTrustedCTLogs(error); + if (trustedLogs) { + xpc_object_t xpc_dictionary = _CFXPCCreateXPCObjectFromCFObject(trustedLogs); + if (xpc_dictionary) { + xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dictionary); + xpc_release(xpc_dictionary); + result = true; + } + } + CFReleaseNull(trustedLogs); + return result; +} + +static bool SecXPC_OTAPKI_CopyCTLogForKeyID(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + bool result = false; + size_t length = 0; + const void *bytes = xpc_dictionary_get_data(event, kSecXPCData, &length); + CFDataRef keyID = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull); + if (keyID) { + CFDictionaryRef logDict = SecOTAPKICopyCTLogForKeyID(keyID, error); + if (logDict) { + xpc_object_t xpc_dictionary = _CFXPCCreateXPCObjectFromCFObject(logDict); + xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_dictionary); + xpc_release(xpc_dictionary); + CFReleaseNull(logDict); + result = true; + } + CFReleaseNull(keyID); + } + return result; +} + +static bool SecXPC_Networking_AnalyticsReport(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + xpc_object_t attributes = xpc_dictionary_get_dictionary(event, kSecTrustEventAttributesKey); + CFStringRef eventName = SecXPCDictionaryCopyString(event, kSecTrustEventNameKey, error); + bool result = false; + if (attributes && eventName) { + result = SecNetworkingAnalyticsReport(eventName, attributes, error); + } + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + CFReleaseNull(eventName); + return result; +} + +static bool SecXPCTrustStoreSetCTExceptions(SecurityClient *client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + CFStringRef appID = NULL; + CFDictionaryRef exceptions = NULL; + if (!SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error) || !appID) { + /* We always want to set the app ID with the exceptions */ + appID = SecTaskCopyApplicationIdentifier(client->task); + } + (void)SecXPCDictionaryCopyDictionaryOptional(event, kSecTrustExceptionsKey, &exceptions, error); + bool result = _SecTrustStoreSetCTExceptions(appID, exceptions, error); + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + CFReleaseNull(exceptions); + CFReleaseNull(appID); + return false; +} + +static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient * __unused client, xpc_object_t event, + xpc_object_t reply, CFErrorRef *error) { + CFStringRef appID = NULL; + (void)SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error); + CFDictionaryRef exceptions = _SecTrustStoreCopyCTExceptions(appID, error); + SecXPCDictionarySetPListOptional(reply, kSecTrustExceptionsKey, exceptions, error); + CFReleaseNull(exceptions); + CFReleaseNull(appID); + return false; +} + +#if TARGET_OS_IPHONE +static bool SecXPCTrustGetExceptionResetCount(SecurityClient * __unused client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + uint64_t exceptionResetCount = SecTrustServerGetExceptionResetCount(error); + if (error && *error) { + return false; + } + + xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, exceptionResetCount); + return true; +} + +static bool SecXPCTrustIncrementExceptionResetCount(SecurityClient * __unused client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + OSStatus status = errSecInternal; + bool result = SecTrustServerIncrementExceptionResetCount(error); + if (result && (!error || (error && !*error))) { + status = errSecSuccess; + } + + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, status); + return result; +} +#endif + +typedef bool(*SecXPCOperationHandler)(SecurityClient *client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error); + +typedef struct { + CFStringRef entitlement; + SecXPCOperationHandler handler; +} SecXPCServerOperation; + +struct trustd_operations { + SecXPCServerOperation trust_store_contains; + SecXPCServerOperation trust_store_set_trust_settings; + SecXPCServerOperation trust_store_remove_certificate; + SecXPCServerOperation trust_store_copy_all; + SecXPCServerOperation trust_store_copy_usage_constraints; + SecXPCServerOperation ocsp_cache_flush; + SecXPCServerOperation ota_pki_trust_store_version; + SecXPCServerOperation ota_pki_asset_version; + SecXPCServerOperation ota_pki_get_escrow_certs; + SecXPCServerOperation ota_pki_get_new_asset; + SecXPCServerOperation ota_pki_copy_trusted_ct_logs; + SecXPCServerOperation ota_pki_copy_ct_log_for_keyid; + SecXPCServerOperation networking_analytics_report; + SecXPCServerOperation trust_store_set_ct_exceptions; + SecXPCServerOperation trust_store_copy_ct_exceptions; + SecXPCServerOperation ota_secexperiment_get_asset; + SecXPCServerOperation ota_secexperiment_get_new_asset; +#if TARGET_OS_IPHONE + SecXPCServerOperation trust_get_exception_reset_count; + SecXPCServerOperation trust_increment_exception_reset_count; +#endif +}; + +static struct trustd_operations trustd_ops = { + .trust_store_contains = { NULL, SecXPCTrustStoreContains }, + .trust_store_set_trust_settings = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetTrustSettings }, + .trust_store_remove_certificate = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreRemoveCertificate }, + .trust_store_copy_all = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyAll }, + .trust_store_copy_usage_constraints = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyUsageConstraints }, + .ocsp_cache_flush = { NULL, SecXPC_OCSPCacheFlush }, + .ota_pki_trust_store_version = { NULL, SecXPC_OTAPKI_GetCurrentTrustStoreVersion }, + .ota_pki_asset_version = { NULL, SecXPC_OTAPKI_GetCurrentAssetVersion }, + .ota_pki_get_escrow_certs = { NULL, SecXPC_OTAPKI_GetEscrowCertificates }, + .ota_pki_get_new_asset = { NULL, SecXPC_OTAPKI_GetNewAsset }, + .ota_secexperiment_get_new_asset = { NULL, SecXPC_OTASecExperiment_GetNewAsset }, + .ota_secexperiment_get_asset = { NULL, SecXPC_OTASecExperiment_GetAsset }, + .ota_pki_copy_trusted_ct_logs = { NULL, SecXPC_OTAPKI_CopyTrustedCTLogs }, + .ota_pki_copy_ct_log_for_keyid = { NULL, SecXPC_OTAPKI_CopyCTLogForKeyID }, + .networking_analytics_report = { NULL, SecXPC_Networking_AnalyticsReport }, + .trust_store_set_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetCTExceptions }, + .trust_store_copy_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyCTExceptions }, +#if TARGET_OS_IPHONE + .trust_get_exception_reset_count = { NULL, SecXPCTrustGetExceptionResetCount }, + .trust_increment_exception_reset_count = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustIncrementExceptionResetCount }, +#endif +}; + +static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) { + xpc_type_t type = xpc_get_type(event); + __block CFErrorRef error = NULL; + xpc_object_t xpcError = NULL; + xpc_object_t replyMessage = NULL; + CFDataRef clientAuditToken = NULL; + CFArrayRef domains = NULL; + SecurityClient client = { + .task = NULL, + .accessGroups = NULL, + .musr = NULL, + .uid = xpc_connection_get_euid(connection), + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + .canAccessNetworkExtensionAccessGroups = false, +#if TARGET_OS_IPHONE + .inMultiUser = false, +#endif + }; + + secdebug("serverxpc", "entering"); + if (type == XPC_TYPE_DICTIONARY) { + replyMessage = xpc_dictionary_create_reply(event); + + uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation); + + audit_token_t auditToken = {}; + xpc_connection_get_audit_token(connection, &auditToken); + + client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); + clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken)); + client.accessGroups = SecTaskCopyAccessGroups(client.task); + + secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation); + + if (operation == sec_trust_evaluate_id) { + CFArrayRef certificates = NULL, anchors = NULL, policies = NULL, responses = NULL, scts = NULL, trustedLogs = NULL, exceptions = NULL; + bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey); + bool keychainsAllowed = xpc_dictionary_get_bool(event, kSecTrustKeychainsAllowedKey); + double verifyTime; + if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) && + SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) && + SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) && + SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustResponsesKey, &responses, &error) && + SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustSCTsKey, &scts, &error) && + SecXPCDictionaryCopyArrayOptional(event, kSecTrustTrustedLogsKey, &trustedLogs, &error) && + SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error) && + SecXPCDictionaryCopyArrayOptional(event, kSecTrustExceptionsKey, &exceptions, &error)) { + // If we have no error yet, capture connection and reply in block and properly retain them. + xpc_retain(connection); + CFRetainSafe(client.task); + CFRetainSafe(clientAuditToken); + + // Clear replyMessage so we don't send a synchronous reply. + xpc_object_t asyncReply = replyMessage; + replyMessage = NULL; + + SecTrustServerEvaluateBlock(SecTrustServerGetWorkloop(), clientAuditToken, certificates, anchors, anchorsOnly, keychainsAllowed, policies, + responses, scts, trustedLogs, verifyTime, client.accessGroups, exceptions, + ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, + CFErrorRef replyError) { + // Send back reply now + if (replyError) { + CFRetain(replyError); + } else { + xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr); + SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) && + SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) && + SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError); + } + if (replyError) { + secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError); + xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError); + if (xpcReplyError) { + xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError); + xpc_release(xpcReplyError); + } + CFReleaseNull(replyError); + } else { + secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply); + } + + xpc_connection_send_message(connection, asyncReply); + xpc_release(asyncReply); + xpc_release(connection); + CFReleaseSafe(client.task); + CFReleaseSafe(clientAuditToken); + }); + } + CFReleaseSafe(policies); + CFReleaseSafe(anchors); + CFReleaseSafe(certificates); + CFReleaseSafe(responses); + CFReleaseSafe(scts); + CFReleaseSafe(trustedLogs); + CFReleaseSafe(exceptions); + } else { + SecXPCServerOperation *server_op = NULL; + switch (operation) { + case sec_trust_store_contains_id: + server_op = &trustd_ops.trust_store_contains; + break; + case sec_trust_store_set_trust_settings_id: + server_op = &trustd_ops.trust_store_set_trust_settings; + break; + case sec_trust_store_remove_certificate_id: + server_op = &trustd_ops.trust_store_remove_certificate; + break; + case sec_trust_store_copy_all_id: + server_op = &trustd_ops.trust_store_copy_all; + break; + case sec_trust_store_copy_usage_constraints_id: + server_op = &trustd_ops.trust_store_copy_usage_constraints; + break; + case sec_ocsp_cache_flush_id: + server_op = &trustd_ops.ocsp_cache_flush; + break; + case sec_ota_pki_trust_store_version_id: + server_op = &trustd_ops.ota_pki_trust_store_version; + break; + case sec_ota_pki_asset_version_id: + server_op = &trustd_ops.ota_pki_asset_version; + break; + case kSecXPCOpOTAGetEscrowCertificates: + server_op = &trustd_ops.ota_pki_get_escrow_certs; + break; + case kSecXPCOpOTAPKIGetNewAsset: + server_op = &trustd_ops.ota_pki_get_new_asset; + break; + case kSecXPCOpOTASecExperimentGetNewAsset: + server_op = &trustd_ops.ota_secexperiment_get_new_asset; + break; + case kSecXPCOpOTASecExperimentGetAsset: + server_op = &trustd_ops.ota_secexperiment_get_asset; + break; + case kSecXPCOpOTAPKICopyTrustedCTLogs: + server_op = &trustd_ops.ota_pki_copy_trusted_ct_logs; + break; + case kSecXPCOpOTAPKICopyCTLogForKeyID: + server_op = &trustd_ops.ota_pki_copy_ct_log_for_keyid; + break; + case kSecXPCOpNetworkingAnalyticsReport: + server_op = &trustd_ops.networking_analytics_report; + break; + case kSecXPCOpSetCTExceptions: + server_op = &trustd_ops.trust_store_set_ct_exceptions; + break; + case kSecXPCOpCopyCTExceptions: + server_op = &trustd_ops.trust_store_copy_ct_exceptions; + break; +#if TARGET_OS_IPHONE + case sec_trust_get_exception_reset_count_id: + server_op = &trustd_ops.trust_get_exception_reset_count; + break; + case sec_trust_increment_exception_reset_count_id: + server_op = &trustd_ops.trust_increment_exception_reset_count; + break; +#endif + default: + break; + } + if (server_op && server_op->handler) { + bool entitled = true; + if (server_op->entitlement) { + entitled = EntitlementPresentAndTrue(operation, client.task, server_op->entitlement, &error); + } + if (entitled) { + (void)server_op->handler(&client, event, replyMessage, &error); + } + } + } + + if (error) + { + if(SecErrorGetOSStatus(error) == errSecItemNotFound) + secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + else if (SecErrorGetOSStatus(error) == errSecAuthNeeded) + secwarning("Authentication is needed %@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + else + secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + + xpcError = SecCreateXPCObjectWithCFError(error); + if (replyMessage) { + xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError); + } + } else if (replyMessage) { + secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage); + } + } else { + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, &error, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event); + secerror("%@: returning error: %@", client.task, error); + xpcError = SecCreateXPCObjectWithCFError(error); + replyMessage = xpc_create_reply_with_format(event, "{%string: %value}", kSecXPCKeyError, xpcError); + } + + if (replyMessage) { + xpc_connection_send_message(connection, replyMessage); + xpc_release(replyMessage); + } + if (xpcError) + xpc_release(xpcError); + CFReleaseSafe(error); + CFReleaseSafe(client.accessGroups); + CFReleaseSafe(client.musr); + CFReleaseSafe(client.task); + CFReleaseSafe(domains); + CFReleaseSafe(clientAuditToken); +} + +static void trustd_xpc_init(const char *service_name) +{ + secdebug("serverxpc", "start"); + xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!listener) { + seccritical("security failed to register xpc listener for %s, exiting", service_name); + abort(); + } + + xpc_connection_set_event_handler(listener, ^(xpc_object_t connection) { + if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) { + xpc_connection_set_target_queue(connection, SecTrustServerGetWorkloop()); + xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { + if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { + trustd_xpc_dictionary_handler(connection, event); + } + }); + xpc_connection_activate(connection); + } + }); + xpc_connection_activate(listener); +} + +static void trustd_sandbox(void) { +#if TARGET_OS_OSX + char buf[PATH_MAX] = ""; + + if (!_set_user_dir_suffix("com.apple.trustd") || + confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0 || + (mkdir(buf, 0700) && errno != EEXIST)) { + secerror("failed to initialize temporary directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + char *tempdir = realpath(buf, NULL); + if (tempdir == NULL) { + secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0 || + (mkdir(buf, 0700) && errno != EEXIST)) { + secerror("failed to initialize cache directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + char *cachedir = realpath(buf, NULL); + if (cachedir == NULL) { + secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + const char *parameters[] = { + "_TMPDIR", tempdir, + "_DARWIN_CACHE_DIR", cachedir, + NULL + }; + + char *sberror = NULL; + if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED, parameters, &sberror) != 0) { + secerror("Failed to enter trustd sandbox: %{public}s", sberror); + exit(EXIT_FAILURE); + } + + free(tempdir); + free(cachedir); +#else // !TARGET_OS_OSX + char buf[PATH_MAX] = ""; + _set_user_dir_suffix("com.apple.trustd"); + confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)); +#endif // !TARGET_OS_OSX +} + +int main(int argc, char *argv[]) +{ + DisableLocalization(); + + char *wait4debugger = getenv("WAIT4DEBUGGER"); + if (wait4debugger && !strcasecmp("YES", wait4debugger)) { + seccritical("SIGSTOPing self, awaiting debugger"); + kill(getpid(), SIGSTOP); + seccritical("Again, for good luck (or bad debuggers)"); + kill(getpid(), SIGSTOP); + } + + trustd_sandbox(); + + const char *serviceName = kTrustdXPCServiceName; + if (argc > 1 && (!strcmp(argv[1], "--agent"))) { + serviceName = kTrustdAgentXPCServiceName; + } + + /* set up SQLite before some other component has a chance to create a database connection */ + _SecDbServerSetup(); + + gTrustd = &trustd_spi; + + /* Initialize static content */ + SecPolicyServerInitialize(); // set up callbacks for policy checks + SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced + SecPinningDbInitialize(); // set up the pinning database +#if TARGET_OS_OSX + SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation) +#endif + + /* We're ready now. Go. */ + trustd_xpc_init(serviceName); + dispatch_main(); +} diff --git a/trust/trustd/trustd_spi.c b/trust/trustd/trustd_spi.c new file mode 100644 index 00000000..0ed05260 --- /dev/null +++ b/trust/trustd/trustd_spi.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifdef LIBTRUSTD +#include + +#include "../utilities/SecFileLocations.h" + +#include "../sec/ipc/securityd_client.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecPinningDb.h" +#include "trustd_spi.h" + +#if TARGET_OS_OSX +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" +#endif + +#if TARGET_OS_IPHONE +#include "trust/trustd/SecTrustExceptionResetCount.h" +#endif + +#endif // LIBTRUSTD + +#ifdef LIBTRUSTD +struct trustd trustd_spi = { + .sec_trust_store_for_domain = SecTrustStoreForDomainName, + .sec_trust_store_contains = SecTrustStoreContainsCertificateWithDigest, + .sec_trust_store_set_trust_settings = _SecTrustStoreSetTrustSettings, + .sec_trust_store_remove_certificate = SecTrustStoreRemoveCertificateWithDigest, + .sec_truststore_remove_all = _SecTrustStoreRemoveAll, + .sec_trust_evaluate = SecTrustServerEvaluate, + .sec_ota_pki_trust_store_version = SecOTAPKIGetCurrentTrustStoreVersion, + .sec_ota_pki_asset_version = SecOTAPKIGetCurrentAssetVersion, + .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates, + .sec_ota_pki_copy_trusted_ct_logs = SecOTAPKICopyCurrentTrustedCTLogs, + .sec_ota_pki_copy_ct_log_for_keyid = SecOTAPKICopyCTLogForKeyID, + .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset, + .sec_ota_secexperiment_get_new_asset = SecOTASecExperimentGetNewAsset, + .sec_ota_secexperiment_get_asset = SecOTASecExperimentCopyAsset, + .sec_trust_store_copy_all = _SecTrustStoreCopyAll, + .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints, + .sec_ocsp_cache_flush = SecOCSPCacheFlush, + .sec_networking_analytics_report = SecNetworkingAnalyticsReport, + .sec_trust_store_set_ct_exceptions = _SecTrustStoreSetCTExceptions, + .sec_trust_store_copy_ct_exceptions = _SecTrustStoreCopyCTExceptions, +#if TARGET_OS_IPHONE + .sec_trust_get_exception_reset_count = SecTrustServerGetExceptionResetCount, + .sec_trust_increment_exception_reset_count = SecTrustServerIncrementExceptionResetCount, +#endif +}; +#endif + +void trustd_init(CFURLRef home_path) { + if (home_path) + SetCustomHomeURL(home_path); + + trustd_init_server(); +} + +void trustd_init_server(void) { +#ifdef LIBTRUSTD + gTrustd = &trustd_spi; + SecPolicyServerInitialize(); + SecRevocationDbInitialize(); + SecPinningDbInitialize(); +#if TARGET_OS_OSX + SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation) +#endif +#endif // LIBTRUSTD +} diff --git a/trust/trustd/trustd_spi.h b/trust/trustd/trustd_spi.h new file mode 100644 index 00000000..107acec6 --- /dev/null +++ b/trust/trustd/trustd_spi.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009-2010,2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef _TRUSTD_SPI_h +#define _TRUSTD_SPI_h + +#include +#include + +// Don't call these functions unless you are trustd +extern struct trustd trustd_spi; + +void trustd_init_server(void); +void trustd_init(CFURLRef home_dir); + +#endif /* _TRUSTD_SPI_h */ diff --git a/xcconfig/PlatformFeatures.xcconfig b/xcconfig/PlatformFeatures.xcconfig index 6ad07118..17f372c2 100644 --- a/xcconfig/PlatformFeatures.xcconfig +++ b/xcconfig/PlatformFeatures.xcconfig @@ -1,6 +1,4 @@ -#include "xcconfig/PlatformLibraries.xcconfig" - PLATFORM_STR = "unknown" PLATFORM_STR[sdk=macosx*] = "macOS" PLATFORM_STR[sdk=iphoneos*] = "iphone" @@ -40,3 +38,14 @@ SHAREDWEBCREDENTIALS_ON[sdk=bridgeos*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=watch*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=appletv*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=macos*] = 0 + +ABC_BUGCAPTURE_ON[sdk=iphoneos*] = 1 +ABC_BUGCAPTURE_ON[sdk=iphonesimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=watchos*] = 1 +ABC_BUGCAPTURE_ON[sdk=watchsimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=appletvos*] = 1 +ABC_BUGCAPTURE_ON[sdk=appletvsimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=macos*] = 1 +ABC_BUGCAPTURE_ON[sdk=bridgeos*] = 0 + +#include "xcconfig/PlatformLibraries.xcconfig" diff --git a/xcconfig/PlatformLibraries.xcconfig b/xcconfig/PlatformLibraries.xcconfig index 76271036..8c2490e6 100644 --- a/xcconfig/PlatformLibraries.xcconfig +++ b/xcconfig/PlatformLibraries.xcconfig @@ -1,6 +1,4 @@ -OTHER_LDFLAGS_AOSKIT_FRAMEWORK[sdk=macosx*] = -weak_framework AOSAccounts -weak_framework AOSAccountsLite - OTHER_LDFLAGS_MOCK_AKS_LIBRARY = -laks_mock -framework SecurityFoundation OTHER_LDFLAGS_AKS_LIBRARY[sdk=macosx*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphoneos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness @@ -110,6 +108,7 @@ OTHER_LDFLAGS_CrashReporterSupport[sdk=appletv*] = OTHER_LDFLAGS_OCMOCK = -framework OCMock OTHER_LDFLAGS_OCMOCK[sdk=bridgeos*] = -// NanoRegistry exists on other platforms, but in this case we only need it on watch -OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY[sdk=watchsimulator*] = -framework NanoRegistry -OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY[sdk=watchos*] = -framework NanoRegistry +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_1 = -weak_framework SymptomDiagnosticReporter +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_0 = +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_ = +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER = $(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_$(ABC_BUGCAPTURE_ON)) diff --git a/xcconfig/Security.xcconfig b/xcconfig/Security.xcconfig index bc0c2d58..c4dd5a07 100644 --- a/xcconfig/Security.xcconfig +++ b/xcconfig/Security.xcconfig @@ -17,7 +17,7 @@ LIBRARY_SEARCH_PATHS = $(inherited) $(SDKROOT)/usr/local/lib/security_libDER // Note that the 'Settings' view in Xcode will display the wrong values for platform-dependent settings // Refer to the actual build command for final computed value -GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 OCTAGON=$(OCTAGON_ON) TRUSTEDPEERS=$(TRUSTEDPEERS_ON) SECUREOBJECTSYNC=$(SECUREOBJECTSYNC_ON) SHAREDWEBCREDENTIALS=$(SHAREDWEBCREDENTIALS_ON) PLATFORM=$(PLATFORM_STR) SECURITY_BUILD_VERSION="\"$(SECURITY_BUILD_VERSION)\"" $(GCC_PREPROCESSOR_DEFINITIONS) +GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 OCTAGON=$(OCTAGON_ON) TRUSTEDPEERS=$(TRUSTEDPEERS_ON) SECUREOBJECTSYNC=$(SECUREOBJECTSYNC_ON) SHAREDWEBCREDENTIALS=$(SHAREDWEBCREDENTIALS_ON) PLATFORM=$(PLATFORM_STR) SECURITY_BUILD_VERSION="\"$(SECURITY_BUILD_VERSION)\"" $(GCC_PREPROCESSOR_DEFINITIONS) ABC_BUGCAPTURE=$(ABC_BUGCAPTURE_ON) SECURITY_FUZZER_BASE_DIR = /AppleInternal/CoreOS/Fuzzers/Security @@ -42,7 +42,7 @@ OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK = --verify-api-error-as-warning -D SECURITY_ SECURITY_XCTEST_DIRECTORY = /AppleInternal/XCTests/com.apple.security // If you expect to be a 'securityd', use these flags -OTHER_LDFLAGS_FOR_SECURITYD = -framework TrustedPeers $(OTHER_LDFLAGS_COREFOLLOWUP) -lnetwork +OTHER_LDFLAGS_FOR_SECURITYD = -framework TrustedPeers $(OTHER_LDFLAGS_COREFOLLOWUP) -lnetwork $(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER) // Hack for runtime path for OCMock, add to your xctest bundle and embedd OCMock.framework OCMOCK_RUNTIME_SEARCH_PATH = $(inherited) @executable_path/Frameworks @loader_path/Frameworks diff --git a/xcconfig/swift_binary.xcconfig b/xcconfig/swift_binary.xcconfig index e20a890f..a968320e 100644 --- a/xcconfig/swift_binary.xcconfig +++ b/xcconfig/swift_binary.xcconfig @@ -15,4 +15,4 @@ CLANG_ENABLE_MODULES = NO OCTAGON_FLAG_1 = -D OCTAGON OTHER_SWIFT_FLAGS = $(OCTAGON_FLAG_$(OCTAGON_ON)) -SWIFT_VERSION=4.2 +SWIFT_VERSION=5